Commit Graph
8619 Commits
Author SHA1 Message Date
Stefan HallerandClaude Opus 5.5 0855e981cf Remove the unused Timestamp of replayed input events
Every caller passes 0, and nothing reads it. The next commit makes
replayed mouse events carry the time they were created; a second, unused
timestamp next to it would only confuse.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-14 14:14:08 +02:00
Stefan HallerandClaude Opus 5.5 9e76ed7c03 Send the two clicks of a double click in tests without waiting between
The test enter_and_double_click_focus_file_diff fails occasionally on
CI. After it double-clicks a file, the files panel still has the focus
instead of the main view.

The test double-clicks by calling Click twice. Click waits for lazygit
to become idle after the press and again after the release, and the
first wait includes the git diff that the click starts for the main
view. gocui only counts the second click as a double click if it handles
it within 500ms of the first one. On a busy CI runner, where many
integration tests run in parallel, the waits can take longer than that,
and the second click counts as a single click.

Add DoubleClick to the test driver. It replays both clicks without
waiting in between, as a terminal reports a double click, and waits for
lazygit to become idle only after the second one.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-14 14:12:19 +02:00
Stefan Haller 883c893911 Improve performance with very long diffs (#6121)
Parsing long diffs was very slow, especially for commits that add or
remove files with hundreds of thousands of lines. This caused very
noticeable lags for certain operations such as scrolling down in such a
diff using `>`, or bringing up the `<ctrl-g>` files menu.
2026-10-14 09:48:15 +02:00
Stefan HallerandClaude Opus 5.5 dc4fee296c Leave out the text of the rows of a rendering that states its lines
Under a diff renderer that states which diff line each row shows, such
as delta, the queries about the lines of the main view read the rows by
those records alone. Still, they took the text of every row as well,
and for a diff of 300,000 lines this was most of the time each of them
took. Moving the selection by change block runs two of them for every
key press.

Take the records of the rows first, and their text only if no row
states a diff line.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-14 08:41:50 +02:00
Stefan HallerandClaude Opus 5.5 3f64902a11 Collect the records of a line when the line has been written
Under a diff renderer that states which diff line each row shows, such
as delta, moving the selection by change block in a diff of 300,000
lines lags noticeably. One reason is that the queries about the lines
of the main view collect the records of every row from the row's
cells, going through every cell of every row. Under delta, a row has
about 130 cells.

Collect the records of a line once, when the write cursor moves on to
the next line, and take them from there. A line that is written to
again is read from its cells until it has been finished again.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-14 08:41:50 +02:00
Stefan HallerandClaude Opus 5.5 cbfa22cfbe Make the path of a diff's lines absolute once per file
Every query about the lines of the main view, such as moving the
selection to the next change block, finds out which line of which file
each row shows. For every row, this joined the path that the diff
states with the path of the worktree. In a diff of 300,000 lines, this
took more than half of the time of the query.

The lines of a diff come file by file, so remember the last path that
was made absolute and reuse it while the path stays the same. Do the
same in the other places that go through every line of a diff. A query
over that diff now takes about 27 milliseconds instead of 63.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-14 08:41:50 +02:00
Stefan HallerandClaude Opus 5.5 185f147db2 Number the lines of a patch in one pass when indexing its change lines
Several actions on the selected lines of a diff look up those lines in
the diff of their file by their line numbers: staging, unstaging and
discarding them, editing the hunk they are in, and adding them to a
custom patch. Showing which lines of a diff are in the custom patch
does the same lookup the other way round. For this, the change lines of
the file's diff are indexed by their line numbers.

The index asked the patch for the number of each change line separately,
and each of these calls counts the lines of the hunk before the line. So
for a new file of 100,000 lines, building the index took 2 seconds.
Number all lines of the patch in one pass instead. Building the index
for that file now takes 4 milliseconds.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-14 08:41:50 +02:00
Stefan HallerandClaude Opus 5.5 80dff3c2b9 Number the lines of a diff in one pass when parsing it
With no diff renderer configured, opening the jump-to-file menu for the
diff of a commit that adds or deletes a file of 100,000 lines takes
more than 20 seconds, and so does picking a file from it. In such a
diff, moving the selection by change block takes as long for each key
press. All this time the UI is frozen.

To find out which line of which file each row of the main view shows,
lazygit parses the view's content as a diff. For every line of a file's
diff it asks the parsed patch for the line's number in the new and in
the old file, and each of these calls counts the lines of the hunk
before it. So parsing takes time quadratic in the length of a hunk, and
the diff of a new or deleted file is a single hunk. For a diff of
200,000 lines, one parse took about 10 seconds, and opening the menu
parses it twice. A diff renderer that states which line each row shows,
such as delta, doesn't go through this parse.

Number all lines of the patch in one pass instead. Parsing that diff
now takes about 40 milliseconds.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-14 08:41:50 +02:00
Stefan Haller ae6639a003 Fix diff rendering after scrolling far down (#6120)
Fix a regression introduced in v0.65.0: if the main view is scrolled
more than about 5000 lines down a diff and another commit with a diff of
more than 5000 lines is selected, the main view kept showing the
previous diff. Switching between the two long commits then didn't update
the main view at all. Only selecting a shorter commit would get this
unstuck.

Along the way, fix another smaller bug and a performance problem; see
commit messages for details.
2026-10-14 08:38:40 +02:00
Stefan HallerandClaude Opus 5.5 f6892ffc94 Read the lines above the view only for a render that stays where it is
A render first reads enough lines to fill the view, plus the lines
above the view, so that a re-render of the diff the user is scrolled
into fills the view where it is. But a render of another diff, such as
the diff of another commit, is shown from the top. So if the view is
scrolled far down a long diff, the next diff only shows up once the
lines above the view have been read as well. For a diff of a few
hundred thousand lines this takes a noticeable while, especially with a
diff renderer such as delta.

ViewBufferManager decides whether a render keeps the view where it is
(see newContentPending). So let linesToReadFromCmdTask count the lines
from the top of the view and pass on how many lines are above it, and
let the task add those only if it keeps the view where it is.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-13 16:31:22 +02:00
Stefan HallerandClaude Opus 5.5 be300454b6 Name the fields of LinesToRead in the task tests
The request for the first lines of a render is going to say how many
lines there are above the view, and the unnamed fields of these
literals would all need another value for it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-13 16:28:17 +02:00
Stefan HallerandClaude Opus 5.5 f91d20f67d Don't let a render stop reading before it has filled the view
If the main view is scrolled more than about 5000 lines down a diff and
another commit with a diff of more than 5000 lines is selected, the
main view keeps showing the previous diff.

A render reads its command's output into an off-screen buffer, and
shows it only once it has read enough lines to fill the view or has
reached the end of the output. It then reads on as far as an accurate
scrollbar needs, and waits for the user to scroll further. Both counts
include the lines above the view, so that a re-render of the diff the
user is scrolled into fills the view where it is. But the 5000-line cap
that is meant for the scrollbar applies to the lines above the view as
well. So if the view is scrolled further down than that, the render
stops reading before it has filled the view, and never shows anything.
The view also counts as loading until the next render starts, so the
layout doesn't keep it from scrolling past the end of the diff in the
meantime.

This has been a problem since 9e23111172 made renders read into an
off-screen buffer. Before that, the lines of a render that stopped early
showed up anyway.

Apply the cap to the lines for the scrollbar only. Also never ask for
fewer lines than fill the view. A view no more than four lines tall
needs fewer lines than that for its scrollbar, even at the top of a
diff.

A render of another diff shows it from the top, so it doesn't need the
lines above the view at all. A later commit stops it from reading them.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-13 16:28:02 +02:00
Stefan HallerandClaude Opus 5.5 56b6c5af31 Stop at the end of the diff when jumping to a file from a panel
With gui.scrollPastBottom set to false, picking the last file of a long
diff from the jump-to-file menu of the commits panel scrolls that file
to the top of the view. This leaves blank space below the end of the
diff.

A jump in a pane that isn't focused puts the file at the top of the view
and leaves it to the layout to stop at the end of the diff. But the
layout doesn't do this while the view is loading. Picking an item from
the menu closes the menu first, and the commits panel starts a re-render
of the diff as it gets the focus back. So the view is loading when the
jump happens, and the layout corrects the position only in a later pass
after the re-render has finished. For a long diff the re-render never
finishes; a later commit fixes this. Clicking a file in the diffstat
doesn't close a menu, so it doesn't have the problem.

Stop the jump at the last screenful of the diff, as a jump in the
focused pane does. Like that one, it stops there whatever
gui.scrollPastBottom is set to.

The diff in click_a_file_in_a_diff_stat_that_comes_first fits on
screen, so the jump doesn't scroll it any more. Make it longer than the
view.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-13 16:26:38 +02:00
Stefan HallerandClaude Opus 5.5 d198ce56f1 Extract how far a jump can scroll its target to the top of the view
A jump in a pane that isn't focused is going to stop at the last
screenful of the diff as well.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-13 16:23:36 +02:00
Stefan HallerandClaude Opus 5.5 29942337f5 Add tests for renders that don't show after scrolling far down a diff
If the main view is scrolled more than about 5000 lines down a diff and
another commit is selected, the main view keeps showing the previous
diff, as long as the new one is longer than 5000 lines as well.

Similarly, if the jump-to-file menu of the commits panel is used to go
to the last file of such a diff, the file's header ends up at the top
of the view with blank space below the end of the diff. This happens
even with gui.scrollPastBottom set to false.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-13 16:18:52 +02:00
Stefan Haller b741725a24 Update docs and schema for release (#6114) v0.66.1 2026-10-11 11:21:51 +02:00
Stefan Haller 72cf6049f1 Update docs and schema for release 2026-10-11 11:18:45 +02:00
Stefan Haller d58920bd57 Edit random tips (#6113) 2026-10-11 11:17:11 +02:00
Stefan Haller 9b353e9dcb Add tip about alt-clicking, which is not very discoverable 2026-10-11 11:12:03 +02:00
Stefan Haller aab6b94a15 Remove obsolete tip 2026-10-11 11:11:45 +02:00
Stefan Haller d6c5e513aa Don't log the diff renderer probe in the command log (#6112)
If a diff renderer is configured, its command shows up in the command
log once after startup, although the user didn't do anything. This is
the probe that asks the renderer whether it emits OSC 1717 metadata. It
changes nothing, so like other read-only commands it shouldn't be
logged.
2026-10-11 11:05:16 +02:00
Stefan Haller aa3da6a20f Keep the diff renderer probe out of the command log
If a diff renderer is configured, its command shows up in the command
log once after startup, although the user didn't do anything. This is
the probe that asks the renderer whether it emits OSC 1717 metadata. It
changes nothing, so like other read-only commands it shouldn't be
logged.
2026-10-11 10:10:41 +02:00
Stefan Haller fc570a6a31 Show the diff view's narrow selection bar on the right edge too (#6105)
This is an improvement for users who use a side-by-side diff renderer on
a very large screen; in this scenario it was hard to see which hunk on
the right side was selected.

See
https://github.com/jesseduffield/lazygit/issues/6098#issuecomment-6064528142.
2026-10-11 09:52:50 +02:00
Stefan Haller 96f93ec79d Show the diff view's narrow selection bar on the right edge too
This is an improvement for users who use a side-by-side diff renderer on
a very large screen; in this scenario it was hard to see which hunk on
the right side was selected.
2026-10-10 14:20:04 +02:00
Stefan Haller a5bf29e092 Open files of a branch's diff from the worktree that has it checked out (#6104)
If you enter a branch in the branches panel and press `e` on a line of a
commit's diff, or on a file in the commit files panel entered from
there, lazygit opens the file in the current worktree. If another
worktree has the branch checked out, this is the wrong copy of the file.
The current worktree may have it in a different state, or not have it at
all. Clicking a lazygit-edit:// hyperlink of a diff renderer in such a
diff has the same problem.

Fix this by opening the file from the worktree that has the branch
checked out instead, and carry the line number forward to the file as
that worktree has it. If no other worktree has the branch checked out,
the file is still opened from the current worktree.

Also, fix the same problem for the `o` command, and for the "Absolute
path" entry in the "Copy to clipboard" menu.

Finally, fix a long-standing annoyance when trying to open a file that
has since been deleted or renamed; in that case, most editors would
create it as a new, empty file, which is not useful. Show an error
message in that case instead.

Fixes #6102.
2026-10-10 14:09:07 +02:00
Stefan HallerandClaude Opus 5.5 3742ac6066 Show an error when editing a file of a diff that doesn't exist
If you press `e` on a file of a commit, and a later commit deleted that
file, the editor is opened on a path that doesn't exist. Most editors
then create it as a new, empty file. This is confusing. The same
happens with `o`, and with any other file that the worktree it is
opened from doesn't have. An example is a file that is added in a branch
that isn't checked out anywhere, since it is opened from the current
worktree.

Show an error instead of opening the editor. For a range selection in
the commit files panel, show it only if none of the selected files
exist. Otherwise open the existing ones and leave out the others
silently; an error shown only after returning from the editor would
come too late to be useful.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-10 13:58:05 +02:00
Stefan HallerandClaude Opus 5.5 6cd6e4532d Copy the absolute path of a branch's file from the worktree that has it
If the commit files panel was entered from a branch that another
worktree has checked out, "Copy absolute path" in its copy menu gives
the file's path in the current worktree. Make it give the path in the
worktree that has the branch checked out. This is the file that `e` and
`o` open, and the one users most likely want the path of.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-10 13:58:05 +02:00
Stefan HallerandClaude Opus 5.5 690509a8cc Open files with o from the worktree that has the branch checked out
Do the same for `o` in the commit files panel as the previous commits
do for `e`. If the panel was entered from a branch that another worktree
has checked out, open the file from that worktree.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-10 13:58:05 +02:00
Stefan HallerandClaude Opus 5.5 6c4409b712 Add a test for opening a file of a branch checked out in another worktree
Pressing `o` on a file in the commit files panel has the same problem as
`e` had before the previous commit. If the commit is of a branch that
another worktree has checked out, the file is still opened from the
current worktree. The absolute path in the panel's copy menu points into
the current worktree too.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-10 13:58:05 +02:00
Stefan HallerandClaude Opus 5.5 51e91fbb85 Open files of a branch's diff from the worktree that has it checked out
If you enter a branch in the branches panel and press `e` on a line of
a commit's diff, or on a file in the commit files panel entered from
there, lazygit opens the file in the current worktree. If another
worktree has the branch checked out, this is the wrong copy of the
file. The current worktree may have it in a different state, or not
have it at all. Clicking a lazygit-edit:// hyperlink of a diff renderer
in such a diff has the same problem.

Open the file from the worktree that has the branch checked out
instead, and carry the line number forward to the file as that worktree
has it.

If no other worktree has the branch checked out, the file is still
opened from the current worktree.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-10 13:58:04 +02:00
Stefan HallerandClaude Opus 5.5 f9a3dc7be7 Add a test for editing a file of a branch checked out in another worktree
If you enter a branch in the branches panel, and that branch is checked
out in another worktree, pressing `e` on a line of a commit's diff opens
the file in the current worktree. The same happens for `e` on a file in
the commit files panel entered from there. The current worktree may not
have the file at all, as in this test, or have it in a different state
than the branch has it. The line number is carried forward to the
current worktree's version of the file too, and this gives line 0 here.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-10 13:58:04 +02:00
Stefan HallerandClaude Opus 5.5 f343c8fd50 Add a way to run GetDiff in another worktree
The next commit carries a line of a diff forward to the file as another
worktree has it, and needs to diff against that worktree's working copy
for this.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-10 13:58:04 +02:00
Stefan HallerandClaude Opus 5.5 64fd7d8686 Route the editing of a diff's files through DiffHelper
Three places open a file of a diff in the editor: `e` and alt-click in
the main view, the lazygit-edit:// hyperlinks of a diff renderer, and
`e` in the commit files panel. The first two also each carry a line of
the diff forward to the file's current line before opening it.

Give them one pair of methods to call. The next commit changes where
these files are opened from, and can then do so in one place.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-10 13:58:04 +02:00
Stefan Haller 283bd590f3 Allow scrolling the diff view horizontally when gui.wrapLinesInDiffView is off (#6109)
If gui.wrapLinesInDiffView is false, long lines of a diff run off the
right edge of the main view, and there was no way to see the rest of
them. This made it hard to see what has changed in such a line. The old
staging and patch-building views scrolled sideways with `H` and `L`, but
the focused main view that replaced them had no binding for these keys.

Bind them in the focused main view, as in the side panels. Leaving the
view scrolls it back to the left edge, as it did for the staging view.

In addition, when jumping to the next search result, and it is past the
right edge, scroll sideways to show it. This happens both in the new
main view when `gui.wrapLinesInDiffView` is off, but also in side
panels, so it is an improvement over pre-0.66 versions there.
2026-10-10 13:57:45 +02:00
Stefan HallerandClaude Opus 5.5 dd68e5644a Scroll a view sideways to show the search match it goes to
If a view doesn't wrap, a search match can be past its right edge, or
left of it once the view is scrolled sideways. Going to such a match
with /, n or N only scrolls the view vertically, so the match stays out
of sight. This matters most for a diff with gui.wrapLinesInDiffView set
to false, where a change is often at the end of a long line.

Scroll the view sideways if the match isn't on screen. Put the match a
third of the way across the view, so that some of the text before it
shows too. If the view can show the match without scrolling, go back to
the left edge instead. This applies to every view that doesn't wrap,
including the side panels.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-10 13:44:43 +02:00
Stefan HallerandClaude Opus 5.5 75083c179e Scroll the focused diff sideways with H and L
If gui.wrapLinesInDiffView is false, long lines of a diff run off the
right edge of the main view, and there is no way to see the rest of
them. This makes it hard to see what has changed in such a line. The
old staging and patch-building views scrolled sideways with H and L, but
the focused main view that replaced them has no binding for these keys.

Bind them in the focused main view, as in the side panels. Leaving the
view scrolls it back to the left edge, as it did for the staging view.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-10 13:44:43 +02:00
Stefan HallerandClaude Opus 5.5 2abe4848f3 Scroll back to the left edge when jumping to another file of a diff
Going to the next or previous file of a diff, or picking one from the
jump-to-file menu or the diffstat, brings that file to the top of the
view. The user goes there to read the file from its start, so scroll the
view back to the left edge as well. Jumps between the hunks of a diff
keep the horizontal scroll position, as moving the selection does.

Nothing scrolls the main view horizontally yet, so this changes nothing
on its own. It prepares for scrolling the focused main view sideways
with H and L.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-10 13:44:43 +02:00
Stefan HallerandClaude Opus 5.5 6da4f658d7 Don't leave a re-rendered diff scrolled further right than it reaches
The main view keeps its horizontal scroll position when a diff is
rendered again. If the new rendering is narrower, for example because
the only long line in it was just staged, the view can end up scrolled
past the end of every line and look empty. If one line still reaches
into the view, the view shows only a sliver of it, although the whole
diff would fit without scrolling.

Once a render has been read to the end, scroll the view back as far as
it takes to put the end of the widest line at the right edge. A long
diff that is read only in part is checked once the rest of it has been
read.

Nothing scrolls the main view horizontally yet, so this changes nothing
on its own. It prepares for scrolling the focused main view sideways
with H and L.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-10 13:44:43 +02:00
Stefan HallerandClaude Opus 5.5 4f678b7d0d Keep the horizontal scroll position when a diff is rendered again
Two places that position the main view after a re-render of the same
diff call SetOrigin(0, y), although they only mean to move the view
vertically. One is the restore after a change of the context size, of
whitespace handling or of the diff renderer. The other is the clamp for
content that ends above the scroll position, for example after staging a
large part of the diff. Use SetOriginY in both, so that they keep the
horizontal scroll position.

Nothing scrolls the main view horizontally yet, so this changes nothing
on its own. It prepares for scrolling the focused main view sideways
with H and L.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-10 13:44:43 +02:00
Stefan HallerandClaude Opus 5.5 abc16e904c Keep horizontally scrolled content out of the inclusion gutter
If a view that shows the inclusion gutter is scrolled horizontally, its
content is drawn over the gutter. The marker of a marked line is
overwritten, and the content starts the gutter's width too far to the
left. The draw loop skips the cells scrolled past the left edge only
until x reaches 0, but the content area starts at the gutter's width.

Nothing scrolls such a view horizontally yet. A later commit lets the
focused main view scroll sideways, and the gutter shows there while
building a custom patch.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-10 13:44:43 +02:00
Stefan Haller 99f92d00ef Fix search match highlighting when a custom patch is active (#6107)
Search matches beside the inclusion gutter were highlighted in the wrong
place, and hovering over or clicking a hyperlink there acted on the
wrong cell. The draw loop starts the content after the gutter, but the
code that maps a view column back to a column of the content only added
the horizontal origin and ignores the gutter.

Add a helper that does both, and use it for search highlights, hover and
clicks.
2026-10-10 13:44:39 +02:00
Stefan HallerandClaude Opus 5.5 42f7bf66a6 Remove the unused View.Line and View.Word
Nothing in lazygit calls View.Line or View.Word; they came with the
original gocui code and have never been used. They are also the only
callers of realPosition. That function ignores the inclusion gutter when
it maps a view position to the buffer. On top of that, Word uses the
returned column as an index into the line's cells, and this goes wrong
for wide characters.

Remove them, together with realPosition and the indexFunc helper. This
leaves contentX as the only code that maps a column of the view to a
column of the content.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-10 13:40:23 +02:00
Stefan HallerandClaude Opus 5.5 fda5abdfb3 Account for the inclusion gutter when mapping view columns to content
Search matches beside the inclusion gutter are highlighted in the wrong
place, and hovering over or clicking a hyperlink there acts on the wrong
cell. The draw loop starts the content after the gutter, but the code
that maps a view column back to a column of the content only adds the
horizontal origin and ignores the gutter.

Add a helper that does both, and use it for search highlights, hover
and clicks.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-10 13:40:23 +02:00
Stefan HallerandClaude Opus 5.5 07995e630b Add tests for search matches and hyperlinks beside the inclusion gutter
If the inclusion gutter is shown, as it is in the focused main view
while building a custom patch, search matches are highlighted two
columns to the left of where they are. Hovering over a hyperlink
underlines the wrong columns, and a click acts on the cell two columns
to the right of the one that was clicked.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-10 13:40:23 +02:00
Stefan Haller 8771f1fc5d Fix double-width characters in the last column drawing over the view's frame (#6106)
A double-width character that starts in the last column of a view is
drawn over the view's frame. One that is scrolled halfway out to the
left is skipped, and the column it reaches into isn't drawn at all. The
draw loop clips cells against the edges of the view as if every cell
were one column wide.

A terminal can't show half of a double-width character. So draw a blank
in the column that is on screen, in the character's colors, and let the
selection highlight cover that column like any other.
2026-10-10 13:40:20 +02:00
Stefan HallerandClaude Opus 5.5 e314ad884a Draw a blank for a double-width character cut off at the edge of a view
A double-width character that starts in the last column of a view is
drawn over the view's frame. One that is scrolled halfway out to the
left is skipped, and the column it reaches into isn't drawn at all. The
draw loop clips cells against the edges of the view as if every cell
were one column wide.

A terminal can't show half of a double-width character. So draw a blank
in the column that is on screen, in the character's colors, and let the
selection highlight cover that column like any other.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-10 13:35:25 +02:00
Stefan HallerandClaude Opus 5.5 bab90de2fd Add tests for double-width characters at the edges of a view
If a double-width character starts in the last column of a view that
doesn't wrap, its second half is drawn over the view's frame. If one is
scrolled halfway out to the left, the column it still reaches into isn't
drawn at all. This column then has neither the selection highlight nor
the line's background. Both happen in every view that doesn't wrap: the
side panels, and the main view with gui.wrapLinesInDiffView set to
false.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-10 13:35:25 +02:00
Stefan Haller 7fc43006c0 Show errors for unresolvable diff lines (#6100)
If lazygit can't work out what diff lines it is supposed to act on when
staging a hunk (for example because of bugs like the one in #6099, or
maybe because of a misbehaving OSC-1717 diff renderer), it used to do
nothing and silently ignore the error. Now it shows an error popup to
the user in such a case, so that they can report the bug more easily.
2026-10-10 13:07:29 +02:00
Stefan HallerandClaude Opus 5.5 2a3883f502 Show an error if the commit to discard lines from can't be found
Discarding lines from a commit's diff rewrites the commit with a
rebase. For this we look up the commit among the commits of the
current branch. If it isn't there, pressing the key does nothing. The
disabled reason only allows discarding in a diff of the commits panel,
so this shouldn't happen. If it does, the user should see it.

Show an error that names the commit instead.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-10 13:04:41 +02:00
Stefan HallerandClaude Opus 5.5 56e234e94c Show an error if the selected diff lines can't be found in the diff
When we stage, discard or edit lines of the working tree's diff, we
read the file's diff again and look for the selected lines in it. If
none of them are there, nothing happens. The same goes for adding
lines of a commit's diff to a custom patch, or taking lines out of
it. This can happen if the file changed since its diff was shown, or
if we read the line numbers out of the diff on screen wrongly.

Show an error that names the file instead. As with a file that can't
be found, don't act on any file if the lines of one are missing.

Unlike the file check, this one happens after a new custom patch has
been started. If the error leaves that patch without any lines, reset
it, as we do when the last line is taken out of a patch.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-10 13:04:41 +02:00