[vim/vim] Add tracing support (PR #20339)

10 views
Skip to first unread message

Siddarth Balaji

unread,
May 27, 2026, 2:53:08 AM (yesterday) May 27
to vim/vim, Subscribed

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


You can view, comment on, or merge this pull request online at:

  https://github.com/vim/vim/pull/20339

Commit Summary

File Changes

(24 files)

Patch Links:


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.Message ID: <vim/vim/pull/20339@github.com>

h_east

unread,
May 27, 2026, 8:08:38 AM (yesterday) May 27
to vim/vim, Subscribed
h-east left a comment (vim/vim#20339)

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.

1. Overlap with existing facilities

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:

  • Recording typed keys → scriptout / -W file / :redir
  • Tracing internal activity → :verbose with the 'verbose' levels and
    'verbosefile' (this already follows autocommands, sourcing, mappings and
    option setting)
  • Execution logging → ch_logfile() / ch_log() / --log / --startuptime
  • Recent messages and commands → :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.

2. Command design: :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.

3. Option design: collapse the three options into one '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
  • bare words (input, command, ex, ...) = categories to record
    (replaces 'tracefilter')
  • verbosity:{minimal|normal|verbose|debug} (replaces 'traceverbosity')
  • ringsize:{N}, minimum 16 (replaces 'traceringsize')
  • empty value = disabled, matching the current "empty filter = off" behaviour

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.Message ID: <vim/vim/pull/20339/c4554333968@github.com>

h_east

unread,
May 27, 2026, 9:04:50 AM (yesterday) May 27
to vim/vim, Subscribed
h-east left a comment (vim/vim#20339)

The decisive question: extend, don't duplicate

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.Message ID: <vim/vim/pull/20339/c4554731738@github.com>

Christian Brabandt

unread,
May 27, 2026, 11:22:28 AM (yesterday) May 27
to vim/vim, Subscribed
chrisbra left a comment (vim/vim#20339)

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.Message ID: <vim/vim/pull/20339/c4555938818@github.com>

Christian Brabandt

unread,
May 27, 2026, 11:23:01 AM (yesterday) May 27
to vim/vim, Subscribed
chrisbra left a comment (vim/vim#20339)

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.Message ID: <vim/vim/pull/20339/c4555941722@github.com>

Siddarth Balaji

unread,
2:32 AM (15 hours ago) 2:32 AM
to vim/vim, Subscribed
cyan12green left a comment (vim/vim#20339)

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).

Definition

So then, first I can start with defining what this feature would be (based on your inputs) and also define the boundaries:

  1. An in-memory ring buffer.
  2. Data ingestion using existing sub-system like ch_log or verbosefile or other existing features instead of reinventing another sub-system.
  3. The hooks should be across various modes/scripts/autocmd/inputs/ex and so on, with its own format.
  4. The logs need to be user friendly, as this feature does not aim to replace the more robust low-level logging features, and instead existing as a high-level at a glance trace of the near history.
  5. Dynamically filtering based on the source or category during trace dump: I think this is something that would be needed to eliminate or reduce noise to have a better UI.
  6. I am not sure if it would necessarily help with settable dot register (or similar use cases): #19413 , since I wanted this primarily to be a logging/history - like feature.

Design

  1. I believe that of the existing infrastructures, 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.
    Added benefit is that then, this could be feature-gated along with channels.
  2. The scope of this could be:
    - Input (raw keycode mapped to readable names)
    - Commands (ex and normal)
    - Operators (and their lifecycle)
    - Mapping (and their resolution during execution)
    - Modes (perhaps the switching between modes)
    - Autocmd and Scripts (This could be quite complex depending on what kind of outputs would be needed from these)

API

  1. I understand the challenges with introducing a new top-level command with its options, but I would like to point out that the existing features don't cover logging across the various moving parts of vim while also having it be high-level in terms of the output. I believe that is the value-add of this feature since as I mentioned earlier, this does not aim to replace the low level robust logging features.
  2. Perhaps, another function similar to 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
  1. Now if there is an actual use case for a new top-level command then as pointed out earlier, this can be condensed to just a command with a verb and command-opt, like pointed out earlier to make it more succinct:
: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

Output

  1. Taken from my existing code, I would like the output to be something similar:
$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]
  1. This is a sample from 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.Message ID: <vim/vim/pull/20339/c4561374957@github.com>

Reply all
Reply to author
Forward
0 new messages