#+TITLE: clatter.el User Guide
#+AUTHOR: Glenn Thompson
#+STARTUP: showall

* Prerequisites

- **Emacs 30.1+** (built with GnuTLS support)
- **GnuTLS** is required for TLS/SSL connections to IRC servers

To verify GnuTLS is available, evaluate:

#+begin_src emacs-lisp
(gnutls-available-p)  ;; should return t
#+end_src

If it returns =nil=, install GnuTLS and rebuild Emacs:

| OS               | Package                                |
|------------------+----------------------------------------|
| Debian/Ubuntu    | =apt install gnutls-bin libgnutls28-dev= |
| Fedora/RHEL      | =dnf install gnutls=                     |
| Arch             | =pacman -S gnutls=                       |
| macOS (Homebrew) | =brew install gnutls=                    |

Most modern Emacs builds include GnuTLS support by default.

* Quick Start

** Minimal Configuration

#+begin_src emacs-lisp
(add-to-list 'load-path (expand-file-name "~/SourceCode/clatter.el"))
(require 'clatter)

(setopt clatter-networks
       '(("libera"
          :server "irc.libera.chat"
          :port 6697
          :tls t
          :nick "yournick"
          :sasl plain
          :autojoin ("#emacs" "#lisp"))))

;; Loading clatter has no side effects: it installs no global hooks and
;; enables no extras.  Call clatter-setup once to wire everything up.
(clatter-setup)
#+end_src

Note: ~clatter-setup~ is required.  Without it the optional features
(activity tracking, notifications, chathistory, read markers, logging,
URL previews) are not enabled and no exit/disconnect cleanup hooks are
installed.  To leave a particular extra off, set its user option to ~nil~
before calling ~clatter-setup~, for example:

#+begin_src emacs-lisp
(setopt clatter-notify-enabled nil   ; no desktop notifications
        clatter-track-enabled  nil)  ; no mode-line activity crumbs
(clatter-setup)
#+end_src

** Connecting

- =M-x clatter= - connect to a network (prompts for selection)
- =M-x clatter-quick-connect= - connect to server/port/nick directly
- =M-x clatter-disconnect= - disconnect from a network
- =M-x clatter-status= - show connection status

** Passwords

Clatter uses =auth-source= by default. Add to =~/.authinfo.gpg=:

#+begin_example
machine irc.libera.chat login yournick password yourpassword
#+end_example

Set =clatter-use-auth-source= to =nil= to disable.

* Command Reference

All commands are typed in the input area prefixed with =/=.

** Connection & Navigation

| Command        | Aliases | Description                                                               |
|----------------+---------+---------------------------------------------------------------------------|
| =/join #channel= | =/j=      | Join a channel                                                            |
| =/part [msg]=    | =/leave=  | Leave current channel                                                     |
| =/query nick=    |         | Open a private message buffer                                             |
| =/close=         | =/wc=     | Close current buffer (parts if channel)                                   |
| =/quit [msg]=    | =/q=      | Disconnect from network                                                   |
| =/buffers=       |         | List all open buffers                                                     |
| =/list [filter]= |         | Open interactive channel list browser (optional server filter, e.g. =>100=) |

Killing a clatter buffer the normal way (=C-x k=, ibuffer, etc.) now
tears it down cleanly without needing =/close= or =/quit=: killing a
channel buffer parts the channel, and killing a server buffer
disconnects that network.

** Messaging

| Command            | Aliases | Description                                                       |
|--------------------+---------+-------------------------------------------------------------------|
| =/msg nick text=     |         | Send private message                                              |
| =/say text=          |         | Send text to the current buffer (useful for text starting with =/=) |
| =/me action=         |         | Send action (/me does something)                                  |
| =/reply text=        | =/r=      | Reply to the selected message (threaded, see below)               |
| =/react emoji=       |         | React to the selected message with emoji (see below)              |
| =/ctcp nick command= |         | Send CTCP query                                                   |

*** Selecting a message for /reply and /react

Both =/reply= and =/react= act on the message in the *secondary
selection*, not on the message at point. Select a message first, then
type the command in the input area:

- Drag over a message with =M-<mouse-1>= (the standard Emacs secondary
  selection), or
- Put point on a message and run =M-x clatter-select-message= (also
  reachable from the message action menu, =C-c C-a=), which copies that
  message into the secondary selection.

The selection is "sticky": it persists until you replace it, so you can
fire several reactions at the same message. Clatter clears it
automatically after a =/reply=. If nothing is selected, clatter prompts
you to select a message first.

** Channel Management

| Command             | Description                            |
|---------------------+----------------------------------------|
| =/topic [new topic]=  | View or set channel topic              |
| =/kick nick [reason]= | Kick a user from channel               |
| =/mode [modes]=       | View or set channel/user modes         |
| =/invite nick=        | Invite user to current channel         |
| =/names=              | List channel members (alias: =/members=) |
| =/nick newnick=       | Change your nickname                   |
| =/away [message]=     | Set or clear away status               |

** Search

| Command           | Aliases      | Description                      |
|-------------------+--------------+----------------------------------|
| =/search query=     | =/grep=, =/find= | Search all IRC logs              |
| =/searchhere query= |              | Search current channel logs only |

Also available as =M-x clatter-search=, =M-x clatter-search-channel=,
and =M-x clatter-search-completing= (completing-read interface).

With prefix arg (=C-u=), =/search= prompts for a network filter.

** Moderation & Filtering

| Command              | Description                                                   |
|----------------------+---------------------------------------------------------------|
| =/suppress type ...=   | Hide message types (join part quit nick mode away kick topic) |
| =/suppress all=        | Suppress all noise                                            |
| =/suppress noise=      | Enable smart (adaptive) noise filtering (see below)           |
| =/suppress none=       | Show everything                                               |
| =/unsuppress type ...= | Stop suppressing specific types                               |
| =/ignore pattern=      | Ignore nick or hostmask (supports * and ?)                    |
| =/unignore pattern=    | Remove from ignore list                                       |
| =/ignore=              | Show current ignore list                                      |
| =/fool nick=           | Mute a nick (hide their messages); no arg shows the list      |
| =/unfool nick=         | Stop muting a nick                                            |
| =/pal nick=            | Highlight a nick as a pal; no arg shows the list              |
| =/unpal nick=          | Remove a nick from the pals list                              |

*** Smart noise filtering

=/suppress all= hides join/part/quit/etc. unconditionally. Smart
filtering instead hides that noise *only for nicks who are mostly
noise*. Each nick accumulates a signal-to-noise ratio: "signal" is
talking (PRIVMSG, notice, topic, reactions) and "noise" is
join/part/quit/nick/mode/away. When a nick's ratio falls below the
threshold, their noise lines are hidden, while people who actually talk
stay fully visible.

Enable it per buffer:

#+begin_src
/suppress noise
#+end_src

Turn it off with =/unsuppress noise=. Suppression is buffer-local, so
run it in each channel where you want it (it is most useful on busy
channels like =#emacs=). The ratios build up as messages arrive, so the
filter gets more accurate the longer a channel stays open.

Tuning:

| Variable                | Default                    | Description                                                      |
|-------------------------+----------------------------+------------------------------------------------------------------|
| =clatter-smart-threshold= | =0.5=                        | Hide a nick's noise when its signal/noise ratio drops below this |
| =clatter-smart-noise=     | =(join part quit nick away)= | Event types that count as noise                                  |

*** Pals and fools

Two complementary nick lists:

- *Pals* (friends) are highlighted with the =clatter-pal= face wherever
  their nick appears, so you never miss them: =/pal nick= adds one,
  =/unpal nick= removes one, and =/pals= shows the list.
- *Fools* are muted: their messages are hidden, much like the ignore
  list but tracked separately so they are easy to toggle. =/fool nick=
  mutes a nick, =/unfool nick= un-mutes, and =/fools= shows the list.

Both match case-insensitively and can be preset via the =clatter-pals=
and =clatter-fools= variables.

** Services & Raw

| Command         | Description                   |
|-----------------+-------------------------------|
| =/ns command=     | Send command to NickServ      |
| =/cs command=     | Send command to ChanServ      |
| =/raw line=       | Send raw IRC protocol line    |
| =/monitor + nick= | Add nick to MONITOR watchlist |
| =/monitor - nick= | Remove nick from MONITOR      |
| =/whois nick=     | Query WHOIS information       |

** DCC File Transfer

| Command            | Description                        |
|--------------------+------------------------------------|
| =/dcc get BOT #PACK= | Request an XDCC pack from a bot    |
| =/dcc list=          | Show all DCC transfers with status |
| =/dcc accept [N]=    | Accept a pending DCC transfer      |
| =/dcc cancel N=      | Cancel a transfer by ID            |

Workflow: join an XDCC channel, search for packs (e.g. =!search query= in #nibl on Rizon),
then request with =/dcc get BotName #PackNumber=. You will be prompted to accept.
Files are saved to =~/Downloads/= by default.

** Autojoin Persistence

| Command                   | Description                            |
|---------------------------+----------------------------------------|
| =/autojoin add #channel=    | Add channel to autojoin and persist    |
| =/autojoin remove #channel= | Remove from autojoin and persist       |
| =/autojoin list=            | Show current autojoin for this network |

If no channel is specified, the current channel is used.
Changes are persisted via =customize-save-variable= to your
=custom-file= and also update the live config immediately.

** Utility

| Command | Description          |
|---------+----------------------|
| =/clear=  | Clear current buffer |

* Configuration Reference

** Network Settings

| Variable                        | Default           | Description                               |
|---------------------------------+-------------------+-------------------------------------------|
| =clatter-networks=                | =nil=               | Network connection list (see Quick Start) |
| =clatter-default-nick=            | =(user-login-name)= | Default nickname                          |
| =clatter-default-realname=        | ="clatter.el user"= | Default realname                          |
| =clatter-default-port=            | =6697=              | Default port                              |
| =clatter-default-tls=             | =t=                 | Use TLS by default                        |
| =clatter-use-auth-source=         | =t=                 | Look up passwords via auth-source         |
| =clatter-reconnect-initial-delay= | =10=                | Seconds before first reconnect            |
| =clatter-reconnect-max-delay=     | =300=               | Max reconnect delay (exponential backoff) |
| =clatter-ping-interval=           | =30=                | Seconds between health pings              |
| =clatter-ping-timeout=            | =120=               | Seconds before ping timeout               |

** Display

| Variable                  | Default      | Description                                                                                                                                                                          |
|---------------------------+--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| =clatter-timestamp-format=  | ="%H:%M"=      | Timestamp format string                                                                                                                                                              |
| =clatter-fill-column=       | =80=           | Fill column for message wrapping                                                                                                                                                     |
| =clatter-nick-column-width= | =20=           | Width of nick column                                                                                                                                                                 |
| =clatter-buffer-max-lines=  | =10000=        | Max lines before buffer truncation                                                                                                                                                   |
| =clatter-max-line-length=   | =400=          | Max IRC line length before splitting                                                                                                                                                 |
| =clatter-message-order=     | =newest-first= | =newest-first= keeps the input at the top with new messages below it; =oldest-first= is a conventional layout with the input line anchored at the *bottom* and messages scrolling above it |
| =clatter-move-to-prompt=    | =t=            | Typing anywhere jumps to the input line first (like ERC's =erc-move-to-prompt=)                                                                                                        |

** Message Suppression

| Variable                  | Default | Description                                               |
|---------------------------+---------+-----------------------------------------------------------|
| =clatter-suppress-messages= | =nil=     | List of symbols: join part quit nick mode away kick topic |

Example:
#+begin_src emacs-lisp
(setopt clatter-suppress-messages '(join part quit away))
#+end_src

** Input

| Variable                      | Default | Description                      |
|-------------------------------+---------+----------------------------------|
| =clatter-flyspell-enable=       | =t=       | Enable flyspell in input area    |
| =clatter-paste-flood-threshold= | =3=       | Lines before paste flood warning |

** Logging

| Variable                     | Default                  | Description                  |
|------------------------------+--------------------------+------------------------------|
| =clatter-log-enable=           | =nil=                      | Enable channel logging       |
| =clatter-log-directory=        | =~/.emacs.d/clatter/logs/= | Log file directory           |
| =clatter-log-rotate-daily=     | =t=                        | Daily log rotation           |
| =clatter-log-timestamp-format= | ="%Y-%m-%d %H:%M:%S"=      | Log timestamp format         |
| =clatter-log-system-messages=  | =t=                        | Log joins/parts/quits        |
| =clatter-log-server-buffer=    | =nil=                      | Log server buffer            |
| =clatter-log-exclude-targets=  | =nil=                      | Targets to skip logging      |
| =clatter-log-flush-interval=   | =30=                       | Seconds between disk flushes |

Logging is enabled by ~clatter-setup~ when =clatter-log-enable= is
non-nil (the default).  To turn it off, set the option to ~nil~ before
calling ~clatter-setup~:

#+begin_src emacs-lisp
(setopt clatter-log-enable nil)
#+end_src

To toggle logging in a running session, use =M-x clatter-log-init= and
=M-x clatter-log-teardown=.

** Notifications

| Variable                      | Default | Description                          |
|-------------------------------+---------+--------------------------------------|
| =clatter-notify-enabled=        | =t=       | Enable desktop notifications         |
| =clatter-notify-on-mention=     | =t=       | Notify on nick mentions              |
| =clatter-notify-on-dm=          | =t=       | Notify on direct messages            |
| =clatter-notify-on-keyword=     | =t=       | Notify on keyword matches            |
| =clatter-notify-keywords=       | =nil=     | Extra keywords to notify on          |
| =clatter-notify-muted-channels= | =nil=     | Channels to never notify             |
| =clatter-notify-muted-nicks=    | =nil=     | Nicks to never notify                |
| =clatter-notify-current-buffer= | =nil=     | Notify even if buffer is visible     |
| =clatter-notify-timeout=        | =5000=    | Notification timeout (ms)            |
| =clatter-notify-icon=           | =nil=     | Path to notification icon            |
| =clatter-notify-urgency=        | ='normal= | Urgency: low, normal, critical       |
| =clatter-notify-sound=          | =nil=     | Sound file for notifications         |
| =clatter-notify-max-length=     | =80=      | Max message length in notification   |
| =clatter-notify-cooldown=       | =3=       | Min seconds between notifications    |
| =clatter-notify-dm-priority=    | ='always= | DM priority: always, rules, never    |
| =clatter-notify-rules=          | =nil=     | Per-channel smart notification rules |

*** Smart Notification Rules

Per-channel/nick rules with schedule support:

#+begin_src emacs-lisp
(setopt clatter-notify-rules
        '((:target "#emacs" :level mentions :schedule (9 . 22))
          (:target "#bots" :level none)
          (:target "#systemcrafters" :level all)
          (:target "friend" :level all)))
#+end_src

Rule levels:
- =all= - notify on every message
- =mentions= - notify on mentions and keywords only
- =dms= - notify only for DMs from this target
- =none= - never notify

Schedules use 24h format =(START . END)=. Wraps midnight:
=(22 . 8)= means 10pm to 8am.

DM priority (=clatter-notify-dm-priority=):
- =always= - DMs always notify regardless of rules (default)
- =rules= - DMs follow per-target rules
- =never= - never notify on DMs

** Bouncer Playback

When the server sends batched history (chathistory, ZNC playback, etc.),
clatter renders it with visual separators:

#+begin_example
 ------------------------------ history ------------------------------
10:15        <alice> hey everyone
10:16          <bob> morning!
 -------------------- end of history (2 messages) --------------------
#+end_example

This works automatically with any IRCv3 BATCH-based playback.

** Channel Preview on Hover (eldoc)

When point is on a =#channel= name in messages, eldoc shows the
channel topic and user count in the echo area. When point is on a
message, it shows the sender and message ID.

This is enabled automatically via =eldoc-mode= in clatter buffers.

** Nick Highlighting

| Variable                        | Default | Description                 |
|---------------------------------+---------+-----------------------------|
| =clatter-hl-nicks-enabled=        | =t=       | Colorize nicks in messages  |
| =clatter-hl-nicks-minimum-length= | =3=       | Min nick length to colorize |
| =clatter-hl-nicks-skip-nicks=     | =nil=     | Nicks to never colorize     |
| =clatter-hl-nicks-skip-faces=     | =(...)=  | Faces to skip colorizing    |
| =clatter-hl-nicks-alias-alist=    | =nil=     | Nick -> color alias mapping |
| =clatter-hl-keywords=             | =nil=     | Extra words to highlight    |

** mIRC Formatting

| Variable                  | Default | Description                       |
|---------------------------+---------+-----------------------------------|
| =clatter-format-enable=     | =t=       | Parse mIRC color/formatting codes |
| =clatter-format-strip-only= | =nil=     | Strip codes without rendering     |

** Inline Images

| Variable                 | Default       | Description                  |
|--------------------------+---------------+------------------------------|
| =clatter-image-enable=     | =nil=           | Enable inline image previews |
| =clatter-image-max-width=  | =400=           | Max image width (pixels)     |
| =clatter-image-max-height= | =300=           | Max image height (pixels)    |
| =clatter-image-max-size=   | =5242880= (5MB) | Max download size            |
| =clatter-image-extensions= | =(png jpg ...)= | Recognized image extensions  |

** URL Preview

| Variable                             | Default | Description                  |
|--------------------------------------+---------+------------------------------|
| =clatter-url-preview-enable=           | =nil=     | Fetch and display URL titles |
| =clatter-url-preview-max-length=       | =200=     | Max title length             |
| =clatter-url-preview-timeout=          | =10=      | Fetch timeout (seconds)      |
| =clatter-url-preview-exclude-patterns= | =nil=     | URL patterns to skip         |

** Search

| Variable                     | Default | Description                  |
|------------------------------+---------+------------------------------|
| =clatter-search-max-results=   | =500=     | Max search results           |
| =clatter-search-context-lines= | =0=       | Context lines around matches |

** Activity Tracking

| Variable                     | Default      | Description                     |
|------------------------------+--------------+---------------------------------|
| =clatter-track-enabled=        | =t=            | Show activity in mode line      |
| =clatter-track-position=       | ='after-modes= | Mode line position              |
| =clatter-track-muted-channels= | =nil=          | Channels to ignore for tracking |
| =clatter-track-shorten-names=  | =t=            | Abbreviate channel names        |
| =clatter-track-show-counts=    | =t=            | Show unread message counts      |

** Chat History

| Variable                         | Default | Description           |
|----------------------------------+---------+-----------------------|
| =clatter-chathistory-enabled=      | =t=       | Fetch backlog on join |
| =clatter-chathistory-limit=        | =50=      | Messages to fetch     |
| =clatter-chathistory-on-join=      | =t=       | Fetch on channel join |
| =clatter-chathistory-on-reconnect= | =t=       | Fetch on reconnect    |

** Nick Completion

| Variable                     | Default | Description                          |
|------------------------------+---------+--------------------------------------|
| =clatter-completion-add-colon= | =t=       | Append =:= after nick at start of line |

** Nick List Sidebar

| Variable               | Default | Description                |
|------------------------+---------+----------------------------|
| =clatter-nicklist-width= | =20=      | Sidebar width              |
| =clatter-nicklist-side=  | ='right=  | Which side (left or right) |

** Raw Protocol Log

| Variable                   | Default | Description                       |
|----------------------------+---------+-----------------------------------|
| =clatter-log-raw-protocol=   | =nil=     | Log raw IRC lines to debug buffer |
| =clatter-rawlog-enabled=     | =nil=     | Enable rawlog module              |
| =clatter-rawlog-max-lines=   | =5000=    | Max rawlog buffer lines           |
| =clatter-rawlog-show-parsed= | =t=       | Show parsed message breakdown     |

** DCC File Transfer

| Variable                       | Default      | Description                                     |
|--------------------------------+--------------+-------------------------------------------------|
| =clatter-dcc-download-directory= | =~/Downloads/= | Where received files are saved                  |
| =clatter-dcc-auto-accept=        | =nil=          | Auto-accept DCC offers                          |
| =clatter-dcc-max-file-size=      | =nil=          | Max file size to accept (bytes), nil = no limit |
| =clatter-dcc-progress-interval=  | =2=            | Seconds between progress updates                |

** Strict Transport Security

| Variable                | Default                            | Description         |
|-------------------------+------------------------------------+---------------------|
| =clatter-sts-enable=      | =t=                                  | Auto-upgrade to TLS |
| =clatter-sts-policy-file= | =~/.emacs.d/clatter/sts-policies.el= | Cached STS policies |

** Read Marker

| Variable                      | Default | Description                     |
|-------------------------------+---------+---------------------------------|
| =clatter-read-marker-enabled=   | =t=       | Sync read position with server  |
| =clatter-read-marker-auto-send= | =t=       | Auto-send read marker on switch |

* Modules

Each module is a separate =.el= file. Most are loaded automatically
by =clatter.el=. Optional modules need explicit =(require)=:

** Auto-loaded (via =clatter.el=)

- =clatter-config.el= - configuration variables
- =clatter-protocol.el= - IRC message building/parsing
- =clatter-connection.el= - TCP/TLS connections, reconnect
- =clatter-handlers.el= - message dispatch and hooks
- =clatter-model.el= - buffer registry, nick lists
- =clatter-ui.el= - message rendering, input handling
- =clatter-commands.el= - slash commands
- =clatter-completion.el= - tab completion
- =clatter-hl-nicks.el= - nick colorization and keywords
- =clatter-track.el= - activity tracking (mode line)
- =clatter-notify.el= - desktop notifications
- =clatter-chathistory.el= - IRCv3 CHATHISTORY
- =clatter-read-marker.el= - IRCv3 read markers

** Enabling the bundled extras

Activity tracking, desktop notifications, chathistory, read markers,
channel logging and URL previews are bundled with clatter but enabled
only when you call ~clatter-setup~ (see Quick Start).  Each is gated by
its own user option:

| Option                      | Feature                     | Default |
|-----------------------------+-----------------------------+---------|
| =clatter-track-enabled=       | Mode-line activity tracking | on      |
| =clatter-notify-enabled=      | Desktop notifications       | on      |
| =clatter-chathistory-enabled= | IRCv3 CHATHISTORY on join   | on      |
| =clatter-read-marker-enabled= | IRCv3 read markers          | on      |
| =clatter-log-enable=          | Channel logging to file     | off     |
| =clatter-url-preview-enable=  | Inline URL title previews   | off     |

Set an option to ~nil~ (or ~t~ for the off-by-default ones) before
calling ~clatter-setup~.  You can also toggle a feature at runtime with its
=clatter-FEATURE-enable= / =clatter-FEATURE-disable= command.

** Optional (require explicitly)

#+begin_src emacs-lisp
;; Inline images (GUI only)
(require 'clatter-image)
(setopt clatter-image-enable t)

;; Org-mode integration: register the "irc:" link type with Org.
(with-eval-after-load 'org
  (require 'clatter-org)
  (clatter-org-setup))

;; Full-text search (auto-loaded by commands, but can require directly)
(require 'clatter-search)

;; DCC file transfer (loaded by clatter-commands, but can require directly)
(require 'clatter-dcc)
(clatter-dcc-setup)
#+end_src

* Org-mode Integration

** Storing Links

In any clatter buffer, =M-x org-store-link= (or =C-c l=) stores
a link to the message at point:

#+begin_example
[[irc:libera/#emacs#abc123][IRC: <user> their message (#emacs)]]
#+end_example

** Capture Templates

Add to your org-capture templates:

#+begin_src emacs-lisp
(setq org-capture-templates
      '(("i" "IRC Message" entry
         (file+headline "~/org/irc.org" "Captured Messages")
         "* %U IRC Note\n%(clatter-org-capture-message)\n%?"
         :empty-lines 1)
        ("c" "IRC Channel Note" entry
         (file+headline "~/org/irc.org" "Channel Notes")
         "* %U %(clatter-org-capture-channel)\n%?"
         :empty-lines 1)))
#+end_src

Then =M-x org-capture= from a clatter buffer captures the message
at point with sender, text, channel, and timestamp.

** Exporting Logs

=M-x clatter-org-export-log= converts a log file to org format,
grouped by date with timestamped entries.

* Keybinding Examples

** Evil Mode

#+begin_src emacs-lisp
(with-eval-after-load 'evil
  (evil-set-initial-state 'clatter-mode 'normal)
  (evil-define-key 'normal clatter-mode-map
    (kbd "g o") #'clatter-hl-open-url-nearest
    (kbd "i") #'clatter-evil-insert-at-prompt)

  (defun clatter-evil-insert-at-prompt ()
    "Move to the input prompt and enter Evil insert state."
    (interactive)
    (when clatter--input-marker
      (goto-char clatter--input-marker)
      (goto-char (line-end-position)))
    (evil-insert-state)))
#+end_src

** General Leader Keys

#+begin_src emacs-lisp
(global-set-key (kbd "C-c i i") #'clatter)
(global-set-key (kbd "C-c i d") #'clatter-disconnect)
(global-set-key (kbd "C-c i s") #'clatter-status)
(global-set-key (kbd "C-c i t") #'clatter-track-switch)
(global-set-key (kbd "C-c i l") #'clatter-track-list)
(global-set-key (kbd "C-c i r") #'clatter-rawlog-open)
(global-set-key (kbd "C-c i o") #'clatter-hl-browse-urls)
(global-set-key (kbd "C-c i p") #'clatter-nicklist-toggle)
(global-set-key (kbd "C-c i /") #'clatter-search)
#+end_src

* Troubleshooting

** Debug Logging

Enable raw protocol logging to see all IRC traffic:

#+begin_src emacs-lisp
(setopt clatter-log-raw-protocol t)
#+end_src

Open the debug buffer: =M-x clatter-rawlog-open=.
Incoming lines are green (=<<=), outgoing are blue (=>>=).

** Direct Messages

DMs automatically create a new buffer when someone messages you.
The buffer is named =*clatter: network/nick*=. Activity tracking
will flag it in the mode line.

** Stale Byte-Compiled Files

If you see void-function errors after updating, delete =.elc= files:

#+begin_example
cd ~/SourceCode/clatter.el && rm -f *.elc
#+end_example

** Connection Issues

- Check =M-x clatter-status= for connection state
- Verify auth-source entry matches =:server= and =:nick=
- STS may auto-upgrade port 6667 to 6697 - check rawlog
- Set =clatter-reconnect-max-delay= lower for faster reconnects

** Message Suppression

If your buffer is too noisy with joins/parts/quits:

#+begin_src emacs-lisp
(setopt clatter-suppress-messages '(join part quit away))
#+end_src

Or at runtime: =/suppress join part quit away=

To undo: =/unsuppress away= or =/suppress none=

** Keybindings and SPC Leader

clatter does not bind any global keys. All functionality is available
via =M-x= commands and =/slash= commands in the input prompt.

If you see references to =SPC i= key sequences, those are examples of
user-configured Evil leader bindings (e.g. via general.el). They are
not built into clatter. See the *Keybinding Examples* section above
for how to set them up.

With Evil, =SPC= only acts as a leader key in *normal state*. When
you press =i= to enter insert state at the prompt, =SPC= types a
space character as expected. There is no conflict.
