mirror of
https://github.com/jesseduffield/lazygit.git
synced 2026-09-10 07:36:27 -04:00
feat: add configurable terminal window title
Add a `gui.terminalTitle` config option (default: `lazygit::{{repoName}}`)
that sets the terminal window title via ANSI escape sequences through
gocui.Screen.SetTitle(). The title updates on startup and when switching
repos. Control characters are sanitized to prevent escape sequence
injection. Set to empty string to disable.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
c07f4d381b
commit
8730d58ba6
|
|
@ -358,6 +358,11 @@ gui:
|
|||
# is already active, go to next tab instead
|
||||
switchTabsWithPanelJumpKeys: false
|
||||
|
||||
# Format string for the terminal window title. Supports placeholders:
|
||||
# - {{repoName}}: Name of the current repository
|
||||
# Set to empty string to disable terminal title updates.
|
||||
terminalTitle: lazygit::{{repoName}}
|
||||
|
||||
# Config relating to git
|
||||
git:
|
||||
# Array of diff renderers. Each entry has the following format:
|
||||
|
|
|
|||
|
|
@ -222,6 +222,10 @@ type GuiConfig struct {
|
|||
SwitchToFilesAfterStashApply bool `yaml:"switchToFilesAfterStashApply"`
|
||||
// If true, when using the panel jump keys (default 1 through 5) and target panel is already active, go to next tab instead
|
||||
SwitchTabsWithPanelJumpKeys bool `yaml:"switchTabsWithPanelJumpKeys"`
|
||||
// Format string for the terminal window title. Supports placeholders:
|
||||
// - {{repoName}}: Name of the current repository
|
||||
// Set to empty string to disable terminal title updates.
|
||||
TerminalTitle string `yaml:"terminalTitle"`
|
||||
}
|
||||
|
||||
func (c *GuiConfig) UseFuzzySearch() bool {
|
||||
|
|
@ -934,6 +938,7 @@ func GetDefaultConfigForPlatform(platform string) *UserConfig {
|
|||
SwitchToFilesAfterStashPop: true,
|
||||
SwitchToFilesAfterStashApply: true,
|
||||
SwitchTabsWithPanelJumpKeys: false,
|
||||
TerminalTitle: "lazygit::{{repoName}}",
|
||||
},
|
||||
Git: GitConfig{
|
||||
Commit: CommitConfig{
|
||||
|
|
|
|||
|
|
@ -533,6 +533,8 @@ func (gui *Gui) onUserConfigLoaded() error {
|
|||
presentation.SetCustomBranches(userConfig.Gui.BranchColors, false)
|
||||
}
|
||||
|
||||
gui.updateTerminalTitle()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -1141,13 +1143,35 @@ func (gui *Gui) loadNewRepo() error {
|
|||
}
|
||||
refresh(options)
|
||||
|
||||
if err := gui.os.UpdateWindowTitle(); err != nil {
|
||||
return err
|
||||
}
|
||||
gui.updateTerminalTitle()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (gui *Gui) updateTerminalTitle() {
|
||||
titleFormat := gui.c.UserConfig().Gui.TerminalTitle
|
||||
if titleFormat == "" {
|
||||
return
|
||||
}
|
||||
|
||||
// gui.git may not be set yet during initial startup
|
||||
if gui.git == nil || gui.git.RepoPaths == nil {
|
||||
return
|
||||
}
|
||||
|
||||
repoName := gui.git.RepoPaths.RepoName()
|
||||
title := utils.ResolvePlaceholderString(titleFormat, map[string]string{
|
||||
"repoName": repoName,
|
||||
})
|
||||
|
||||
// Sanitize title by removing control characters that could break terminal behavior
|
||||
title = utils.SanitizeTerminalTitle(title)
|
||||
|
||||
if gocui.Screen != nil {
|
||||
gocui.Screen.SetTitle(title)
|
||||
}
|
||||
}
|
||||
|
||||
func (gui *Gui) showIntroPopupMessage() {
|
||||
gui.waitForIntro.Add(1)
|
||||
|
||||
|
|
|
|||
|
|
@ -31,3 +31,15 @@ func ResolvePlaceholderString(str string, arguments map[string]string) string {
|
|||
}
|
||||
return strings.NewReplacer(oldnews...).Replace(str)
|
||||
}
|
||||
|
||||
// SanitizeTerminalTitle removes control characters from a string intended
|
||||
// for use as a terminal title. Control characters (ASCII 0-31 and 127) could
|
||||
// break terminal behavior or be used for escape sequence injection.
|
||||
func SanitizeTerminalTitle(title string) string {
|
||||
return strings.Map(func(r rune) rune {
|
||||
if r < 32 || r == 127 {
|
||||
return -1 // Remove control characters
|
||||
}
|
||||
return r
|
||||
}, title)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,3 +66,73 @@ func TestResolvePlaceholderString(t *testing.T) {
|
|||
assert.EqualValues(t, s.expected, ResolvePlaceholderString(s.templateString, s.arguments))
|
||||
}
|
||||
}
|
||||
|
||||
func TestSanitizeTerminalTitle(t *testing.T) {
|
||||
scenarios := []struct {
|
||||
name string
|
||||
input string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
name: "normal string",
|
||||
input: "lazygit::myproject",
|
||||
expected: "lazygit::myproject",
|
||||
},
|
||||
{
|
||||
name: "empty string",
|
||||
input: "",
|
||||
expected: "",
|
||||
},
|
||||
{
|
||||
name: "string with spaces",
|
||||
input: "lazygit :: my project",
|
||||
expected: "lazygit :: my project",
|
||||
},
|
||||
{
|
||||
name: "string with unicode",
|
||||
input: "lazygit::项目",
|
||||
expected: "lazygit::项目",
|
||||
},
|
||||
{
|
||||
name: "removes null byte",
|
||||
input: "lazy\x00git",
|
||||
expected: "lazygit",
|
||||
},
|
||||
{
|
||||
name: "removes escape sequence",
|
||||
input: "lazy\x1b[31mgit",
|
||||
expected: "lazy[31mgit",
|
||||
},
|
||||
{
|
||||
name: "removes newline and tab",
|
||||
input: "lazy\ngit\ttitle",
|
||||
expected: "lazygittitle",
|
||||
},
|
||||
{
|
||||
name: "removes carriage return",
|
||||
input: "lazy\rgit",
|
||||
expected: "lazygit",
|
||||
},
|
||||
{
|
||||
name: "removes DEL character",
|
||||
input: "lazy\x7fgit",
|
||||
expected: "lazygit",
|
||||
},
|
||||
{
|
||||
name: "removes bell character",
|
||||
input: "lazy\x07git",
|
||||
expected: "lazygit",
|
||||
},
|
||||
{
|
||||
name: "preserves printable special chars",
|
||||
input: "lazy&git|test<>",
|
||||
expected: "lazy&git|test<>",
|
||||
},
|
||||
}
|
||||
|
||||
for _, s := range scenarios {
|
||||
t.Run(s.name, func(t *testing.T) {
|
||||
assert.EqualValues(t, s.expected, SanitizeTerminalTitle(s.input))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -925,6 +925,11 @@
|
|||
"type": "boolean",
|
||||
"description": "If true, when using the panel jump keys (default 1 through 5) and target panel is already active, go to next tab instead",
|
||||
"default": false
|
||||
},
|
||||
"terminalTitle": {
|
||||
"type": "string",
|
||||
"description": "Format string for the terminal window title. Supports placeholders:\n- {{repoName}}: Name of the current repository\nSet to empty string to disable terminal title updates.",
|
||||
"default": "lazygit::{{repoName}}"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
|
|
|
|||
Loading…
Reference in a new issue