| Commit message (Collapse) | Author | Age | Files | Lines |
| |
|
|
|
|
|
|
|
|
|
|
|
| |
EmacSQL 4.3.1 registers a finalizer per connection that calls
emacsql-close after GC. The sqlite-builtin and sqlite-module backends
clear their handle slot during an explicit close, so the finalizer
later runs emacsql-close on a closed connection and sqlite-close fires:
finalizer failed: (wrong-type-argument sqlitep nil)
Adds an :around method on emacsql-close for both backends that
short-circuits when the handle is already nil. Requires cl-generic
and eieio at the top of the file so the cl-defmethod forms expand.
|
| |
|
|
|
|
|
|
|
|
|
| |
Adds an org-tidy use-package block hooked into org-mode and sets
org-tidy-properties-style to 'inline so each :PROPERTIES: drawer
collapses to a small marker in the heading line. The drawer stays
editable through TAB cycling or via M-x org-tidy-mode toggle.
Also sets org-cycle-hide-drawers to 'all in cj/org-general-settings
so drawers fold whenever their parent heading folds -- the native
companion to org-tidy's overlay-based hiding.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Undercover now instruments gptel-tools/*.el alongside modules/*.el,
so the new git_status / git_log / git_diff / web_fetch tools (and
their successors) report coverage instead of reading as zero.
The matching pre-coverage clean step deletes gptel-tools/*.elc so
stale byte-compiled artifacts don't shadow the .el sources. If
Emacs loads the .elc first, undercover's source instrumentation
never runs.
docs/design/coverage.org gains an Elisp-coverage-producer subsection
documenting the glob, the :merge-report dependence (SimpleCov merges
cross-process reports, LCOV does not), and the missing-artifact
failure mode.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Adds docs/design/gptel-network-tools.org capturing the brainstorm
output for the next gptel-tools batch -- net_diagnose, net_discover,
net_services, network_status, dns_lookup -- with argv shapes,
target-gating guardrails for nmap, and a ~47-test sketch.
Restructures the GPTel Tool Work parent in todo.org with seven themed
categories: Git, Org, messaging, file/buffer, filesystem, media /
reading, and dev workflow. Each carries a body framing the design
choice and stub child themes. Filesystem covers the pandoc /
imagemagick / ffmpeg / ripgrep / fd / file+exiftool / jq+yq surface
plus an eshell escape hatch. Per-theme spec lands in the task body
once written. Implementation tasks join as siblings once the spec
is approved.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
flycheck's `flycheck-define-checker' macro requires the `:command'
executable to be a string literal at macro-expansion time -- it does
`(stringp (car command))' and errors otherwise. The previous
`(eval (expand-file-name ...))' form (commit c4cf8d7d, the
externalization fix) put a `(eval FORM)' wrapper in the executable
position, which flycheck rejected at load:
Error (use-package): recentf/:config: Command executable for
syntax checker languagetool must be a string:
(eval (expand-file-name "scripts/languagetool-flycheck"
user-emacs-directory))
`(eval FORM)' is only valid for SUBSEQUENT command-list elements
(arguments), not the executable.
Wrap the entire `flycheck-define-checker' invocation in `eval' +
backquote so the expanded path is spliced in as a string literal
before the macro sees it. The hardcoded `~/.emacs.d/...' path is
gone for the same reason the original externalization wanted it
gone: survives a non-standard `user-emacs-directory'.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
The default-backend swap to gpt-5.5 (commit f16fa4e4) set
`gptel-model' as the string "gpt-5.5". gptel's modeline-display
code calls `symbolp' on the model value and signals
`wrong-type-argument symbolp "gpt-5.5"' on every render, which
manifested as Emacs freezing in the AI-Assistant buffer ("Querying
ChatGPT..." → error in process sentinel → repeated redisplay errors).
Both default-setting sites now use `'gpt-5.5' (interned symbol).
The Anthropic backend tolerated string model names so the original
"claude-opus-4-7" string worked, which is why this hadn't surfaced
before.
|
| |
|
|
|
|
|
|
| |
Two places set the default backend + model on gptel initialization
-- `cj/ensure-gptel-backends' (the lazy-init fallback) and the
`use-package gptel :config' block (the eager-set after initialization).
Both now pick the ChatGPT backend with `gpt-5.5' instead of Claude
with `claude-opus-4-7'.
|
| |
|
|
|
|
|
|
|
|
|
| |
- gptel-git-tools-magit-backend.org -- spec for reimplementing the
three current git_* tools on top of magit, plus three new tools
(blame, show, branches).
- gptel-agentic-tool-ideas.org -- brainstorm seed for additional
agentic gptel tools.
- agentic-knowledgebase.org -- design sketch for using org-roam as
the agent's durable project memory with org-agenda as the
execution layer.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Fourth ADOPT entry from `docs/design/gptel-tools-shortlist.org'.
Lets gptel pull a URL into the conversation so the model can read
docs / current API shapes / etc. without me copy-pasting.
Shape:
- URL must be `http://' or `https://' (file://, ftp://, javascript:,
scheme-less, etc. are rejected at the validator).
- HTML responses go through `pandoc -f html -t plain' so the model
gets a reading shape that isn't full of markup; falls back to
`w3m -dump -T text/html' if pandoc isn't on PATH; signals
`user-error' if neither is. Pass `raw=t' to skip stripping.
- Output capped at 200KB by default, hard cap 1MB; `max_bytes'
argument lets the caller pick a lower cap. Truncation reported
inline.
- 4xx / 5xx response codes signal `error' with the code -- the
alternative is returning an error page body, which the model
would treat as content.
`:confirm t' on the tool because every call is a real outbound
network request. The tool's description warns that URLs go
wherever the user-agent points, including internal networks if
that's what the URL names.
`tests/test-gptel-tools-web-fetch.el' -- 20 tests across Normal /
Boundary / Error. URL validator covers http / https / non-string
/ empty / non-http schemes. `--effective-max-bytes' covers default
/ low-clamp / hard-cap / passthrough. Truncate helper covers
under-cap / at-cap / over-cap with the marker. HTML stripper runs
against real pandoc / w3m (both installed in dev env, neither
should mangle simple markup). Orchestrator stubs
`cj/gptel-web-fetch--retrieve' via `cl-letf' to cover normal /
raw / 4xx / 5xx / oversize / bad-scheme paths.
Wired into `cj/gptel-local-tool-features' so gptel exposes the
tool on next restart.
Note: `call-process-region' invocation flattened to a single
`with-temp-buffer' with DELETE=t -- the initial draft nested a
second temp buffer and routed output to the inner one, which got
killed before `buffer-string' on the outer ran. Test caught it.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Three read-only git context tools so gptel can see what's changed
without me pasting `git status` / `git log` / `git diff` output into
every chat turn. Builds the first batch from the ADOPT bucket in
`docs/design/gptel-tools-shortlist.org`.
Shape per tool:
- `gptel-tools/git_status.el` — `git status --short --branch` for a
directory inside a git working tree under HOME. Returns the
porcelain output, or a "Clean working tree" marker when only the
branch line is present.
- `gptel-tools/git_log.el` — `git log --oneline -nN` with an optional
`--since` filter. N defaults to 20, capped at 100; nil / non-
integer / out-of-range N falls back to the default.
- `gptel-tools/git_diff.el` — `git diff [REF1 [REF2]] [-- FILE]`.
Output capped at ~500KB so a runaway diff can't blow up context;
truncation is reported inline.
Validation is uniform: path must resolve under HOME, must be a
directory, must be inside a git working tree (verified via
`git rev-parse --is-inside-work-tree`). Color is disabled via
`-c color.ui=false` at the git level (`git status` doesn't accept
`--no-color` directly).
Tests run against real temp git repos created via `process-file`,
not mocked — there's nothing in gptel-tools/git_*.el that's
process-mockable in a meaningful way, and a real `git init` + a
couple of commits is cheaper than building a fake. 31 tests total:
7 for git_status, 11 for git_log, 13 for git_diff.
Wired into `cj/gptel-local-tool-features` so gptel exposes the
three tools on next restart.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Commit d3a8e01b's defer change broke startup with a `void-function
nerd-icons-faicon' error. `dashboard-config.el' calls
`nerd-icons-faicon' / `nerd-icons-mdicon' / `nerd-icons-devicon' at
load time to build `dashboard-navigator-buttons', so nerd-icons must
be loaded eagerly before dashboard-config requires. The "defer for
batch and headless" intent doesn't hold here -- dashboard loads
unconditionally at startup, so nerd-icons does too either way.
Kept the `with-eval-after-load 'nerd-icons' safety net for the
re-evaluation case (advice still attaches if this module is
re-required after nerd-icons already loaded).
Comment in the file records why deferral isn't workable here so a
future cleanup pass doesn't try the same change again.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
- markdown-config.el: two related fixes on `markdown-preview'.
First, the URL was `https://localhost:8080/imp' but simple-httpd
serves plaintext on port 8080 -- the browser hit a TLS handshake
against a non-TLS listener and the preview never rendered. Changed
to `http://' and switched from `browse-url-generic' to plain
`browse-url' so the user's default protocol handler picks the
browser. Second, the function used to start the network listener
as a side effect of opening a preview; that's split into a
separate `cj/markdown-preview-server-start' command and
`markdown-preview' now signals a `user-error' (with the recovery
command in the message) when the server isn't running.
- slack-config.el: wrap the
`which-key-add-keymap-based-replacements' call in
`with-eval-after-load 'which-key'. Matches the pattern other
config modules use and means a slow / missing which-key load
won't block requiring slack-config.
- ai-vterm.el: pass the inner shell-command-string through
`shell-quote-argument' before wrapping in the tmux invocation.
The default value with embedded double quotes was safe under the
prior literal-single-quote wrap, but a user-customized
`cj/ai-vterm-agent-command' containing a single quote silently
broke the shell parse. Two existing tests updated to tolerate
the post-quote escape shape; new regression test asserts a
single-quote-bearing custom command survives.
- eshell-config.el: scope the `TERM=xterm-256color' override to
eshell-spawned processes only via an `eshell-mode' hook that
prepends to a buffer-local `process-environment'. The previous
global `setenv' at config-time changed `TERM' for every
subsequent `start-process' across the Emacs session, so any
subprocess (not just eshell pipelines) inherited
`xterm-256color' regardless of whether the receiver could
interpret the escapes.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
- prog-lsp.el: rename `cj/lsp--remove-eldoc-provider' →
`cj/lsp--remove-eldoc-provider-global' and call it once from the
lsp-mode `:config' block instead of attaching it per-buffer via
`lsp-managed-mode-hook'. The previous per-buffer remove with the
buffer-local flag raced lsp-mode's own population of the local
hook; removing the provider from the global default before any LSP
buffer attaches makes the absence stick. Two existing tests
updated to the new contract (remove-from-default + idempotent
re-run).
- prog-webdev.el / prog-python.el: warn at load time when
`prettier' or `pyright' is missing on PATH via
`cj/executable-find-or-warn'. Both modules now `(require
'system-lib)' to expose the helper. Missing dependencies surface
up front instead of mid-edit at first format/LSP attach.
- keyboard-compat.el: document existing idempotence. The hook
install uses a named function so `add-hook' deduplicates, and the
hook body only calls `define-key' (latest binding wins, same
value) -- adding a comment so future readers don't re-question.
- dev-fkeys.el: add a `typescript' clause to
`cj/--f6-test-runner-cmd-for'. F6 now runs `npx --no-install
vitest <path>' when vitest is on PATH, otherwise `npx --no-install
jest <path>'. Updates the matching test from "returns nil" to
cover both code paths; the impl-level test now asserts the routed
command instead of expecting a user-error.
- flycheck-config.el: build the LanguageTool wrapper path with
`(expand-file-name "scripts/languagetool-flycheck"
user-emacs-directory)' instead of a hardcoded `~/.emacs.d/...'.
Survives a non-standard `user-emacs-directory'.
- latex-config.el: replace the hardcoded Zathura viewer with
`cj/--latex-select-pdf-viewer', which walks
`cj/--latex-pdf-viewer-candidates' (zathura → evince → okular →
SumatraPDF → xdg-open) and falls back to "PDF Tools" when nothing
is on PATH. Each entry maps an executable to the matching
TeX-view-program-list name so AUCTeX's defaults handle the
actual viewer invocation.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
- org-roam-config.el: extract `cj/--org-roam-should-copy-completed-task-p'
and gate the `org-after-todo-state-change-hook' on it. Skips
fileless buffers (org-capture, indirect, temp Org) where
`buffer-file-name' is nil and the downstream copy used to crash.
Same gcal.org skip preserved. Five existing tests updated to
bind `buffer-file-name' inside `run-hooks' so the positive-case
hook still fires.
- org-webclipper.el: drop the redundant
`org-protocol-protocol-alist' registration inside
`cj/webclipper-ensure-initialized'. The
`with-eval-after-load 'org-protocol' block at the bottom of the
module is the single registration site now; comment in the
initializer explains why. Split the matching test into two:
one for template registration (the initializer's actual job) and
one for protocol registration (which now fires from the
after-load block when `org-protocol' provides).
- org-webclipper.el: validate `:url' and `:title' in
`cj/org-protocol-webclip'. `:url' must be a non-empty string;
`:title' must be a string when provided. Signals `user-error'
with the unexpected value instead of silently setting the
globals to nil and failing downstream in the capture handler.
- mu4e-org-contacts-integration.el: declare `contacts-file' (via
`eval-when-compile (defvar ...)') and `cj/get-all-contact-emails'
(via `declare-function') near the top of the file. Byte-compile
in isolation no longer warns about free variables / unknown
functions; the cross-module dependency is explicit at the top.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
- popper-config.el: move `(popper-mode +1)` and `(popper-echo-mode
+1)` from the use-package `:init` block into `:config`.
`:disabled t' on use-package skips `:config' but still runs
`:init', so the previous shape enabled popper-mode on every load,
including batch / test runs, despite the disabled marker.
- modeline-config.el: make `cj/modeline-vc-fetch' fall back when
the internal `vc-git--symbolic-ref' is missing. `require' uses
`nil 'noerror', the call sits inside an `fboundp' guard, and
`ignore-errors' wraps the call itself so an Emacs version that
renames or removes the accessor leaves `branch' at
`vc-working-revision''s output instead of crashing the modeline.
- ui-config.el: guard the cursor-color `post-command-hook' behind
`(display-graphic-p)' both at install time and inside the
function body. Batch / TTY runs short-circuit cleanly with no
per-command overhead. A `server-after-make-frame-hook' catches
the daemon case where the first GUI frame is created after
ui-config loads and installs the hook lazily. Updates
test-ui-config--buffer-cursor-state and
test-ui-cursor-color-integration to stub `display-graphic-p' so
the work body still runs under batch.
- nerd-icons-config.el: drop `:demand t' (`:defer t' now), keeping
the `:config' advice install as the natural lazy-on-load path.
Add a `with-eval-after-load 'nerd-icons' block as a safety net for
the already-loaded case on re-eval; the block uses `advice-member-p'
so the advice never stacks.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
- Guard `cj/duplicate-line-or-region' when COMMENT is non-nil but the
current mode has no `comment-start' (e.g. fundamental-mode).
Previously the function silently produced malformed output via
`comment-region'; now it signals a clear `user-error'.
- Factor the `find-file' advice install in external-open.el into
`cj/external-open-install-advice'. Same idempotent shape
(remove-then-add) but the intent is named.
- Add `cj/--validate-decoration-char' in custom-comments.el and
wire it into all six divider / border / box helpers. Rejects
multi-char strings, empty strings, and control characters like
newline/tab that would corrupt subsequent `M-q' flows. Updated
the five nil-decoration ERT tests from `:type 'wrong-type-argument'
(the old crash signal from `string-to-char' on nil) to
`:type 'user-error', since the validator produces a clear
message instead of a deep crash.
- Extract `cj/--require-spell-checker' in flyspell-and-abbrev.el.
Both `cj/flyspell-toggle' and `cj/flyspell-then-abbrev' now call
the shared helper; the checker list lives in
`cj/--spell-checker-executables', so adding nuspell or any other
checker is a one-line edit.
- Preserve trailing newlines in custom-ordering output. Both
`cj/--arrayify' and `cj/--unarrayify' now detect a trailing
newline on the input region and re-append it to the result,
matching the pattern custom-text-enclose.el already uses.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
system-defaults, chrono-tools
Six small fixes the 2026-05-15 module-by-module re-review surfaced:
- Consolidate `user-home-dir` -- canonical defconst stays in
early-init.el (package-archive bootstrap needs it before normal
modules load); user-constants.el switches to a `defvar` with the
identical `(getenv "HOME")` expression so the module still loads /
byte-compiles standalone, but at runtime early-init's defconst
wins.
- Drop the redundant `(autoload 'env-bsd-p ...)` line in
system-defaults.el. The `(eval-when-compile (require
'host-environment))` already exposes the symbol to the byte
compiler, and at runtime host-environment is loaded earlier in
init.el. Added a comment documenting the boundary.
- Convert `cj/debug-modules` and `cj/use-online-repos` from `defvar`
to `defcustom`, with `:type`, `:group 'cj`, and a top-level
`(defgroup cj ...)` so both show up in M-x customize.
- Name the package-archive priorities in early-init.el. Nine new
defconsts replace the magic numbers (200 / 125 / 120 / 115 / 100 /
25 / 20 / 15 / 5) with one constant each, plus a header comment
explaining the local-first ordering and the gnu > nongnu > melpa >
melpa-stable trust ranking within each tier.
- Delete the 19-line commented-out `use-package time` world-clock
block in chrono-tools.el. `time-zones` immediately above is the
active replacement; git history preserves the old config if anyone
needs it.
- Add coverage for `cj/tmr-select-sound-file`. Collapsed the
prefix-arg branch into a delegation to
`cj/tmr-reset-sound-to-default` (single reset source) and
extracted `cj/tmr--available-sound-files` as a pure helper that
tests directly. 9 ERT tests across Normal / Boundary / Error
cover the available-sounds helper, the reset path, the prefix-arg
delegation (no prompt), the normal selection path, and the
empty-dir / missing-dir / cancel boundaries.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The custom modeline builds `mode-line-format` from explicit segments
and skips `minor-mode-alist`, so flycheck's lighter never appears.
That hid error and warning counts even in buffers where flycheck was
auto-enabling (every emacs-lisp and sh buffer).
The fix is Option 4 from the design doc: customize the flycheck
modeline variables, then add a single guarded `(:eval ...)` form to
`mode-line-format`. Five new lines total, two-file change.
`modules/flycheck-config.el` :custom block gets:
(flycheck-mode-line-prefix "🐛")
(flycheck-mode-success-indicator " ✓")
`flycheck-mode-line-color` stays default-t so error / warning counts
pick up their faces automatically.
`modules/modeline-config.el` `mode-line-format` gets an `(:eval ...)`
between the recording indicator and `cj/modeline-vc-branch`:
(:eval (when (and (mode-line-window-selected-p)
(bound-and-true-p flycheck-mode))
(flycheck-mode-line-status-text)))
The `mode-line-window-selected-p` guard mirrors `cj/modeline-vc-branch`
and `cj/modeline-misc-info` -- segments hide in inactive windows.
The `bound-and-true-p flycheck-mode` guard keeps the form silent in
buffers where flycheck hasn't loaded or isn't enabled, which is
safer than referencing `flycheck-mode` directly.
The `(:eval ...)` is inline rather than a named `defvar-local`, so no
addition to the risky-local-variable list is needed.
`tests/test-modeline-config-flycheck-segment.el` -- 3 smoke tests
asserting the segment is present and both guards are in place. All
existing tests stay green.
Manual verification (per the design doc) is the user's call -- the
emoji prefix and the colored count behavior need a running GUI Emacs
to observe.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The Gptel Work project asked for a survey of published gptel tools
with adopt / skip / defer decisions per candidate. I can't do a
live community-tool survey from this session, so the doc covers
the candidates the task body called out plus a few obvious
adjacents.
Decisions:
- ADOPT (7): `search_in_files`, `git_status` / `git_log` /
`git_diff` (three tools), `web_fetch`, `search_emacs_help`,
`find_file_by_name`, `take_screenshot`. Each gets a sketch in
the doc -- args, validation posture, implementation outline.
- DEFER (2): `run_shell_command` (huge surface, click-fatigue
risk; the ADOPT-bucket tools cover most legit use cases),
`org_capture` (needs UX design for template pre-fill and the
round-trip).
- SKIP (1): `eval_elisp` (code execution from a model is too
dangerous even with confirm-each-call).
The doc also lists three follow-ups: the live community survey
that this session couldn't do, per-tool implementation sub-tasks
to be filed under the next iteration of Gptel Work, and a
sandboxing-convention decision for `web_fetch` (allowlist of
outbound URLs vs description-only warning).
Three open questions at the bottom of the doc for review:
build-all-at-once vs paired stages, `fd` as a hard dep vs `find`
fallback, Hyprland-only screenshot vs Wayland-generic via a
portal.
Closes the Gptel Work PROJECT for this iteration -- all 9 in-scope
sub-tasks landed this session.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
conversations
`cj/gptel-load-conversation` prompts via `completing-read`. A
dedicated browser shows what each conversation is about at a
glance and supports single-key load / delete / rename without
having to scroll a minibuffer list.
New module `modules/ai-conversations-browser.el` +
`cj/gptel-browse-conversations` entry point bound to `C-; a b`
("browse conversations"). Opens `*GPTel-Conversations*` in
`cj/gptel-browser-mode` (a `special-mode` derivative).
Each row shows date, time, topic slug, and a preview of the most
recent message (length configurable via
`cj/gptel-browser-preview-length`, default 60 chars). Rows sort
newest first.
In the browser:
- `RET` / `l`: load the conversation (delegates to
`cj/gptel-load-conversation` with the file pre-selected via a
`cl-letf` stub on `completing-read` so the user isn't prompted
twice), then bury the window.
- `d`: delete the file under point after `y-or-n-p` confirmation,
re-render.
- `r`: rename the file under point. Preserves the timestamp,
slugifies the new topic, refuses unchanged input and existing
targets.
- `g`: refresh.
- `n` / `p`: next / previous row.
- `q`: quit-window.
21 tests cover the helpers (topic parsing, header stripping,
preview shaping for truncate / short / empty cases, row-for-file
with conversation + non-conversation filenames, rows enumeration,
render output for empty + populated cases, newest-first sort,
rename-target preservation of timestamp + slug, rename-target
error on missing timestamp) and the file-touching actions (delete
with y, cancel with n, rename, rename-on-empty-line error).
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
`gptel-rewrite` is the killer feature for the keep-gptel decision,
and it now lives behind two commands instead of the bare call:
- `cj/gptel-rewrite-with-directive` (`C-; a r`, replacing the
former bare `gptel-rewrite` binding): completing-read on a
directive name from `cj/gptel-rewrite-directives`, then rewrite
the active region.
- `cj/gptel-rewrite-redo-with-different-directive` (`C-; a R`):
replay the prior region with a different directive. The region
is preserved via markers stored buffer-local on the first call so
it survives accept/reject of the prior rewrite.
I picked the hook injection approach over an `:after`-advice +
state-capture pattern. `gptel-rewrite-directives-hook` is an
abnormal hook gptel-rewrite already consults for a per-call
system message. Wrapping the call in a one-shot `let`-binding on
that hook gives the directive exactly the lifetime of the rewrite
and leaves nothing to clean up. Mutating `gptel-directives`
globally would mean either restoring it afterward or living with
the change -- both worse than the hook.
Directives ship inline as a `defcustom` alist with the six names
called out in the task -- `terse`, `fix-grammar`,
`refactor-readability`, `add-docstring`, `explain-as-comment`,
`shorten`. Customization is a `customize-variable` or `setq`
away.
9 tests cover the defcustom shape (default names present, bodies
non-empty strings), the wrapper (normal path, no-region error,
unknown-directive error, last-state recording), and the redo
(replays the prior region, errors when no previous, excludes the
current directive from the re-pick prompt). `gptel-rewrite`
stubbed in tests so no rewrite UI fires.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
New module `modules/ai-quick-ask.el`. Bound to `C-; a q` via
`cj/ai-keymap` ("quick ask").
`cj/gptel-quick-ask` reads a prompt in the minibuffer, creates a
transient `*GPTel-Quick*` buffer in `cj/gptel-quick-mode` (a
special-mode derivative with `q` / `escape` / `c` bindings), inserts
"Q: <prompt>" plus a response marker, then calls `gptel-request`
with `:stream t` so the answer streams into the buffer. Doesn't
touch `*AI-Assistant*`, doesn't autosave.
Two follow-up commands work in the buffer:
- `cj/gptel-quick-dismiss` (`q` / `escape`): delete the window and
kill the buffer. Idempotent when the buffer is absent.
- `cj/gptel-quick-continue` (`c`): extract the prompt + response,
seed them into `*AI-Assistant*` under proper org headings (matching
the `cj/gptel--fresh-org-prefix` shape), display the side window,
then dismiss the quick buffer.
13 tests cover the pure helpers (initial-text shape, response
extraction across normal / multi-line / no-marker / empty inputs,
seed-text shape), the ask path (buffer created in right mode,
prompt recorded, gptel-request called, empty-prompt error), the
dismiss path (kills buffer / no-op when absent), and the continue
path (seeds `*AI-Assistant*`, dismisses quick buffer, errors
outside a quick buffer). `gptel-request` is stubbed in tests so
nothing hits the network.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
indicator
`cj/gptel-autosave-enabled` flipped to t inside the save/load entry
points with no way back off short of editing the variable or
clearing the buffer, and no visible indicator that it was on.
Two pieces:
- `cj/gptel-autosave-toggle` flips the buffer-local state in the
current GPTel buffer. Bound to `C-; a A` via `cj/ai-keymap`
(which-key: "toggle autosave"). When autosave is OFF and no
filepath is configured yet, the command prompts to save the
conversation first so a save target exists; otherwise it just
flips the bit.
- `cj/gptel-autosave-mode-line-format` surfaces " [AS]" in the
mode-line when autosave is on, blank when off. Installed via a
`gptel-mode-hook` so every GPTel buffer picks it up. The install
helper is idempotent.
6 new tests cover enable/disable paths, the no-filepath prompt path,
the not-a-gptel-buffer error path, the mode-line format evaluation,
and the install idempotence.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The gptel-tools files had zero direct coverage outside of
`update_text_file`, which landed with its rewrite earlier this
session. This commit adds 52 tests across the five other tools.
For three of the tools the helpers were already top-level defuns
(`read_text_file`, `list_directory_files`, `move_to_trash`). The
other two had their main bodies inlined into the `gptel-make-tool`
lambda -- I extracted them so the work is testable without mocking
gptel itself:
read_buffer.el -> `cj/read-buffer--get-content`
write_text_file.el -> `cj/write-text-file--run` plus
`--validate-path`, `--backup-name`,
`--ensure-parent`
Test files, by tool:
- read_buffer.el (5 tests): normal, empty, buffer-object,
text-property-stripping, missing buffer.
- write_text_file.el (10 tests): validate-path, backup-name
shape, ensure-parent (creates missing / rejects unwritable), run
with normal / overwrite / existing-no-overwrite / empty content /
outside-home.
- read_text_file.el (12 tests): validate-file-path (normal +
three error shapes), metadata plist shape, size limits (no-op /
hard cap / warning bypass with no-confirm), binary detection
(text vs null-byte), special-type EPUB and generic-binary paths.
- list_directory_files.el (15 tests): mode-to-permissions (file /
dir / executable), get-file-info (file / directory), extension
filter (keep / drop / always-dir / nil-extension), format-file-
entry, list-directory flat / recursive / error, format-output
with and without files.
- move_to_trash.el (10 tests): unique-name (no conflict /
conflict with timestamp / no-extension), validate-path (HOME / /tmp
/ outside / critical-dir / missing), perform on file and
directory.
Each test file uses the same load-path / gptel-stub idiom
(`eval-and-compile` block, gptel stub when the real package isn't
available) so the byte-compile hook is happy.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
ai-conversations.el shipped without direct tests. This file covers
every helper and interactive entry point across Normal / Boundary /
Error.
Helpers: `cj/gptel--slugify-topic` (ASCII, empty input, all-special,
unicode stripped, idempotent, trim, digits); `cj/gptel--timestamp-
from-filename` (normal decode, year-edge boundaries, malformed
inputs returning nil); `cj/gptel--existing-topics` and `cj/gptel--
latest-file-for-topic` (multi-topic / multi-timestamp temp dirs,
empty dir, missing dir, prefix-overlap isolation); `cj/gptel--
conversation-candidates` (newest-first and oldest-first sort order,
display-string shape, error on missing dir); `cj/gptel--save-buffer-
to-file` (visibility headers prepended, round-trip through `cj/
gptel--strip-visibility-headers`).
Autosave: post-response hook saves only when gptel-mode + enabled +
filepath are all set; autosave-after-send swallows write errors via
`message` instead of signaling; the install-once guard prevents
double-registration.
Interactive entry points: save/delete exercised via `cl-letf` stubs
on `completing-read` and `y-or-n-p`.
Per-test temp directories; no writes outside them.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The wiring keyed on `with-eval-after-load 'magit` fires while two
of its three references are still undefined. `magit.el` calls
`(provide 'magit)` BEFORE its `cl-eval-when (load eval)` block
requires `magit-commit` and `magit-stash`. At that moment the
`magit-commit` transient prefix doesn't exist, and
`transient-append-suffix` silently no-ops on missing prefixes
(default `transient-error-on-insert-failure` is nil). The "g
Generate commit" and "x Explain" suffixes never landed. Only the
M-g binding worked, because `git-commit` IS required before
provide.
Three per-feature hooks replace the single `'magit` hook: one each
on `git-commit`, `magit-commit`, and `magit-diff`. Each hooks the
exact dependency the wiring needs, side-stepping the load-order
race entirely.
The companion test was rewritten to check `after-load-alist`
registration rather than drive the hooks through `provide`. Emacs
30 batch mode doesn't fire registered `eval-after-load` callbacks
on `provide` alone -- only an actual `load` does. Inspecting the
registration is the stronger guard anyway: the regression is "a
single `'magit` hook," and the right shape of that check is "no
entry under `magit`, entries under `git-commit`, `magit-commit`,
`magit-diff`."
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
I rewrote `update_text_file.el` in pure Elisp. The previous version
shelled out to sed for everything, had a stray quote terminator at EOF
(line 149) that broke loading, produced literal backslash-n where
actual newlines were expected, and prompted via `y-or-n-p` redundantly
with gptel's own `:confirm t` flag.
The five operations -- replace, append, prepend, insert-at-line,
delete-lines -- split into pure string transforms that test without
touching the disk. The file-level wrapper validates the path, enforces
a 10MB size limit, takes a timestamped backup, and writes atomically.
No backup is created when the operation is a no-op. Patterns are
literal substrings (not regex) so the model can't trip over
metacharacter quoting.
`tests/test-update-text-file.el` covers Normal / Boundary / Error per
operation plus the file-level wrapper. 48 tests green. Added
`update_text_file` to `cj/gptel-local-tool-features` so gptel exposes
the tool after restart.
|
| |
|
|
|
|
|
|
| |
gptel's `gptel--with-buffer-copy-internal` copies the source buffer's `major-mode` symbol but doesn't run mode hooks. An inherited-org-mode prompt buffer keeps `tab-width` at this config's global default of 4 instead of the 8 that `org-mode-hook` would set. When gptel later parses the prompt buffer with `org-element`, Org's `tab-width=8` guard raises "Tab width in Org files must be 8, not 4."
I was hitting this on every second `gptel-magit-generate-message` from COMMIT_EDITMSG. `vc-config.el` sets `git-commit-major-mode 'org-mode'`, and the diffs contained list-shaped content that `org-element--list-struct` parsed.
The advice forces `tab-width=8` in the prompt buffer when its inherited mode is org-mode. It's a local workaround for an upstream gap. An upstream patch to run `(delay-mode-hooks (funcall major-mode))` in the buffer-copy is the real fix. I'll send it next.
|
| |
|
|
|
|
|
| |
Replace raw autoload calls with a `use-package` declaration so
`use-package-always-ensure` installs gptel-magit on machines that
haven't run `package-install`, fixing the "Cannot open load file"
error on transient setup.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The shape (if (not (abbrev-mode)) (abbrev-mode)) calls abbrev-mode with
no argument -- that's the toggle signature, not a query. When the mode
was already on the function flipped it off then on instead of being a
no-op. Replaced with (unless (bound-and-true-p VAR) (MODE 1)) for both
abbrev-mode and flycheck-mode. 4 ERT tests cover both-off, both-on, and
the two mixed states.
Also ran the module hardening pass across 24 newly-added modules,
renamed the six completed Review sub-tasks to Harden, filed 11 new
findings under their Harden parents, and broke three design specs
(EMMS-free music, dev F-keys, dev-setup-project) into 20
dependency-ordered sub-tasks via parallel subagents. Verified the
sqlite finalizer bug from 2026-04-26 is gone and closed its tracking
entry.
|
| |
|
|
|
|
|
|
| |
The three integration tests in test-video-audio-recording-process-cleanup spawn wf-recorder via cj/ffmpeg-record-video and assert on pgrep counts. They guard with executable-find and XDG_SESSION_TYPE checks, but neither catches the case where the subprocess can run wf-recorder yet lacks Wayland screencast permission. wf-recorder picks a region, retries "Failed to copy frame" 17 times, then exits with code 183 inside a second. The assertion fires against an empty pgrep.
I added test-cleanup--can-capture-frames, which calls cj/ffmpeg-record-video against a temp dir, waits 1s, and checks pgrep. If wf-recorder didn't survive, the three integration tests skip. The result is cached, so the ~2.5s cost is paid once per batch.
I added the same guard to test-integration-video-recording-multiple-start-stop-cycles. Its assertion is (= count initial-count), so it trivially passed in any environment where capture didn't work. Skipping is more honest than passing for the wrong reason.
|
| |
|
|
| |
Now that yasnippet handles `<cj` + TAB in every buffer including org-mode, the `cj` entry in `org-structure-template-alist` is redundant. I removed it and left a one-line comment pointing to where the marker now lives.
|
| |
|
|
|
|
|
|
|
|
|
|
| |
New `snippets/fundamental-mode/cj-comment-block` expands `<cj` + TAB to the literal three-line marker block:
#+begin_src cj: comment
<cursor>
#+end_src
It lives in `fundamental-mode/` so yas's parent-chain lookup finds it in every buffer, plus the activation hook from the previous commit explicitly turns on `fundamental-mode` as an extra mode in every buffer — so even modes that don't descend from `fundamental-mode` (like `special-mode`-derived buffers) pick it up.
The marker is what my Python scanner skill picks out across files. Now I can plant it in any buffer, not just org where the old org-tempo entry lived.
|
| |
|
|
|
|
|
|
| |
The yasnippet use-package block switches from `:hook (prog-mode . yas-minor-mode)` to `:demand t` + `(yas-global-mode 1)`. That makes yas-minor-mode active in every buffer, not just prog-mode-derived ones.
I added a small helper, `cj/--yas-activate-fundamental-extras`, attached as `:hook (yas-minor-mode . ...)`. It calls `(yas-activate-extra-mode 'fundamental-mode)` so the snippet table at `snippets/fundamental-mode/` is consulted in every buffer regardless of the buffer's own major mode. That's what makes universal triggers like `<cj` work everywhere.
The new `tests/test-prog-general-yas-activation.el` covers both wiring (yas-global-mode on, fundamental-mode in yas-extra-modes, yas-minor-mode active in org/text buffers) and end-to-end expansion (the marker snippet expands correctly in fundamental, text, org, emacs-lisp, and python-ts modes). 9 tests, all green; full unit suite green with no regressions.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
`cj/org-roam-filter-by-tag' called `org-roam-node-tags' directly.
That accessor is generated by `cl-defstruct' and ships with a
compiler-macro that inlines the call to an `aref' against the
`cl-struct-org-roam-node-tags' tag variable at byte-compile time.
In tests, `cl-letf' on `(symbol-function 'org-roam-node-tags)' sets
the function cell but the byte-compiled call site never consults it
-- it executes the inlined `aref' instead. When org-roam isn't
loaded (legitimate for a tag-filter unit test), the inlined code
fails with `void-variable cl-struct-org-roam-node-tags'.
Wrap the accessor in `cj/--org-roam-node-tags' that calls through
`funcall' with a quoted symbol. Quoted symbols skip the
compiler-macro (which only fires on direct call forms), so the
funcall resolves the function cell at runtime and picks up the
test's `cl-letf' stub. Production behavior is unchanged; tests
no longer need org-roam loaded.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
`org-web-tools-pandoc-sleep-time' is a plain float with no
custom-set handler that needs to fire. `setopt' adds the entire
customize-variable validation machinery -- which, lazily, depends on
wid-edit being loaded.
The handler's tests stub `require' so org-web-tools never really
loads, then mock `setopt' via `cl-letf' on the function cell. That
mock has no effect on byte-compiled code because `setopt' is a
macro: the production handler has already expanded to a call into
`setopt--set'. When `setopt--set' runs, it walks into the customize
machinery and hits an unbound `widget-field-keymap' (wid-edit not
loaded), and the test fails with a confusing wrong-type-argument.
`setq' has identical runtime effect for this variable and dodges
the customize machinery entirely. Tests now pass without contorted
mocking.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The module had `(eval-when-compile (require 'keybindings))`, which
silences the byte-compiler but doesn't make `cj/custom-keymap'
available when the module is required. The top-level
`(keymap-set cj/custom-keymap "!" cj/system-command-map)' at the tail
of the file then fails with `void-variable cj/custom-keymap'.
Normal Emacs startup happened to work because `init.el' requires
`keybindings' before `system-commands'. But requiring the module in
isolation -- including from `make test-file
FILE=test-system-commands-resolve-and-run.el' -- blows up.
Fix: use a plain `(require 'keybindings)' so the load-time
dependency matches the load-time reference.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The Info-mode entry in cj/buffer-source-functions copied the bare
target string info:(manual)Node. Per the task body that introduced
the dispatcher, the intended output is the labeled org-link form
[[info:(manual)Node][(manual) Node]] -- a paste into notes lands as
a clickable link with a human-readable label, not a bare URI.
The label uses (manual) Node so the manual name and node name are
both grep-friendly in note files.
Existing test on a compressed .info.gz file now asserts the bracket
form. Added a boundary test for an uncompressed .info file (the
other branch of the suffix-stripping logic) so both compression
shapes are locked in.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
make compile warned that cj/toggle-gptel is not known to be defined
when ai-vterm.el is byte-compiled. The M-F9 binding still worked
during normal startup because init.el loads ai-config.el after
ai-vterm.el, but the dependency was implicit -- byte-compile saw the
function symbol unresolved, and loading ai-vterm.el in isolation
left M-F9 bound to an undefined function.
Declare cj/toggle-gptel as an interactive autoload pointing at
ai-config. This silences the warning, keeps ai-vterm.el free of a
load-time (require 'ai-config), and makes the load-order contract
explicit: the binding works as long as ai-config eventually loads.
Test asserts that requiring ai-vterm in isolation leaves
cj/toggle-gptel fboundp as an autoload sigil (not a real function).
A regression that adds (require 'ai-config) at the top of
ai-vterm.el would flip this, and a regression that drops the
autoload form would leave fboundp nil.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Add a tiny source-level architecture suite at
tests/test-architecture-startup-contracts.el with two checks:
- Only keybindings.el may globally own the exact C-; prefix. Catches
accidental cross-module rebinding before it ships.
- Top-level timer scheduling (run-with-timer / run-at-time /
run-with-idle-timer) must be guarded by (unless noninteractive ...)
so requiring a module in batch / test mode does not schedule
startup timers. Timer calls inside defuns are exempt -- the test
only rejects forms that execute their body when the module loads.
Four modules had unguarded top-level timer scheduling and would have
tripped the new test. Wrap their startup hooks/timers in
(unless noninteractive ...):
- modules/org-agenda-config.el: 10s idle cache build
- modules/org-refile-config.el: 5s idle cache build
- modules/quick-video-capture.el: after-init-hook + 2s fallback
- modules/wrap-up.el: emacs-startup-hook bury-buffers delay
The contract being protected is "requiring a module in batch should
not start a clock running." Test failures will now point straight at
the offending file/form.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
=make coverage= used to print a line-weighted percentage that only saw
files SimpleCov instrumented. 104 modules existed on disk but only 49
appeared in =.coverage/simplecov.json=, so the headline number was
flattering: untouched modules counted for nothing.
The summary script now adds two things on top of the existing report:
- A =Not in SimpleCov report= section listing modules present under
=modules/*.el= but absent from the SimpleCov output. Missing-module
detection is exactly direct =modules/*.el=; subdirectories and =.elc=
files are ignored.
- A =Project module coverage= line that is module-weighted across every
direct =modules/*.el= file. Tracked modules contribute their per-file
coverage percentage; missing modules contribute 0%.
The original line-weighted SimpleCov percentage stays as the
=instrumented coverage= number. The new module-weighted score is the
honest project-level reading: missing modules count as 0% without
inventing a fake executable-line denominator for them.
Tests assert the missing-module section, the new percentage, and the
ignore rules for .elc / nested files.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The spec lays out the EMMS-removal design: package-owned track and
playlist structs, a narrow backend protocol with mpv as the v1 backend,
state-change hooks replacing EMMS player hooks, an overlay-based
selected-track marker, a fake-backend test architecture, a quantified
performance budget, a 22-step parity walk, and the migration plan.
The review tracks implementation readiness: which migration-plan step
is safe to start, which decisions still block the rest, and the exact
spec edits required.
Two decisions landed this session and are now baked into the spec:
- Platform support: Linux and macOS get full features; Windows runs in
degraded mode (play/stop/next/previous only) because Emacs cannot
natively connect to mpv's Windows named-pipe IPC. Anyone who wants
full Windows parity can wire mpvc.exe shellout or a w32-* named-pipe
client as a follow-up.
- File-extension scope: cj/music-file-extensions stays as-is. webm and
ape files in ~/music are intentionally skipped.
Socket path now references temporary-file-directory instead of a
hardcoded /tmp/ prefix so the spec stays consistent with the Windows
section.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Replaces the .ai/ draft (2025-11-14) with a corrected and tightened
version under docs/design/. The earlier draft had stale line numbers
pointing at a modeline-config.el layout that no longer exists,
conflated Option 3's risky-local-variable requirement with Option 4's
inline (:eval ...) approach, and missed the active-window gating
convention used by the rest of the modeline.
The new spec uses concrete line refs against current code, calls out
flycheck-mode-line-color (which the old draft missed), recommends
calling flycheck-mode-line-status-text directly instead of returning
the nested (:eval ...) cons, and gates the segment to active window
for consistency with cj/modeline-vc-branch and cj/modeline-misc-info.
todo.org task points at the new path and drops the broken
docs/flycheck-modeline-customization-spec.org link.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Replaces a thin third-party config snippet (one use-package corfu + one
use-package cape, with no migration steps and no prescient piece) with
a full spec covering the current company stack: corfu, cape,
corfu-popupinfo, kind-icon, corfu-prescient.
Maps every current company setting to its corfu equivalent
(idle-delay, prefix-length, tooltip-limit, wrap, require-match,
global-mode exclusions, doc popups, icon kinds, prescient sort).
Walks the per-module fixups -- selection-framework, mail-config,
ledger-config, latex-config, eshell-config, and the three prog-*
mode hooks. Adds a test plan and risks section.
todo.org points at the new doc; the broken :COMPLETE_CONFIG:
property (which referenced the wrong line range in someday-maybe)
is gone.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Add two dispatchers to cj/buffer-source-functions so C-; b p yields a
useful link form in two more major modes.
mu4e-view-mode returns "mu4e:msgid:<id>" so the result pastes into org
as a clickable link and matches mu4e's own org-protocol handler.
Falls through to buffer-file-name when point isn't on a real message.
Info-mode returns "info:(manual)node" -- the form org-info-store-link
produces. file-name-base only strips one extension, so a compressed
"emacs.info.gz" comes back as "emacs.info"; trim the trailing ".info"
to get the bare manual name. Falls through when Info hasn't populated
its current-file / current-node vars yet.
Tests cover normal + boundary fallthrough for each new mode.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
`cj/org-noter-insert-note-dwim' is the most-used action in a noter
session; it deserves the doubled-prefix letter. Move it from
`C-; n i' to `C-; n n'.
Sibling-stepping moves off `n'/`p' (which were sync-next /
sync-prev) onto the angle-bracket pair `>'/`<' to free up `n' and
to read more naturally as direction. `.' stays as
sync-current-note.
Updated `which-key' labels to match. Four new ERT tests in
`tests/test-org-noter-config-keymap.el' lock the keymap shape so a
casual edit doesn't silently drift the layout.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
`make compile' had been flagging `cj/calibredb-clear-filters' and
`cj/nov-jump-to-calibredb' as "defined multiple times in this file"
since 2026-05-12. Investigation: there's only one `(defun ...)' of
each in the source -- use-package's `:bind' expansion makes the
byte-compiler count the referenced symbol as a definition when the
function is defined in the same file, then it sees the real
`defun' later and warns about a redefinition.
Reorder so each `defun' appears before the `use-package' that
references it via `:bind':
- `cj/calibredb-clear-filters' moved above (use-package calibredb).
- `cj/nov--metadata-get', `cj/nov--file-path', and
`cj/nov-jump-to-calibredb' moved above (use-package nov). The
two helpers had to move with the public function so the
byte-compiler doesn't emit fresh free-function warnings.
Source content unchanged; only line positions move. Both
duplicate-definition warnings are gone after this; full unit suite
still green.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Old behavior: `C-; b p' called `cj/copy-path-to-buffer-file-as-kill',
which only worked in file-visiting buffers and errored otherwise.
That meant the most useful "give me a clickable handle on this
buffer" key did nothing in eww, elfeed, dired (file-at-point ≠
buffer's default-directory), and other browsing-shaped modes.
Replace with a `major-mode'-aware dispatch:
- `cj/buffer-source-functions' alist maps major-mode → thunk
returning a string (or nil to fall through).
- `cj/copy-buffer-source-as-kill' looks up the current mode,
calls the thunk, falls back to `buffer-file-name', errors only
when both yield nil.
- `cj/copy-path-to-buffer-file-as-kill' kept as a `defalias' for
backwards compat (the old name is referenced in adjacent tests).
First-batch dispatches:
- eww-mode -> (eww-current-url)
- elfeed-show-mode -> (elfeed-entry-link elfeed-show-entry)
- dired-mode -> (dired-get-filename nil t)
- dirvish-mode -> same
- doc-view / pdf-view: covered by the buffer-file-name fallback
(they already set buffer-file-name correctly).
10 new ERT tests cover the dispatch paths, the
buffer-file-name fallback, the user-error on nil source, the alias
target, and the `C-; b p' keymap entry.
which-key label flipped from "copy file path" to "copy buffer
source" to match.
Deferred to a follow-up task: mu4e-view-mode, org-mode at a
heading, help-mode, Info-mode, magit-log/commit/status, xref/grep/
compilation, image-mode, archive-mode -- each needs a format
decision before implementation.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
M-F9 used to invoke `cj/ai-vterm-pick-buffer' (a buffer picker
narrowed to alive AI-agent buffers). In practice the F9 plain-key
toggle + C-F9 project picker covered the common cases, and the
buffer picker rarely earned its keystroke. Rebind M-F9 to
`cj/toggle-gptel' so the F9 family covers the two main in-Emacs AI
surfaces at one keystroke each:
<f9> ai-vterm toggle (unchanged)
C-<f9> ai-vterm picker (unchanged)
M-<f9> gptel *AI-Assistant* (NEW)
Removed entirely:
- `cj/ai-vterm-pick-buffer' (the command itself).
- `cj/--ai-vterm-pick-buffer-candidates' (its helper).
- `tests/test-ai-vterm--pick-buffer-candidates.el' (deleted).
Updated:
- `tests/test-ai-vterm--f9-in-vterm.el' binding assertions
(vterm-mode-map and global) flipped to `cj/toggle-gptel'.
- Module commentary + `cj/ai-vterm' docstring describe the new
M-F9 behavior.
- `cj/toggle-gptel' lives in `modules/ai-config.el'; the binding
stays in `ai-vterm.el' next to the rest of the F9 family so the
dispatch shape is visible in one place.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Anthropic: bump Opus 4.6 → 4.7 (current frontier). Sonnet 4.6
and Haiku 4.5 stay -- still current. Default `gptel-model' setq
also bumped to claude-opus-4-7 in both places it was set.
OpenAI: drop the cohort retired from ChatGPT on 2026-02-13
(gpt-4o, gpt-5 original, gpt-4.1, o1). Replace with the current
lineup: gpt-5.5 (flagship), gpt-5.4-mini (fast/cheap), o3
(reasoning). All three are documented at
developers.openai.com/api/docs/models/.
Drive-by: stale docstring example in cj/gptel--current-model-selection
bumped to match.
gptel's bundled :models list only knows up to May-2025 IDs but
gptel-make-anthropic / gptel-make-openai accept any string and pass
it straight to the API, so newer names work without a gptel upgrade.
|