Until now every keybinding config field was a plain string. That meant a user
couldn't ask for two keys to invoke a command — the config silently accepted
only one form.
Convert every string-typed field across all 13 KeybindingXxxConfig structs to
Keybinding so the union type extends to every command. Defaults wrap their
single-key value in Keybinding{...} so the generated Config.md still renders one
scalar key per binding.
The alt fields keep their separate Binding registrations for now: this commit
does not yet introduce the merge mechanism that folds them into the main field —
that comes in a follow-up. Consumers previously calling opts.GetKeys on a string
field now call opts.GetKeys on the Keybinding, or take .String() / Keys[0] where
a single value is needed.
Adds a Keybinding.String helper for rendering, schema-generator work that
inlines the Keybinding union into each consuming property, and a unit test
covering the user-facing scalar/sequence YAML forms for quit.
This is useful when cancelling out of the commit panel mid-sentence (after
having typed the space for the next word); when entering the commit message
panel again, the space was gone and you had to type it again. Small thing, but
it just seems better to resume the panel in exactly the state that you left it
in. (Which we actually don't do; we don't remember the cursor position, or which
of the subject/description panels was active. That would be a separate
improvement.)
The save path and the load path used to be asymmetric. On save, the textarea
getters applied strings.TrimSpace, which stripped any leading blank lines, a
trailing newline after the cursor, or indentation on the very first line of the
description — all of which are legitimate user content. On load,
SplitCommitMessageAndDescription did TrimSpace on the description as well, and
the preserved message was routed through that same git-format split because
HandleCommitPress passed it as OpenCommitMessagePanel's InitialMessage. The
result: every round-trip through "escape and reopen" silently mutated the
message.
The fix is to treat our own preservation file as its own format, distinct from
git's canonical "summary\n\nbody" format:
- The textarea getters return raw content. strings.TrimSpace moves to the one
place that still needs it: the empty-summary check in HandleCommitConfirm (git
itself strips trailing whitespace and blank lines, so no pre-trim is needed
before -m).
- SplitPreservedCommitMessage / SetPreservedMessageInView split on the single
"\n" our Join uses, without any trimming — truly lossless.
- SplitCommitMessageAndDescription keeps its git-format behavior but replaces
TrimSpace with TrimPrefix("\n"), so it strips only the blank-line separator
and leaves body indentation intact.
- HandleCommitPress now mirrors HandleWIPCommitPress: it no longer passes the
preserved message as InitialMessage. OpenCommitMessagePanel resolves the
preserved content itself, uses it for display via the preservation-format
setter, and stores it as the initial message so the close-time "did the user
change anything?" check still correctly detects a cleared panel.
- GetInitialMessage no longer trims. With raw getters on both sides of the
comparison, trimming here caused spurious non-matches (e.g. for preserved
content with trailing whitespace). The original motivation — matching a
"WIP: " prefix with trailing space — works unchanged.
- UpdateCommitPanelView becomes dead code and is removed; its one remaining
caller (history cycling, always git-format) goes directly through
SetMessageAndDescriptionInView.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
It is shown either when committing with `w`, or when typing the skipHooks prefix
if there is one. This should hopefully make it clearer when the hooks are run
and when they are not.
Sometimes we populate the commit message panel with a pre-created commit
message. The two cases where this happens is:
- you type `w` to commit, in which case we put the skipHookPrefix in the subject
- you have a commitPrefix pattern, in which case we match it against the branch
name and populate the subject with the replacement string if it matches
In either case, if you have a preserved commit message, we use that.
Now, when you use either of these and then cancel, we preserve that initial,
unchanged message and reuse it the next time you commit. This has two problems:
it strips spaces, which is a problem for the commitPrefix patterns, which often
end with a space. And also, when you change your config to experiment with
commitPrefix patterns, the change seemingly doesn't take effect, which can be
very confusing.
To fix both of these problems, only preserve the commit message when it is not
identical to the initial message.
This is how we do it for confirmation with suggestions too, so be consistent. It
will make things easier later in this branch if we only have one context per
"panel" on the stack, even if the panel consists of two views.
Concretely this means:
- only push the message context onto the stack when opening the panel (this
requires making the description view visible manually; we do the same for
suggestions)
- when switching between message and description, use ReplaceContext rather than
PushContext
Previously we would hide it if no onSwitchToEditor function was set; that was
from a time when <c-o> was bound directly to the switch-to-editor command. Now
it is bound to showing a menu, and that menu is always available even if no
onSwitchToEditor function is set. (We rather need to disable the switch to
editor item _within_ that menu, see next commit.)
Only do this when an onSwitchToEditor function is actually provided. For the
"Move patch into new commit" command we don't, because it isn't totally
straightforward in that case.
This is useful for when you begin to type the message in lazygit's commit panel,
and then realize that you'd rather use your editor's more powerful editing
capabilities. Pressing <c-o> will take you right there.
Previously we used a single-line prompt for a tag annotation. Now we're using the commit message
prompt.
I've had to update other uses of that prompt to allow the summary and description labels to
be passed in
When we use the one panel for the entire commit message, its tricky to have a keybinding both for adding a newline and submitting.
By having two panels: one for the summary line and one for the description, we allow for 'enter' to submit the message when done from the summary panel,
and 'enter' to add a newline when done from the description panel. Alt-enter, for those who can use that key combo, also works for submitting the message
from the description panel. For those who can't use that key combo, and don't want to remap the keybinding, they can hit tab to go back to the summary panel
and then 'enter' to submit the message.
We have some awkwardness in that both contexts (i.e. panels) need to appear and disappear in tandem and we don't have a great way of handling that concept,
so we just push both contexts one after the other, and likewise remove both contexts when we escape.