Commit graph

62 commits

Author SHA1 Message Date
Stefan Haller 1fb5f87d05 Lay out the filter row of a menu that filters as you type
The row is reserved for as long as such a menu is open, even while it is
still hidden, so that it can appear without moving the menu. That costs
two rows of the popup, which is why the screen has to be a little taller
before a menu is worth showing at all.

The prompt in front of the input field is dropped when the row gets too
narrow to type in, and the keybindings menu says what '@' does when it
still fits.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-31 20:41:22 +02:00
Stefan Haller 435e02efa8 Remove the now-dead PopupMutex
PopupMutex guarded CurrentPopupOpts against a popup being created on a
worker goroutine while the UI thread deactivated it, or reset it on a
repo switch. Now that popup and menu creation is bounced onto the UI
thread, every access to CurrentPopupOpts — create, deactivate, and the
reset-on-switch (which already runs on the UI thread) — happens on the
one goroutine, so the mutex protects nothing.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-17 12:35:54 +02:00
Stefan Haller da065b5b63 Add comments
I got confused when I investigated the bug that was fixed in the previous
commit, so hopefully these will be helpful for the next person reading this
code.
2026-03-08 17:24:26 +01:00
Stefan Haller bcfb4e11c0 Fix off-by-one error when calculating popup panel dimensions
The symptom of the bug was that confirmation panels with wrapped text were one
character too wide, which could sometimes result in them being one line too
heigh. One concrete example is the "Discard file changes" confirmation that
appears when pressing `d` in the commit files panel.

I got very confused when investigating this bug, and the reason is that
getPopupPanelDimensionsAux took two parameters panelWidth and panelHeight, but
the second was actually contentHeight. Rename it to contentHeight, and change
the first one to also be the content width rather than the panel width. This is
easier for clients, and less confusing.
2026-03-08 17:24:26 +01:00
Stefan Haller 1ede4e6eb9 Limit popup panel widths to a maximum width
On very large screens they would get ridiculously wide.

The limits we chose here are a little arbitrary:
- 80 for confirmations and prompts
- 90 for menus
- auto-wrap width plus 25 for the commit message editor (or 100 if auto-wrap is
  off)
2026-01-28 09:02:27 +01:00
Stefan Haller fec7e9ce61 Bump gocui (and tcell)
and adapt lazygit's client code accordingly.
2025-12-23 16:49:16 +01:00
Stefan Haller 7c126cd2fc Strip leading/trailing whitespace from prompt input
This doesn't really solve a pressing problem, because I guess it's unlikely that
users add spaces at the beginning or end of what they type into a prompt; but it
could happen, and in this case we almost always want to strip it. Just adding
this here for completeness while I was working on this code.

The only exception is the input prompt of custom commands, because who knows
what users want to use that input for in their custom command.
2025-11-15 15:38:24 +01:00
Stefan Haller b3435bd59c Add AllowEmptyInput flag to PromptOpts
Most of our prompts don't (shouldn't) allow empty input, but most callers didn't
check, and would run into cryptic errors when the user pressed enter at an empty
prompt (e.g. when creating a new branch). Now we simply don't allow hitting
enter in this case, and show an error toast instead.

This behavior is opt-out, because there are a few cases where empty input is
supported (e.g. creating a stash).
2025-11-15 15:36:43 +01:00
Stefan Haller 48330141bd Cleanup: put the IsPasting logic in the right place
Previously it was used both for the Confirm handler and the Cancel handler, as
well as for the Confirm handler of confirmation popups (not prompts). There was
no other way to do it given how wrappedConfirmationFunction was shared between
all these; but now there is. The logic is really only needed for the Confirm
handler of prompts.

This doesn't fix anything, it just makes things clearer.
2025-11-15 14:13:24 +01:00
Stefan Haller 8d8cf42786 Refactor: extract body of wrappedConfirmationFunction into a helper function
And call this new helper function from both wrappedConfirmationFunction and
wrappedPromptConfirmationFunction; this gives us more flexibility to do
different things in each of those.
2025-11-15 14:07:36 +01:00
phanium d88f95275f Modernize all codes
go run golang.org/x/tools/gopls/internal/analysis/modernize/cmd/modernize@latest -fix -test ./...
2025-11-15 10:46:23 +01:00
Stefan Haller fbaea583a5 When pasting multi-line text into a prompt, don't treat the line feeds as "confirm"
This is likely to do bad things; for example, if the prompt is the shell command
prompt, then we would run into what looks like a deadlock bug in tcell. In other
cases, the characters in the following lines might be treated as random commands
after the prompt is confirmed.
2025-10-14 12:10:51 +02:00
Stefan Haller 5a630aeda1 Refactor: add a separate Prompt view
So far, confirmations and prompts were handled by the same view, context, and
controller, with a bunch of conditional code based on whether the view is
editable. This was more or less ok so far, since it does save a little bit of
code duplication; however, now we need separate views, because we don't have
dynamic keybindings, but we want to map "confirm" to different keys in
confirmations (the "universal.confirm" user config) and prompts (hard-coded to
enter, because it doesn't make sense to customize it there).

It also allows us to get rid of the conditional code, which is a nice benefit;
and the code duplication is actually not *that* bad.
2025-09-05 10:42:03 +02:00
Stefan Haller da7121fa87 Don't append "Disabled: " to menu tooltip if disabled reason is empty
In some cases we set a disabled reason but leave the text empty, so that we
don't get an error toast when the item is invoked. In such a case it looks
awkward if there is a tooltip showing "Disabled: " with no following text.
2025-08-14 17:59:38 +02:00
Stefan Haller 09e2bfaf99 Trim trailing newlines when showing confirmations
When showing a confirmation whose text ended with a line feed, we would make the
popup panel one line less tall than it needs to be, so it would show a scroll
bar. One example where this occurred is the very first popup that users ever see
(the "seriously you rock" message for new users); that's a pretty bad first
impression.

This happens because our code to suppress trailing newlines in views doesn't
work for styled text, and the text in confirmations is bold. This code checks if
the last character of the text is a line feed, and in this case it isn't; the
escape sequence for turning bold off comes after it.

We should really fix this by improving that mechanism, but this would require
some tricky logic, so as a quick fix, trim trailing (and leading) linefeeds from
the text that we display in a confirmation, before making it bold.
2025-08-08 20:37:44 +02:00
Stefan Haller b3215a750c Cleanup: get rid of the variadic parameter of ContextMgr.Push
Apparently this was an attempt at working around go's lack of default arguments,
but it's very unidiomatic and a bit confusing. Make it a normal parameter
instead, so all clients have to pass it explicitly.
2025-04-08 16:08:25 +02:00
Stefan Haller e5137b86cf Add a tabWidth parameter to WrapViewLinesToWidth to match gocui 2025-02-20 09:13:56 +01:00
Stefan Haller 20d0b4316d Only avoid the blank line at end of view if view is not editable
For editable views it is important to actually show the blank line so that we
can put the cursor there for typing.

This fixes problems with adding blank lines at the end of longer commit
messages.
2025-01-20 17:52:53 +01:00
Stefan Haller b7444b9a49 Return arrays with line indices from WrapViewLinesToWidth
This makes it easy to convert an original line index to a wrapped line index, or
vice versa.
2024-12-23 12:24:09 +01:00
Stefan Haller 1f2cb35cc9 Refactor: move wrapMessageToWidth to utils/lines.go
to make it more generally usable by clients other than ConfirmationHelper, which
we will do later in this branch. Rename it to WrapViewLinesToWidth while we're
at it.

Add tests; in particular, add a sanity check that we wrap lines the same way as
gocui does. The tests that are added here are the same ones as in gocui for its
lineWrap function, but we'll extend them a bit in later commits in this branch.
2024-12-23 12:24:09 +01:00
Stefan Haller 3610f13418 Fix several bugs in wrapMessageToWidth
This corresponds to the following fixes in gocui's lineWrap function:
- https://github.com/jesseduffield/gocui/pull/67/commits/86cf561ef493
- https://github.com/jesseduffield/gocui/pull/67/commits/24746d5cd6ee
- https://github.com/jesseduffield/gocui/pull/67/commits/4b97941c4ec6
2024-12-23 12:24:09 +01:00
Stefan Haller f6f2a52dee Bump gocui and adapt lazygit code
Original commit message of the gocui change:

This fixes View.Size, Width and Height to be the correct (outer) size of a view
including its frame, and InnerSize/InnerWidth/InnerHeight to be the usable
client area exluding the frame. Previously, Size was actually the InnerSize (and
a lot of client code used it as such, so these need to be changed to InnerSize).
InnerSize, on the other hand, was *one* less than Size (not two, as you would
have expected), and in many cases this was made up for at call sites by adding 1
(e.g. in calcRealScrollbarStartEnd, parseInput, and many other places in the
lazygit code).

There are still some weird things left that I didn't address here:
- a view's lower-right coordinates (x1/y1) are one less than you would expect.
  For example, a view with a 2x2 client area like this:
    ╭──╮
    │ab│
    │cd│
    ╰──╯
  in the top-left corner of the screen (x0 and y0 both zero) has x1/xy at 3, not
  4 as would be more natural.
- a view without a frame has its coordinates extended by 1 on all sides; to
  illustrate, the same 2x2 view as before but without a frame, sitting in the
  top-left corder of the screen, has coordinates x0=-1, y0=-1, x1=2, y1=2. This
  is highly confusing and unexpected.

I left these as they are because they would be even more of a breaking change,
and also because they don't have quite as much of an impact on general app code.
2024-12-01 10:40:08 +01:00
Stefan Haller 825f5c0a91 Use AutoRenderHyperLinks in confirmation view
This allows us to get rid of the underlineLinks function.
2024-09-28 12:04:51 +02:00
Stefan Haller b15a1c7ae7 Remove return value of CreatePopupPanel 2024-09-06 08:45:48 +02:00
Stefan Haller 371998e635 Remove return value of IContextMgr.Push/Pop et. al. 2024-09-06 08:45:48 +02:00
Stefan Haller 8302575078 Remove return value of Focus-related functions 2024-09-06 08:45:48 +02:00
Stefan Haller b91beb68e1 Remove return value of HandleRender 2024-09-06 08:45:48 +02:00
Stefan Haller 5659f1f3e9 Bump gocui
And adapt client code.
2024-09-06 08:45:48 +02:00
Yaroslav Halchenko 4bbfe7b3cc [DATALAD RUNCMD] run codespell throughout fixing typos automagically
=== Do not change lines below ===
{
 "chain": [],
 "cmd": "codespell -w",
 "exit": 0,
 "extra_inputs": [],
 "inputs": [],
 "outputs": [],
 "pwd": "."
}
^^^ Do not change lines above ^^^

Signed-off-by: Yaroslav Halchenko <debian@onerussian.com>
2024-08-27 18:03:00 +02:00
Stefan Haller a709caf138 Remove error return value from functions that always return nil 2024-08-27 10:33:06 +02:00
Stefan Haller 61b59837bb Use our new hyperlink support in confirmations 2024-08-24 10:36:01 +02:00
Stefan Haller f98b57aa5e Change direct access to Common.UserConfig to a getter
This will allow us to turn the field into an atomic.Value for safe concurrent
access.
2024-08-18 10:24:52 +02:00
Stefan Haller f30387e7f5 Replace CurrentPopupContexts() with Context().CurrentPopup() 2024-08-17 11:14:51 +02:00
Stefan Haller 7ed94c0410 Replace CurrentContext() with Context().Current() 2024-08-17 11:14:51 +02:00
Stefan Haller 98335361fd Replace PopContext() with Context().Pop() 2024-08-17 11:14:50 +02:00
Stefan Haller bd36b8a95e Replace PushContext() with Context().Push() 2024-08-17 11:14:50 +02:00
Stefan Haller 4b6479b25f Stagger popup panels
When opening a popup panel on top of another one, offset the new one a little
bit down and to the right.
2024-06-28 08:14:07 +02:00
Stefan Haller 1ab1fb3599 Resize all open popup panels in layout, not just the topmost one
Probably not the most import feature in the world, but when resizing the
terminal window while multiple popup panels were open at the same time, we would
only resize the topmost one.

The main reason for changing this is because it makes the next commit easier to
implement.
2024-06-28 08:14:07 +02:00
Stefan Haller 1d502d3245 Remove return value from ResizeCurrentPopupPanel
It always returned nil, so there's no point in returning an error.
2024-06-28 08:14:07 +02:00
Stefan Haller bb01648521 Remove redundant calls to resize editable panels at creating time
The only purpose of this was to scroll the editable text correctly (see
https://github.com/jesseduffield/lazygit/pull/2146); now that gocui takes care
of that, we no longer need to do this.
2024-06-28 08:14:07 +02:00
Stefan Haller b795d91fa8 Remove redundant resizeConfirmationPanel() call at panel creating time
We resize the panel in layout, so there's no need to do that after creation.
2024-06-27 10:18:12 +02:00
Stefan Haller ccc620e5fc Remove duplicate function
ResizeConfirmationPanel and resizeConfirmationPanel were identical, get rid of
one of them.
2024-06-27 10:14:00 +02:00
Stefan Haller 34d7afc0e9 Remove unused functions 2024-06-27 10:14:00 +02:00
Stefan Haller c3d1a79a89 Fix clicking outside of the commit description panel or suggestions panel
We forgot to handle the "suggestions" and "commitDescription" view names.

Instead of listing all the names of views that can appear in popups though,
let's use the context kind for this, which feels more robust.

This is a change in behavior: previously, clicking outside of the search or
filter prompt would close the prompt, now it no longer does (because search has
a persistent popup kind, but it wasn't listed in the list of view names before).
2024-06-27 09:36:50 +02:00
Stefan Haller 7e92dbfd3d Add menu prompt
This makes it possible to add a prompt to a menu. It will be shown above the
menu items, separated from them by a blank line.
2024-06-23 12:33:16 +02:00
Stefan Haller dbc21af3b1 Extract function wrapMessageToWidth
This steals even more code from `gocui.lineWrap`.

We'll make use of this in the next commit.
2024-06-23 12:33:15 +02:00
Stefan Haller 2d0c96466a Fix calculation of tooltip height
For tooltips that are just one or two characters longer than the available
width, the last word would be cut off. On my screen this happened for the
tooltip for the fixup command.
2024-05-26 19:26:27 +02:00
Stefan Haller 010b0ae923 Show delete/edit keybindings in suggestions subtitle if available 2024-05-19 07:06:18 +02:00
Stefan Haller a7041cf492 Allow editing a custom command from the suggestions list by pressing 'e'
For custom commands it is useful to select an earlier command and have it copied
to the prompt for further editing. This can be done by hitting 'e' now.

For other types of suggestion panels we don't enable this behavior, as you can't
create arbitrary new items there that don't already exist as a suggestion.
2024-05-19 07:06:18 +02:00
Stefan Haller da3e0f7147 Support deleting items from the custom commands history
In the custom commands panel you can now tab to the suggestions and hit 'd' to
delete items from there. Useful if you mistyped a command and don't want it to
appear in your history any more.
2024-05-19 07:06:18 +02:00