Skip to content

Commit 1f5cdfc

Browse files
committed
Speed up completion: tab-delimited wire format + two-tier cache
The vector-of-{:candidate :type :ns}-maps shape was costly to decode on the warm-up: every candidate allocated an alist, every :type a keyword, every :ns a string. Switch the default form to emit a tab- and newline-delimited string ("name\tCODE\tns\n...") and parse it with split-string + a tiny decode-row helper. The Compliment / Orchard rich shape and the oldest newline-only string still parse for backward compat. On top of that, add a global core-cache: symbols from port-completion-core-namespaces (just "clojure.core" by default, configurable) are fetched once per session via the new port-completion-core-form and never expire. Per-ns queries use port-completion-local-form which filters those out server-side, so each per-ns response is just the ns-local vars plus non-core requires -- typically 10-100x smaller in projects that mostly use clojure.core. Two-tier mode auto-disables when port-completion-form is customized away from the default (compared cheaply against a pinned port-completion--default-form defconst), so the Compliment override installed by port-enable-orchard keeps working. Refresh manually via M-x port-completion-refresh-core.
1 parent eff352c commit 1f5cdfc

3 files changed

Lines changed: 511 additions & 106 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,13 @@
55
### New features
66

77
- The message log buffer now has its own `port-log-mode` (read-only, `q` to bury, `c` to clear), with distinct faces per direction and a `:note` direction (`!!!` arrow) for internal entries. New commands `port-show-message-log` and `port-clear-message-log`. Per-message truncation past `port-log-max-message-length` (default 2000), buffer-wide trim past `port-log-max-buffer-lines` (default 5000), and auto-follow that only chases windows already scrolled to the end.
8+
- Two-tier completion cache: symbols from `port-completion-core-namespaces` (default `("clojure.core")`) are fetched once per session into a shared global cache, and per-namespace queries skip them server-side. In typical projects this cuts the warm-up response by ~10x and the per-keystroke cache walk by the same factor. Auto-disabled when `port-completion-form` is customised away from the default (so the Compliment override installed by `port-enable-orchard` still works). Refresh manually via `M-x port-completion-refresh-core`.
89

910
### Changes
1011

1112
- `*port-messages*` log entries are now printed via `prin1` instead of `pp` by default. `pp` formatting was the actual culprit behind a recent reported Emacs hang while typing in the REPL: pretty-printing a 4000-entry completion warm-up response takes ~120ms; `prin1` takes ~6ms. Set the new `port-log-pretty-print` defcustom to `t` to opt back in to multi-line readable output.
1213
- Tool-socket bootstrap now defines a second wrapper `port.tooling/-data-eval` alongside `-eval`. The data variant skips the inner `pr-str` so prepl's outer print does a single serialization pass; the Elisp side then has parsed data directly in `:val` rather than a printed string that needs re-parsing. Eliminates one full EDN round-trip per tooling call and the escape-doubling that bites long nested strings. Completion, xref, eldoc, stacktrace, test, and Orchard probes have been migrated to the new path; `port-tooling-call` / `port-tooling-decode-val` are unchanged for display callers (`port-doc`, `port-source`, etc.). Existing sessions need to reconnect to pick up the new bootstrap.
13-
14-
### New features
15-
16-
- Completion candidates now carry capf annotations: corfu / company popups show a one-letter kind tag (`f`, `m`, `v`, `c`, …) plus the source namespace next to each candidate. Works out of the box with the default form (vars / macros / classes); the bundled Compliment variant ships richer types (instance methods, keywords, locals, …) the same way. Format is customisable via `port-completion-annotation-function`.
14+
- Completion wire format is now a tab- and newline-delimited string (`name\tCODE\tns\n…`) instead of a vector of EDN maps. No alist or keyword allocation per candidate at parse time — `split-string` on tab and newline, then build the alist only for candidates that actually need annotation. ~5x faster decode on the warm-up response. The Compliment / Orchard rich shape (vector of maps) still parses for backward compat.
1715

1816
## 0.3.0 (2026-05-20)
1917

0 commit comments

Comments
 (0)