mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-05-11 04:15:48 +02:00
Let users define custom icons and color for files on the config file (#4395)
- **PR Description** _Yet another icon-related PR_ - Implementation on config file for user defined file icons and colors. - Fix for some file icon mappings. I use [eza](https://github.com/eza-community/eza), [nvim-wewb-devicons](https://github.com/nvim-tree/nvim-web-devicons) and lazygit; the first ones already let user to override icons and colors via a config file, so with this change I can customize based on filenames and file extensions. | Before | After | |--------|--------| |  |  | ```yaml gui: customIcons: filenames: "CONTRIBUTING.md": { icon: "\uede2", color: "#FEDDEF" } "HACKING.md": { icon: "\uede2", color: "#FEDDEF" } extensions: ".cat": icon: "\U000f011b" color: "#BC4009" ".dog": icon: "\U000f0a43" color: "#B6977E" ```
This commit is contained in:
commit
5038fa2d51
8 changed files with 124 additions and 17 deletions
|
@ -43,6 +43,15 @@ gui:
|
|||
# See https://github.com/jesseduffield/lazygit/blob/master/docs/Config.md#custom-branch-color
|
||||
branchColorPatterns: {}
|
||||
|
||||
# Custom icons for filenames and file extensions
|
||||
# See https://github.com/jesseduffield/lazygit/blob/master/docs/Config.md#custom-files-icon--color
|
||||
customIcons:
|
||||
# Map of filenames to icon properties (icon and color)
|
||||
filenames: {}
|
||||
|
||||
# Map of file extensions (including the dot) to icon properties (icon and color)
|
||||
extensions: {}
|
||||
|
||||
# The number of lines you scroll by when scrolling the main window
|
||||
scrollHeight: 2
|
||||
|
||||
|
@ -649,32 +658,39 @@ os:
|
|||
```
|
||||
|
||||
## Custom Command for Opening a Link
|
||||
|
||||
```yaml
|
||||
os:
|
||||
openLink: 'bash -C /path/to/your/shell-script.sh {{link}}'
|
||||
```
|
||||
|
||||
Specify the external command to invoke when opening URL links (i.e. creating MR/PR in GitLab, BitBucket or GitHub). `{{link}}` will be replaced by the URL to be opened. A simple shell script can be used to further mangle the passed URL.
|
||||
|
||||
## Custom Command for Copying to and Pasting from Clipboard
|
||||
|
||||
```yaml
|
||||
os:
|
||||
copyToClipboardCmd: ''
|
||||
```
|
||||
|
||||
Specify an external command to invoke when copying to clipboard is requested. `{{text}` will be replaced by text to be copied. Default is to copy to system clipboard.
|
||||
|
||||
If you are working on a terminal that supports OSC52, the following command will let you take advantage of it:
|
||||
|
||||
```yaml
|
||||
os:
|
||||
copyToClipboardCmd: printf "\033]52;c;$(printf {{text}} | base64 -w 0)\a" > /dev/tty
|
||||
```
|
||||
|
||||
For tmux you need to wrap it with the [tmux escape sequence](https://github.com/tmux/tmux/wiki/FAQ#what-is-the-passthrough-escape-sequence-and-how-do-i-use-it), and enable passthrough in tmux config with `set -g allow-passthrough on`:
|
||||
|
||||
```yaml
|
||||
os:
|
||||
copyToClipboardCmd: printf "\033Ptmux;\033\033]52;c;$(printf {{text}} | base64 -w 0)\a\033\\" > /dev/tty
|
||||
```
|
||||
|
||||
For the best of both worlds, we can let the command determine if we are running in a tmux session and send the correct sequence:
|
||||
|
||||
```yaml
|
||||
os:
|
||||
copyToClipboardCmd: >
|
||||
|
@ -686,10 +702,12 @@ os:
|
|||
```
|
||||
|
||||
A custom command for reading from the clipboard can be set using
|
||||
|
||||
```yaml
|
||||
os:
|
||||
readFromClipboardCmd: ''
|
||||
```
|
||||
|
||||
It is used, for example, when pasting a commit message into the commit message panel. The command is supposed to output the clipboard content to stdout.
|
||||
|
||||
## Configuring File Editing
|
||||
|
@ -832,6 +850,27 @@ gui:
|
|||
|
||||
Note that the regular expressions are not implicitly anchored to the beginning/end of the branch name. If you want to do that, add leading `^` and/or trailing `$` as needed.
|
||||
|
||||
## Custom Files Icon & Color
|
||||
|
||||
You can customize the icon and color of files based on filenames or extensions:
|
||||
|
||||
```yaml
|
||||
gui:
|
||||
customIcons:
|
||||
filenames:
|
||||
"CONTRIBUTING.md": { icon: "\uede2", color: "#FEDDEF" }
|
||||
"HACKING.md": { icon: "\uede2", color: "#FEDDEF" }
|
||||
extensions:
|
||||
".cat":
|
||||
icon: "\U000f011b"
|
||||
color: "#BC4009"
|
||||
".dog":
|
||||
icon: "\U000f0a43"
|
||||
color: "#B6977E"
|
||||
```
|
||||
|
||||
Note that there is no support for regular expressions.
|
||||
|
||||
## Example Coloring
|
||||
|
||||

|
||||
|
@ -960,6 +999,7 @@ In situations where certain naming pattern is used for branches, this can be use
|
|||
Example:
|
||||
|
||||
Some branches:
|
||||
|
||||
- jsmith/AB-123
|
||||
- cwilson/AB-125
|
||||
|
||||
|
|
|
@ -57,6 +57,9 @@ type GuiConfig struct {
|
|||
BranchColors map[string]string `yaml:"branchColors" jsonschema:"deprecated"`
|
||||
// See https://github.com/jesseduffield/lazygit/blob/master/docs/Config.md#custom-branch-color
|
||||
BranchColorPatterns map[string]string `yaml:"branchColorPatterns"`
|
||||
// Custom icons for filenames and file extensions
|
||||
// See https://github.com/jesseduffield/lazygit/blob/master/docs/Config.md#custom-files-icon--color
|
||||
CustomIcons CustomIconsConfig `yaml:"customIcons"`
|
||||
// The number of lines you scroll by when scrolling the main window
|
||||
ScrollHeight int `yaml:"scrollHeight" jsonschema:"minimum=1"`
|
||||
// If true, allow scrolling past the bottom of the content in the main window
|
||||
|
@ -707,6 +710,18 @@ type CustomCommandMenuOption struct {
|
|||
Value string `yaml:"value" jsonschema:"example=feature,minLength=1"`
|
||||
}
|
||||
|
||||
type CustomIconsConfig struct {
|
||||
// Map of filenames to icon properties (icon and color)
|
||||
Filenames map[string]IconProperties `yaml:"filenames"`
|
||||
// Map of file extensions (including the dot) to icon properties (icon and color)
|
||||
Extensions map[string]IconProperties `yaml:"extensions"`
|
||||
}
|
||||
|
||||
type IconProperties struct {
|
||||
Icon string `yaml:"icon"`
|
||||
Color string `yaml:"color"`
|
||||
}
|
||||
|
||||
func GetDefaultConfig() *UserConfig {
|
||||
return &UserConfig{
|
||||
Gui: GuiConfig{
|
||||
|
|
|
@ -39,7 +39,7 @@ func NewCommitFilesContext(c *ContextCommon) *CommitFilesContext {
|
|||
}
|
||||
|
||||
showFileIcons := icons.IsIconEnabled() && c.UserConfig().Gui.ShowFileIcons
|
||||
lines := presentation.RenderCommitFileTree(viewModel, c.Git().Patch.PatchBuilder, showFileIcons)
|
||||
lines := presentation.RenderCommitFileTree(viewModel, c.Git().Patch.PatchBuilder, showFileIcons, &c.UserConfig().Gui.CustomIcons)
|
||||
return lo.Map(lines, func(line string, _ int) []string {
|
||||
return []string{line}
|
||||
})
|
||||
|
|
|
@ -31,7 +31,7 @@ func NewWorkingTreeContext(c *ContextCommon) *WorkingTreeContext {
|
|||
getDisplayStrings := func(_ int, _ int) [][]string {
|
||||
showFileIcons := icons.IsIconEnabled() && c.UserConfig().Gui.ShowFileIcons
|
||||
showNumstat := c.UserConfig().Gui.ShowNumstatInFilesView
|
||||
lines := presentation.RenderFileTree(viewModel, c.Model().Submodules, showFileIcons, showNumstat)
|
||||
lines := presentation.RenderFileTree(viewModel, c.Model().Submodules, showFileIcons, showNumstat, &c.UserConfig().Gui.CustomIcons)
|
||||
return lo.Map(lines, func(line string, _ int) []string {
|
||||
return []string{line}
|
||||
})
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"github.com/gookit/color"
|
||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||
"github.com/jesseduffield/lazygit/pkg/commands/patch"
|
||||
"github.com/jesseduffield/lazygit/pkg/config"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/filetree"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/presentation/icons"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/style"
|
||||
|
@ -23,12 +24,13 @@ func RenderFileTree(
|
|||
submoduleConfigs []*models.SubmoduleConfig,
|
||||
showFileIcons bool,
|
||||
showNumstat bool,
|
||||
customIconsConfig *config.CustomIconsConfig,
|
||||
) []string {
|
||||
collapsedPaths := tree.CollapsedPaths()
|
||||
return renderAux(tree.GetRoot().Raw(), collapsedPaths, -1, -1, func(node *filetree.Node[models.File], treeDepth int, visualDepth int, isCollapsed bool) string {
|
||||
fileNode := filetree.NewFileNode(node)
|
||||
|
||||
return getFileLine(isCollapsed, fileNode.GetHasUnstagedChanges(), fileNode.GetHasStagedChanges(), treeDepth, visualDepth, showNumstat, showFileIcons, submoduleConfigs, node)
|
||||
return getFileLine(isCollapsed, fileNode.GetHasUnstagedChanges(), fileNode.GetHasStagedChanges(), treeDepth, visualDepth, showNumstat, showFileIcons, submoduleConfigs, node, customIconsConfig)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -36,12 +38,13 @@ func RenderCommitFileTree(
|
|||
tree *filetree.CommitFileTreeViewModel,
|
||||
patchBuilder *patch.PatchBuilder,
|
||||
showFileIcons bool,
|
||||
customIconsConfig *config.CustomIconsConfig,
|
||||
) []string {
|
||||
collapsedPaths := tree.CollapsedPaths()
|
||||
return renderAux(tree.GetRoot().Raw(), collapsedPaths, -1, -1, func(node *filetree.Node[models.CommitFile], treeDepth int, visualDepth int, isCollapsed bool) string {
|
||||
status := commitFilePatchStatus(node, tree, patchBuilder)
|
||||
|
||||
return getCommitFileLine(isCollapsed, treeDepth, visualDepth, node, status, showFileIcons)
|
||||
return getCommitFileLine(isCollapsed, treeDepth, visualDepth, node, status, showFileIcons, customIconsConfig)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -116,6 +119,7 @@ func getFileLine(
|
|||
showFileIcons bool,
|
||||
submoduleConfigs []*models.SubmoduleConfig,
|
||||
node *filetree.Node[models.File],
|
||||
customIconsConfig *config.CustomIconsConfig,
|
||||
) string {
|
||||
name := fileNameAtDepth(node, treeDepth)
|
||||
output := ""
|
||||
|
@ -156,7 +160,7 @@ func getFileLine(
|
|||
isDirectory := file == nil
|
||||
|
||||
if showFileIcons {
|
||||
icon := icons.IconForFile(name, isSubmodule, isLinkedWorktree, isDirectory)
|
||||
icon := icons.IconForFile(name, isSubmodule, isLinkedWorktree, isDirectory, customIconsConfig)
|
||||
paint := color.HEX(icon.Color, false)
|
||||
output += paint.Sprint(icon.Icon) + nameColor.Sprint(" ")
|
||||
}
|
||||
|
@ -218,6 +222,7 @@ func getCommitFileLine(
|
|||
node *filetree.Node[models.CommitFile],
|
||||
status patch.PatchStatus,
|
||||
showFileIcons bool,
|
||||
customIconsConfig *config.CustomIconsConfig,
|
||||
) string {
|
||||
indentation := strings.Repeat(" ", visualDepth)
|
||||
name := commitFileNameAtDepth(node, treeDepth)
|
||||
|
@ -266,7 +271,7 @@ func getCommitFileLine(
|
|||
isLinkedWorktree := false
|
||||
|
||||
if showFileIcons {
|
||||
icon := icons.IconForFile(name, isSubmodule, isLinkedWorktree, isDirectory)
|
||||
icon := icons.IconForFile(name, isSubmodule, isLinkedWorktree, isDirectory, customIconsConfig)
|
||||
paint := color.HEX(icon.Color, false)
|
||||
output += paint.Sprint(icon.Icon) + " "
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"github.com/gookit/color"
|
||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||
"github.com/jesseduffield/lazygit/pkg/commands/patch"
|
||||
"github.com/jesseduffield/lazygit/pkg/config"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/filetree"
|
||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
@ -91,7 +92,7 @@ func TestRenderFileTree(t *testing.T) {
|
|||
for _, path := range s.collapsedPaths {
|
||||
viewModel.ToggleCollapsed(path)
|
||||
}
|
||||
result := RenderFileTree(viewModel, nil, false, s.showLineChanges)
|
||||
result := RenderFileTree(viewModel, nil, false, s.showLineChanges, &config.CustomIconsConfig{})
|
||||
assert.EqualValues(t, s.expected, result)
|
||||
})
|
||||
}
|
||||
|
@ -161,7 +162,7 @@ func TestRenderCommitFileTree(t *testing.T) {
|
|||
},
|
||||
)
|
||||
patchBuilder.Start("from", "to", false, false)
|
||||
result := RenderCommitFileTree(viewModel, patchBuilder, false)
|
||||
result := RenderCommitFileTree(viewModel, patchBuilder, false, &config.CustomIconsConfig{})
|
||||
assert.EqualValues(t, s.expected, result)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -3,11 +3,13 @@ package icons
|
|||
import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/jesseduffield/lazygit/pkg/config"
|
||||
)
|
||||
|
||||
// NOTE: Visit next links for inspiration:
|
||||
// https://github.com/eza-community/eza/blob/main/src/output/icons.rs
|
||||
// https://github.com/nvim-tree/nvim-web-devicons/blob/master/lua/nvim-web-devicons/icons-default.lua
|
||||
// https://github.com/nvim-tree/nvim-web-devicons/tree/master/lua/nvim-web-devicons/default
|
||||
|
||||
var (
|
||||
DEFAULT_FILE_ICON = IconProperties{Icon: "\uf15b", Color: "#878787"} //
|
||||
|
@ -15,6 +17,7 @@ var (
|
|||
DEFAULT_DIRECTORY_ICON = IconProperties{Icon: "\uf07b", Color: "#878787"} //
|
||||
)
|
||||
|
||||
// NOTE: The filename map is case sensitive.
|
||||
var nameIconMap = map[string]IconProperties{
|
||||
".atom": {Icon: "\ue764", Color: "#EED9B7"}, //
|
||||
".babelrc": {Icon: "\ue639", Color: "#FED836"}, //
|
||||
|
@ -90,7 +93,7 @@ var nameIconMap = map[string]IconProperties{
|
|||
"Cargo.lock": {Icon: "\ue7a8", Color: "#DEA584"}, //
|
||||
"Cargo.toml": {Icon: "\ue7a8", Color: "#DEA584"}, //
|
||||
"checkhealth": {Icon: "\U000f04d9", Color: "#75B4FB"}, //
|
||||
"cmakelists.txt": {Icon: "\ue794", Color: "##DCE3EB"}, //
|
||||
"CMakeLists.txt": {Icon: "\ue794", Color: "#DCE3EB"}, //
|
||||
"CODE_OF_CONDUCT": {Icon: "\uf4ae", Color: "#E41662"}, //
|
||||
"CODE_OF_CONDUCT.md": {Icon: "\uf4ae", Color: "#E41662"}, //
|
||||
"CODE-OF-CONDUCT.md": {Icon: "\uf4ae", Color: "#E41662"}, //
|
||||
|
@ -280,7 +283,7 @@ var extIconMap = map[string]IconProperties{
|
|||
".cljd": {Icon: "\ue76a", Color: "#519ABA"}, //
|
||||
".cljs": {Icon: "\ue642", Color: "#2AB6F6"}, //
|
||||
".cls": {Icon: "\ue69b", Color: "#4B5163"}, //
|
||||
".cmake": {Icon: "\ue794", Color: "##DCE3EB"}, //
|
||||
".cmake": {Icon: "\ue794", Color: "#DCE3EB"}, //
|
||||
".cmd": {Icon: "\uebc4", Color: "#FF7043"}, //
|
||||
".cob": {Icon: "\u2699", Color: "#005CA5"}, // ⚙
|
||||
".cobol": {Icon: "\u2699", Color: "#005CA5"}, // ⚙
|
||||
|
@ -402,14 +405,14 @@ var extIconMap = map[string]IconProperties{
|
|||
".guardfile": {Icon: "\ue21e", Color: "#626262"}, //
|
||||
".gv": {Icon: "\U000f1049", Color: "#005F87"}, //
|
||||
".gz": {Icon: "\uf410", Color: "#ECA517"}, //
|
||||
".h": {Icon: "\uf0fd", Color: "##A074C4"}, //
|
||||
".h": {Icon: "\uf0fd", Color: "#A074C4"}, //
|
||||
".haml": {Icon: "\ue664", Color: "#F4521E"}, //
|
||||
".hbs": {Icon: "\U000f15de", Color: "#FF7043"}, //
|
||||
".hc": {Icon: "\U000f00a2", Color: "#FAF743"}, //
|
||||
".heex": {Icon: "\ue62d", Color: "#9575CE"}, //
|
||||
".hex": {Icon: "\U000f12a7", Color: "#25A79A"}, //
|
||||
".hh": {Icon: "\uf0fd", Color: "##A074C4"}, //
|
||||
".hpp": {Icon: "\uf0fd", Color: "##A074C4"}, //
|
||||
".hh": {Icon: "\uf0fd", Color: "#A074C4"}, //
|
||||
".hpp": {Icon: "\uf0fd", Color: "#A074C4"}, //
|
||||
".hrl": {Icon: "\ue7b1", Color: "#B83998"}, //
|
||||
".hs": {Icon: "\ue61f", Color: "#FFA726"}, //
|
||||
".htm": {Icon: "\uf13b", Color: "#E44E27"}, //
|
||||
|
@ -417,7 +420,7 @@ var extIconMap = map[string]IconProperties{
|
|||
".huff": {Icon: "\U000f0858", Color: "#CFD8DD"}, //
|
||||
".hurl": {Icon: "\uf0ec", Color: "#FF0288"}, //
|
||||
".hx": {Icon: "\ue666", Color: "#F68713"}, //
|
||||
".hxx": {Icon: "\uf0fd", Color: "##A074C4"}, //
|
||||
".hxx": {Icon: "\uf0fd", Color: "#A074C4"}, //
|
||||
".ical": {Icon: "\uf073", Color: "#2B9EF3"}, //
|
||||
".icalendar": {Icon: "\uf073", Color: "#2B9EF3"}, //
|
||||
".ico": {Icon: "\U000f021f", Color: "#25A6A0"}, //
|
||||
|
@ -688,7 +691,7 @@ var extIconMap = map[string]IconProperties{
|
|||
".tlz": {Icon: "\uf410", Color: "#ECA517"}, //
|
||||
".tmux": {Icon: "\uebc8", Color: "#14BA19"}, //
|
||||
".toml": {Icon: "\ue6b2", Color: "#9C4221"}, //
|
||||
".torrent": {Icon: "\ue275", Color: "##4C90E8"}, //
|
||||
".torrent": {Icon: "\ue275", Color: "#4C90E8"}, //
|
||||
".tres": {Icon: "\ue65f", Color: "#42A5F5"}, //
|
||||
".ts": {Icon: "\U000f06e6", Color: "#0188D1"}, //
|
||||
".tscn": {Icon: "\ue65f", Color: "#42A5F5"}, //
|
||||
|
@ -763,13 +766,19 @@ func patchFileIconsForNerdFontsV2() {
|
|||
extIconMap[".vue"] = IconProperties{Icon: "\ufd42", Color: "#89e051"} // ﵂
|
||||
}
|
||||
|
||||
func IconForFile(name string, isSubmodule bool, isLinkedWorktree bool, isDirectory bool) IconProperties {
|
||||
func IconForFile(name string, isSubmodule bool, isLinkedWorktree bool, isDirectory bool, customIconsConfig *config.CustomIconsConfig) IconProperties {
|
||||
base := filepath.Base(name)
|
||||
if icon, ok := customIconsConfig.Filenames[base]; ok {
|
||||
return IconProperties{Color: icon.Color, Icon: icon.Icon}
|
||||
}
|
||||
if icon, ok := nameIconMap[base]; ok {
|
||||
return icon
|
||||
}
|
||||
|
||||
ext := strings.ToLower(filepath.Ext(name))
|
||||
if icon, ok := customIconsConfig.Extensions[ext]; ok {
|
||||
return IconProperties{Color: icon.Color, Icon: icon.Icon}
|
||||
}
|
||||
if icon, ok := extIconMap[ext]; ok {
|
||||
return icon
|
||||
}
|
||||
|
|
|
@ -263,6 +263,27 @@
|
|||
"additionalProperties": false,
|
||||
"type": "object"
|
||||
},
|
||||
"CustomIconsConfig": {
|
||||
"properties": {
|
||||
"filenames": {
|
||||
"additionalProperties": {
|
||||
"$ref": "#/$defs/IconProperties"
|
||||
},
|
||||
"type": "object",
|
||||
"description": "Map of filenames to icon properties (icon and color)"
|
||||
},
|
||||
"extensions": {
|
||||
"additionalProperties": {
|
||||
"$ref": "#/$defs/IconProperties"
|
||||
},
|
||||
"type": "object",
|
||||
"description": "Map of file extensions (including the dot) to icon properties (icon and color)"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"type": "object",
|
||||
"description": "Custom icons for filenames and file extensions\nSee https://github.com/jesseduffield/lazygit/blob/master/docs/Config.md#custom-files-icon--color"
|
||||
},
|
||||
"GitConfig": {
|
||||
"properties": {
|
||||
"paging": {
|
||||
|
@ -404,6 +425,10 @@
|
|||
"type": "object",
|
||||
"description": "See https://github.com/jesseduffield/lazygit/blob/master/docs/Config.md#custom-branch-color"
|
||||
},
|
||||
"customIcons": {
|
||||
"$ref": "#/$defs/CustomIconsConfig",
|
||||
"description": "Custom icons for filenames and file extensions\nSee https://github.com/jesseduffield/lazygit/blob/master/docs/Config.md#custom-files-icon--color"
|
||||
},
|
||||
"scrollHeight": {
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
|
@ -700,6 +725,18 @@
|
|||
"type": "object",
|
||||
"description": "Config relating to the Lazygit UI"
|
||||
},
|
||||
"IconProperties": {
|
||||
"properties": {
|
||||
"icon": {
|
||||
"type": "string"
|
||||
},
|
||||
"color": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"type": "object"
|
||||
},
|
||||
"KeybindingAmendAttributeConfig": {
|
||||
"properties": {
|
||||
"resetAuthor": {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue