Built-in support to log and print the last few typed keys and executed commands. To be used for debugging or understanding what went wrong. Could also be used for statistics. Allows for various verbosity and filtering levels.
related: #12046
related: #12063
This is my first time contributing, so any feedback is welcome. Currently, I haven't added any support for scripts, plugins or autocmd, so if I am heading in the right direction, then I can work on that.
Regards,
Sid
https://github.com/vim/vim/pull/20339
(24 files)
—
Reply to this email directly, view it on GitHub, or unsubscribe.
Triage notifications on the go with GitHub Mobile for iOS or Android.
You are receiving this because you are subscribed to this thread.![]()
Thanks for the PR, and for clearly marking it as an early step and asking for
direction — that makes it easy to give useful feedback. Below are two separate
things: first whether the feature is needed given what Vim already has, and
then, independent of that, some concrete suggestions on the command and option
design.
Before investing more effort, it would help to spell out what this gives that
the existing mechanisms don't, because there is a lot of overlap:
scriptout / -W file / :redir:verbose with the 'verbose' levels and'verbosefile' (this already follows autocommands, sourcing, mappings andch_logfile() / ch_log() / --log / --startuptime:messages (message history) / :history /keytrans()The one genuinely new aspect I see is the in-memory ring buffer that you can
dump after the fact, as opposed to 'verbosefile', which streams everything
to a file up front. That is a real difference and matches the linked requests
(#12046, #12063). If you can frame the feature explicitly around that gap — "a
bounded, always-on ring buffer you inspect after something went wrong" — it
becomes much easier to judge on its own merits. As it stands the scope is large
(a new command, three new options, ~2000 lines, no feature guard) for something
that partly duplicates the above, so narrowing the justification first seems
worthwhile.
:trace with subcommands:tracewhathappened is long and not very Vim-like. I'd suggest a terse base
command :trace with verb subcommands, the way diagnostic/introspection
commands already work in Vim: :profile start|pause|dump|func, :syntax,
:sign define|place|unplace. :profile is the closest precedent since it is
also a debugging aid driven by subcommands.
For example:
:trace dump [count] " print recent events (replaces :tracewhathappened)
:3,40trace dump " range works on the base command
:trace clear " drop recorded events
(:trace show would read fine too.) Note that tr already abbreviates to
:trewind/:try, so the shortest unambiguous form would be :tra — not a
problem, just worth knowing.
'traceopt'Three options for one feature is a lot of option namespace, and the rtv/
rtf/rts short names are hard to remember. Vim's idiom for this is a single
comma-separated option with bare flags plus key:value items, exactly like
'diffopt' (and 'completeopt', 'wildoptions', 'tabpanelopt', ...). A
single 'traceopt' could carry all three:
set traceopt=input,command,ex,mapping,mode,verbosity:debug,ringsize:1024
input, command, ex, ...) = categories to record'tracefilter')verbosity:{minimal|normal|verbose|debug} (replaces 'traceverbosity')ringsize:{N}, minimum 16 (replaces 'traceringsize')The old 'tracefilter' was itself a comma list, so it maps directly onto the
bare flags of the parent option with no nesting. The verbosity:/ringsize:
items parse the same way as 'diffopt''s context:4 / algorithm:histogram,
so this stays fully within an existing, well-understood pattern.
Together these two changes shrink the user-visible surface from one command
plus three options to one command plus one option, which also helps with the
scope concern in point 1.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
Triage notifications, keep track of coding agent tasks and review pull requests on the go with GitHub Mobile for iOS and Android. Download it today!
You are receiving this because you are subscribed to this thread.![]()
Stepping back from naming and option count, there is a more fundamental
question worth settling before more work goes in.
The only genuinely new thing here is a bounded, always-on, in-memory ring
buffer of recent events that you can dump after the fact. Almost everything
else already exists in Vim, just spread across separate mechanisms:
(See above my comment)
So the question is:
Why can't this be added as an extension of one of those existing
subsystems — for example an in-memory / ring-buffer mode for
'verbosefile'/:verbose, or building on the message-history or ch_log
infrastructure — instead of a new :trace command plus its own option
family?
I think the burden of proof is on introducing a new parallel subsystem.
Adding a new top-level command and a new option family has a high bar in Vim
precisely because a second, overlapping system fragments where users look,
duplicates the buffer/parse/doc/test code, and splits the concept of "recent
activity" across two stores that then have to be kept consistent. If the gap
genuinely cannot be filled by extending an existing facility, that's a strong
argument for the feature; if it can, the new subsystem is hard to justify
regardless of how it's named.
This isn't a request to scrap the idea — the ring-buffer-you-dump-later angle
is real. It's a request to pin down where it should live before polishing the
surface.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
Triage notifications, keep track of coding agent tasks and review pull requests on the go with GitHub Mobile for iOS and Android. Download it today!
You are receiving this because you are subscribed to this thread.![]()
I agree, it seems to duplicate a bit of existing functionality. On the other hand, I think it could also pave the way to e.g. the settable dot register: #19413
—
Reply to this email directly, view it on GitHub, or unsubscribe.
Triage notifications, keep track of coding agent tasks and review pull requests on the go with GitHub Mobile for iOS and Android. Download it today!
You are receiving this because you are subscribed to this thread.![]()
Marking as draft for now
—
Reply to this email directly, view it on GitHub, or unsubscribe.
Triage notifications, keep track of coding agent tasks and review pull requests on the go with GitHub Mobile for iOS and Android. Download it today!
You are receiving this because you are subscribed to this thread.![]()
Thank you for the feedbacks.
What my PR is attempting to solve is like you aptly pointed out, ring-buffer-you-dump-later which is not quite there in the other features. But, I do recognize the high bar to introduce another sub-system for logging (or logging adjacent).
So then, first I can start with defining what this feature would be (based on your inputs) and also define the boundaries:
ch_log or verbosefile or other existing features instead of reinventing another sub-system.trace dump: I think this is something that would be needed to eliminate or reduce noise to have a better UI.ch_log() and its other channel functionalities could serve as the best underlying mechanism to gather these logs. So perhaps a dedicated channel that writes into the ring-buffer could be one way to do that.channels.ch_logfile() if extending existing functionalities, but I am not sure if this would be accurate in terms of conveying what it does or what its functionality would be.ch_logringbuffer()
$ vim --logringbuffer input,command,ex
:trace dump [count] " print recent events (replaces :tracewhathappened)
:3,40trace dump " range works on the base command
:trace clear " drop recorded events
:set traceopt=input,command,ex,mapping,mode,verbosity:debug,ringsize:1024
$vim -u NONE -N -c "set tracefilter=command,input,mapping,ex,mode" -c "inoremap jj <Esc>" -c "call feedkeys(\"ihello\r\rjj\", 't')"
:tracewhathappened
#1 [ex] inoremap<Space>jj<Space><Esc> arg=jj<Space><Esc> [NORMAL]
#2 [ex] call<Space>feedkeys("ihello\r\rjj",<Space>'t') arg=feedkeys("ihello\r\rjj",<Space>'t') [NORMAL]
#3 [input] text=ihello<CR><CR>jj [NORMAL]
#4 [command] i [NORMAL]
#5 [insert] "hello" [INSERT]
#10-#11 [input] <CR> x2 [INSERT]
#12 [mapping] jj -> <Esc> [INSERT]
#13 [input] text=<Esc> [INSERT]
#14 [input] <Esc> [INSERT]
verbosefile for a similar operation as above (Agreed that verbose makes much more sense for debugging complicated operations like autocmd or plugins)$ ./src/vim -u NONE -N -c "inoremap jj <Esc>" -c "call feedkeys(\"ihello\r\rjj\", 't')" -V1000dump.log
$ cat dump.log
==== start log session Thu May 28 11:13:24 2026 ====
0.000752943 : Setting termcap entry ku to *A
0.000757784 : Adding termcap entry kd to *B
...
Executing: inoremap jj <Esc>ap entry PE to
Executing: call feedkeys("ihello\r\rjj", 't')-- INSERT --
Executing: q!
—
Reply to this email directly, view it on GitHub, or unsubscribe.
Triage notifications, keep track of coding agent tasks and review pull requests on the go with GitHub Mobile for iOS and Android. Download it today!
You are receiving this because you are subscribed to this thread.![]()