Silently consume unrecognized or malformed escape sequences - #5738
#5738Merged
stefanhaller merged 3 commits intoJun 30, 2026
masterjesseduffield/lazygit:masterfrom
swallow-unknown-escape-sequencesjesseduffield/lazygit:swallow-unknown-escape-sequencesCopy head branch name to clipboard
Merged
Silently consume unrecognized or malformed escape sequences#5738stefanhaller merged 3 commits intomasterjesseduffield/lazygit:masterfrom swallow-unknown-escape-sequencesjesseduffield/lazygit:swallow-unknown-escape-sequencesCopy head branch name to clipboard
stefanhaller merged 3 commits into
masterjesseduffield/lazygit:masterfrom
swallow-unknown-escape-sequencesjesseduffield/lazygit:swallow-unknown-escape-sequencesCopy head branch name to clipboard
Conversation
The escape interpreter errors on anything outside the handful of sequences it understands (SGR, EL, OSC 8 hyperlinks), and view.go then renders the unparsed bytes as text cells. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
A text-mode escape interpreter can't do anything meaningful with cursor positioning, DEC private modes, or terminal resets — but it must still consume them, not print them as literal text. Before this change, any sequence outside SGR / EL / OSC-8 errored out of parseOne, and view.go rendered the unparsed bytes as visible cells. On Windows this would show up as junk at the start of main-panel output once we add PTY support using ConPTY, because ConPTY's session-init stream is full of such sequences. Three additions to the state machine: - stateEscape: a single byte in 0x30–0x7E after ESC (e.g. ESC c = RIS) is a complete Fs/Fp sequence per ECMA-48; consume and reset. - stateCSI: accept the DEC private-mode prefix bytes (<, =, >, ?), and accept a CSI final byte (0x40–0x7E) immediately after [ as the end of a zero-param sequence. - stateParams: accept any CSI final byte we don't implement as the end of the sequence rather than a parse error. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
After the previous commit, the escape interpreter still had five paths
that returned an error from parseOne, which view.go handles by rendering
whatever bytes it had accumulated as literal cells. Each of these is a
case where silently consuming the sequence is strictly better than
leaking garbage.
- ';' as the first CSI byte: '\x1b[;5H' is a valid sequence (row
defaults to 1) but we errored on the leading ';'.
- Intermediate bytes in CSI ('\x1b[0 q' = DECSCUSR): the sequence ends
in a final byte we don't implement, so consume and drop.
- Malformed SGR params (empty slot like '\x1b[1;;m'): if outputCSI
fails mid-parse, reset state instead of re-emitting the sequence.
- OSC 8 that isn't actually OSC 8 ('\x1b]8x...'): treat as an OSC we
don't understand and skip to its terminator rather than error-
resetting mid-sequence, which used to leave the rest of the OSC body
to be printed as text.
- The sanity-check overflow paths (too many params, param too long)
now switch to a 'discard until final byte' state rather than
returning the accumulated bytes.
A new stateCSIDiscard centralizes the 'consume bytes until the CSI
final' behavior used by both the intermediate-byte and overflow paths.
errCSITooLong and errOSCParseError are gone with their only callers.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
stefanhaller
enabled auto-merge
June 30, 2026 07:24
tmeijn
pushed a commit
to tmeijn/dotfiles
that referenced
this pull request
Jul 9, 2026
This MR contains the following updates: | Package | Update | Change | |---|---|---| | [jesseduffield/lazygit](https://github.com/jesseduffield/lazygit) | minor | `v0.62.2` → `v0.63.0` | MR created with the help of [el-capitano/tools/renovate-bot](https://gitlab.com/el-capitano/tools/renovate-bot). **Proposed changes to behavior should be submitted there as MRs.** --- ### Release Notes <details> <summary>jesseduffield/lazygit (jesseduffield/lazygit)</summary> ### [`v0.63.0`](https://github.com/jesseduffield/lazygit/releases/tag/v0.63.0) [Compare Source](jesseduffield/lazygit@v0.62.2...v0.63.0) <!-- Release notes generated using configuration in .github/release.yml at v0.63.0 --> #### What's Changed ##### Enhancements 🔥 - Add direnv support by [@​stefanhaller](https://github.com/stefanhaller) in [#​5660](jesseduffield/lazygit#5660) - Improve cycling through multiple pagers by [@​stefanhaller](https://github.com/stefanhaller) in [#​5678](jesseduffield/lazygit#5678) - Detect external repo changes via background polling by [@​stefanhaller](https://github.com/stefanhaller) in [#​5662](jesseduffield/lazygit#5662) - Make the side panels configurable by [@​stefanhaller](https://github.com/stefanhaller) in [#​5702](jesseduffield/lazygit#5702) - Add a global keybinding for editing the config file by [@​stefanhaller](https://github.com/stefanhaller) in [#​5728](jesseduffield/lazygit#5728) - Improve resolving non-textual and submodule merge conflicts by [@​stefanhaller](https://github.com/stefanhaller) in [#​5735](jesseduffield/lazygit#5735) - Auto-dismiss the continue-rebase prompt when it becomes stale by [@​stefanhaller](https://github.com/stefanhaller) in [#​5758](jesseduffield/lazygit#5758) - Support custom pagers and passphrase prompts on Windows by [@​stefanhaller](https://github.com/stefanhaller) in [#​5740](jesseduffield/lazygit#5740) - Make creating worktrees simpler and less error-prone by [@​stefanhaller](https://github.com/stefanhaller) in [#​5741](jesseduffield/lazygit#5741) - Improve deleting worktrees and their branches by [@​stefanhaller](https://github.com/stefanhaller) in [#​5748](jesseduffield/lazygit#5748) - Allow overriding the platform used for default keybindings by [@​stefanhaller](https://github.com/stefanhaller) in [#​5671](jesseduffield/lazygit#5671) - Add `gui.shrinkSidePanelsToContent` option by [@​stefanhaller](https://github.com/stefanhaller) in [#​5754](jesseduffield/lazygit#5754) - Show renamed files in the custom patch builder by [@​stefanhaller](https://github.com/stefanhaller) in [#​5759](jesseduffield/lazygit#5759) ##### Fixes 🔧 - Fix unstaging a submodule with dirty content by [@​stefanhaller](https://github.com/stefanhaller) in [#​5666](jesseduffield/lazygit#5666) - Fix coloring of wrapped delta lines by [@​stefanhaller](https://github.com/stefanhaller) in [#​5711](jesseduffield/lazygit#5711) - Fix Files Panel artefacts during rebase commands by [@​stefanhaller](https://github.com/stefanhaller) in [#​5661](jesseduffield/lazygit#5661) - Keep selected commits stable across refreshes by [@​stefanhaller](https://github.com/stefanhaller) in [#​5717](jesseduffield/lazygit#5717) - Fix quoting of shell commands on Windows by [@​stefanhaller](https://github.com/stefanhaller) in [#​5704](jesseduffield/lazygit#5704) - Silently consume unrecognized or malformed escape sequences by [@​stefanhaller](https://github.com/stefanhaller) in [#​5738](jesseduffield/lazygit#5738) - Don't include common ancestor when picking "both" for a conflict in diff3 style by [@​stefanhaller](https://github.com/stefanhaller) in [#​5747](jesseduffield/lazygit#5747) ##### Maintenance ⚙️ - Some fixes to our infrastructure by [@​stefanhaller](https://github.com/stefanhaller) in [#​5705](jesseduffield/lazygit#5705) - Restructure the `just` recipes for running integration tests by [@​stefanhaller](https://github.com/stefanhaller) in [#​5720](jesseduffield/lazygit#5720) - Fix flaky TestNewCmdTaskInstantStop test by [@​stefanhaller](https://github.com/stefanhaller) in [#​5743](jesseduffield/lazygit#5743) - Bump golang.org/x/sync from 0.20.0 to 0.21.0 by [@​dependabot](https://github.com/dependabot)\[bot] in [#​5684](jesseduffield/lazygit#5684) - Bump golang.org/x/sys from 0.45.0 to 0.46.0 by [@​dependabot](https://github.com/dependabot)\[bot] in [#​5685](jesseduffield/lazygit#5685) - Bump github.com/sahilm/fuzzy from 0.1.2 to 0.1.3 by [@​dependabot](https://github.com/dependabot)\[bot] in [#​5706](jesseduffield/lazygit#5706) - Bump actions/cache from 5 to 6 by [@​dependabot](https://github.com/dependabot)\[bot] in [#​5722](jesseduffield/lazygit#5722) - Bump actions/checkout from 6 to 7 by [@​dependabot](https://github.com/dependabot)\[bot] in [#​5723](jesseduffield/lazygit#5723) - Bump goreleaser/goreleaser-action from 7.2.2 to 7.2.3 by [@​dependabot](https://github.com/dependabot)\[bot] in [#​5745](jesseduffield/lazygit#5745) - Bump golangci/golangci-lint-action from 9.2.0 to 9.3.0 by [@​dependabot](https://github.com/dependabot)\[bot] in [#​5746](jesseduffield/lazygit#5746) - Bump golang.org/x/net from 0.47.0 to 0.55.0 by [@​dependabot](https://github.com/dependabot)\[bot] in [#​5752](jesseduffield/lazygit#5752) - Pin gofumpt version to 0.9.2 by [@​stefanhaller](https://github.com/stefanhaller) in [#​5753](jesseduffield/lazygit#5753) - Fix a few flaky tests by [@​stefanhaller](https://github.com/stefanhaller) in [#​5756](jesseduffield/lazygit#5756) ##### I18n 🌎 - Update translations from Crowdin by [@​stefanhaller](https://github.com/stefanhaller) in [#​5760](jesseduffield/lazygit#5760) ##### Performance Improvements 📊 - Prevent staging from becoming slower over time by [@​stefanhaller](https://github.com/stefanhaller) in [#​5712](jesseduffield/lazygit#5712) **Full Changelog**: <jesseduffield/lazygit@v0.62.2...v0.63.0> </details> --- ### Configuration 📅 **Schedule**: (UTC) - Branch creation - At any time (no schedule defined) - Automerge - At any time (no schedule defined) 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever MR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this MR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this MR, check this box --- This MR has been generated by [Mend Renovate](https://github.com/renovatebot/renovate). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yNTYuMCIsInVwZGF0ZWRJblZlciI6IjQzLjI1Ni4wIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJSZW5vdmF0ZSBCb3QiLCJhdXRvbWF0aW9uOmJvdC1hdXRob3JlZCIsImRlcGVuZGVuY3ktdHlwZTo6bWlub3IiXX0=-->
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Lazygit only recognizes a handful of escape sequences (mainly for colors, erasing to the end of the line, and OSC-8 hyperlinks). It would render all other ones as literal text in the UI, which doesn't make sense. This wasn't a problem so far because other sequences tend not to occur in pager output, but we are going to add ConPTY support for Windows in a later PR, and ConPTY does emit a lot of those escape sequences, which would then show up as junk in the UI.
While we're at it, also swallow malformed escape sequences instead of printing them verbatim.