From 4c812463f1a0f4adf1a568c3c3644dcfeaeb596b Mon Sep 17 00:00:00 2001 From: Neko Box Coder Date: Sat, 27 Dec 2025 18:56:45 +0000 Subject: [PATCH 1/3] Fixing `tabhighlight` and `tabreverse` options not applying properly --- internal/config/colorscheme.go | 10 +++++ internal/config/settings.go | 2 +- internal/display/tabwindow.go | 49 ++++++++++++------------- runtime/colorschemes/gotham.micro | 1 + runtime/colorschemes/monokai-dark.micro | 1 + runtime/colorschemes/sunny-day.micro | 1 + runtime/help/options.md | 11 +++--- 7 files changed, 43 insertions(+), 32 deletions(-) diff --git a/internal/config/colorscheme.go b/internal/config/colorscheme.go index 1058ab5286..1109717f2e 100644 --- a/internal/config/colorscheme.go +++ b/internal/config/colorscheme.go @@ -208,6 +208,16 @@ func StringToStyle(str string) tcell.Style { return style } +func ReverseColor(s tcell.Style) tcell.Style { + _, _, attr := s.Decompose() + attr = attr ^ tcell.AttrReverse + if attr&tcell.AttrReverse == tcell.AttrReverse { + return s.Reverse(true) + } else { + return s.Reverse(false) + } +} + // StringToColor returns a tcell color from a string representation of a color // We accept either bright... or light... to mean the brighter version of a color func StringToColor(str string) (tcell.Color, bool) { diff --git a/internal/config/settings.go b/internal/config/settings.go index 2f8158334f..20256701e9 100644 --- a/internal/config/settings.go +++ b/internal/config/settings.go @@ -130,7 +130,7 @@ var DefaultGlobalOnlySettings = map[string]any{ "scrollbarchar": "|", "sucmd": "sudo", "tabhighlight": false, - "tabreverse": true, + "tabreverse": false, "xterm": false, } diff --git a/internal/display/tabwindow.go b/internal/display/tabwindow.go index 844f12e922..005d080d7b 100644 --- a/internal/display/tabwindow.go +++ b/internal/display/tabwindow.go @@ -2,7 +2,6 @@ package display import ( runewidth "github.com/mattn/go-runewidth" - "github.com/micro-editor/tcell/v2" "github.com/zyedidia/micro/v2/internal/buffer" "github.com/zyedidia/micro/v2/internal/config" "github.com/zyedidia/micro/v2/internal/screen" @@ -97,25 +96,23 @@ func (w *TabWindow) Display() { globalTabReverse := config.GetGlobalOption("tabreverse").(bool) globalTabHighlight := config.GetGlobalOption("tabhighlight").(bool) + tabBarStyle := config.DefStyle - // xor of reverse and tab highlight to get tab character (as in filename and surrounding characters) reverse state - tabCharHighlight := (globalTabReverse || globalTabHighlight) && !(globalTabReverse && globalTabHighlight) - - reverseStyles := func(reverse bool) (tcell.Style, tcell.Style) { - tabBarStyle := config.DefStyle.Reverse(reverse) - if style, ok := config.Colorscheme["tabbar"]; ok { - tabBarStyle = style - } - tabBarActiveStyle := tabBarStyle - if style, ok := config.Colorscheme["tabbar.active"]; ok { - tabBarActiveStyle = style - } - return tabBarStyle, tabBarActiveStyle + if style, ok := config.Colorscheme["tabbar"]; ok { + tabBarStyle = style + } + if globalTabReverse { + tabBarStyle = config.ReverseColor(tabBarStyle) + } + tabBarActiveStyle := tabBarStyle + if globalTabHighlight { + tabBarActiveStyle = config.ReverseColor(tabBarStyle) + } + if style, ok := config.Colorscheme["tabbar.active"]; ok { + tabBarActiveStyle = style } - draw := func(r rune, n int, active bool, reversed bool) { - tabBarStyle, tabBarActiveStyle := reverseStyles(reversed) - + draw := func(r rune, n int, active bool, tab bool) { style := tabBarStyle if active { style = tabBarActiveStyle @@ -128,11 +125,11 @@ func (w *TabWindow) Display() { c = ' ' } if x == w.Width-1 && !done { - screen.SetContent(w.Width-1, w.Y, '>', nil, tabBarStyle) + screen.SetContent(w.Width-1, w.Y, '>', nil, style) x++ break } else if x == 0 && w.hscroll > 0 { - screen.SetContent(0, w.Y, '<', nil, tabBarStyle) + screen.SetContent(0, w.Y, '<', nil, style) } else if x >= 0 && x < w.Width { screen.SetContent(x, w.Y, c, nil, style) } @@ -143,13 +140,13 @@ func (w *TabWindow) Display() { for i, n := range w.Names { if i == w.active { - draw('[', 1, true, tabCharHighlight) + draw('[', 1, true, true) } else { - draw(' ', 1, false, tabCharHighlight) + draw(' ', 1, false, true) } for _, c := range n { - draw(c, 1, i == w.active, tabCharHighlight) + draw(c, 1, i == w.active, true) } if i == len(w.Names)-1 { @@ -157,11 +154,11 @@ func (w *TabWindow) Display() { } if i == w.active { - draw(']', 1, true, tabCharHighlight) - draw(' ', 2, true, globalTabReverse) + draw(']', 1, true, true) + draw(' ', 2, true, false) } else { - draw(' ', 1, false, tabCharHighlight) - draw(' ', 2, false, globalTabReverse) + draw(' ', 1, false, true) + draw(' ', 2, false, false) } if x >= w.Width { diff --git a/runtime/colorschemes/gotham.micro b/runtime/colorschemes/gotham.micro index d067a81cfa..e4af7ef2d6 100644 --- a/runtime/colorschemes/gotham.micro +++ b/runtime/colorschemes/gotham.micro @@ -25,5 +25,6 @@ color-link cursor-line "#091F2E" color-link color-column "#11151C" color-link symbol "#99D1CE,#0C1014" color-link match-brace "#0C1014,#D26937" +color-link tabbar "#0C1014,#99D1CE" color-link tab-error "#D75F5F" color-link trailingws "#D75F5F" diff --git a/runtime/colorschemes/monokai-dark.micro b/runtime/colorschemes/monokai-dark.micro index 3a1e89c4f3..949535de24 100644 --- a/runtime/colorschemes/monokai-dark.micro +++ b/runtime/colorschemes/monokai-dark.micro @@ -25,4 +25,5 @@ color-link cursor-line "#323232" color-link color-column "#323232" color-link match-brace "#1D0000,#AE81FF" color-link tab-error "#D75F5F" +color-link tabbar "#1D0000,#D5D8D6" color-link trailingws "#D75F5F" diff --git a/runtime/colorschemes/sunny-day.micro b/runtime/colorschemes/sunny-day.micro index 24a3e763ea..e19c623e3b 100644 --- a/runtime/colorschemes/sunny-day.micro +++ b/runtime/colorschemes/sunny-day.micro @@ -26,4 +26,5 @@ color-link cursor-line "229" color-link current-line-number "246" color-link match-brace "230,22" color-link tab-error "210" +color-link tabbar "230,0" color-link trailingws "210" diff --git a/runtime/help/options.md b/runtime/help/options.md index d4832c5d08..7f27e51b48 100644 --- a/runtime/help/options.md +++ b/runtime/help/options.md @@ -460,8 +460,9 @@ Here are the available options: default value: `true` -* `tabhighlight`: inverts the tab characters' (filename, save indicator, etc) - colors with respect to the tab bar. + +* `tabhighlight`: highlighting the current active tab by using the inverted tab bar color. + Has no effect if `tabbar.active` is present in the current colorscheme. default value: `false` @@ -471,9 +472,9 @@ Here are the available options: default value: `false` -* `tabreverse`: reverses the tab bar colors when active. +* `tabreverse`: reverses the tab bar colors. - default value: `true` + default value: `false` * `tabsize`: the size in spaces that a tab character should be displayed with. @@ -626,7 +627,7 @@ so that you can see what the formatting should look like. "statusline": true, "sucmd": "sudo", "syntax": true, - "tabhighlight": true, + "tabhighlight": false, "tabmovement": false, "tabreverse": false, "tabsize": 4, From 922d2c4b0966db2771040cb4674abd6fa1ee8647 Mon Sep 17 00:00:00 2001 From: Neko Box Coder Date: Sat, 27 Dec 2025 18:57:16 +0000 Subject: [PATCH 2/3] Adding `tabbarchars` option for customizing tabbar visuals --- internal/config/settings.go | 1 + internal/display/tabwindow.go | 106 +++++++++++++++++++++++++++++----- runtime/help/colors.md | 4 +- runtime/help/options.md | 13 +++++ 4 files changed, 109 insertions(+), 15 deletions(-) diff --git a/internal/config/settings.go b/internal/config/settings.go index 20256701e9..895267e387 100644 --- a/internal/config/settings.go +++ b/internal/config/settings.go @@ -129,6 +129,7 @@ var DefaultGlobalOnlySettings = map[string]any{ "savehistory": true, "scrollbarchar": "|", "sucmd": "sudo", + "tabbarchars": "div= ,active=[],inactive= ", "tabhighlight": false, "tabreverse": false, "xterm": false, diff --git a/internal/display/tabwindow.go b/internal/display/tabwindow.go index 005d080d7b..4baa028201 100644 --- a/internal/display/tabwindow.go +++ b/internal/display/tabwindow.go @@ -6,6 +6,8 @@ import ( "github.com/zyedidia/micro/v2/internal/config" "github.com/zyedidia/micro/v2/internal/screen" "github.com/zyedidia/micro/v2/internal/util" + "strings" + "unicode/utf8" ) type TabWindow struct { @@ -29,15 +31,26 @@ func (w *TabWindow) Resize(width, height int) { func (w *TabWindow) LocFromVisual(vloc buffer.Loc) int { x := -w.hscroll - + tabactiverunes, tabinactiverunes, tabdivrunes := GetTabRunes() for i, n := range w.Names { - x++ + if i == w.active { + x += len(tabactiverunes) / 2 + } else { + x += len(tabinactiverunes) / 2 + } + s := util.CharacterCountInString(n) if vloc.Y == w.Y && vloc.X < x+s { return i } x += s - x += 3 + + if i == w.active { + x += len(tabactiverunes) - len(tabactiverunes)/2 + } else { + x += len(tabinactiverunes) - len(tabinactiverunes)/2 + } + x += len(tabdivrunes) if x >= w.Width { break } @@ -90,6 +103,39 @@ func (w *TabWindow) SetActive(a int) { } } +func GetTabRunes() ([]rune, []rune, []rune) { + var tabactivechars string + var tabinactivechars string + var tabdivchars string + for _, entry := range strings.Split(config.GetGlobalOption("tabbarchars").(string), ",") { + split := strings.SplitN(entry, "=", 2) + if len(split) < 2 { + continue + } + key, val := split[0], split[1] + switch key { + case "active": + tabactivechars = val + case "inactive": + tabinactivechars = val + case "div": + tabdivchars = val + } + } + + if utf8.RuneCountInString(tabactivechars) < 2 { + tabactivechars = "" + } + if utf8.RuneCountInString(tabinactivechars) < 2 { + tabinactivechars = "" + } + + tabactiverunes := []rune(tabactivechars) + tabinactiverunes := []rune(tabinactivechars) + tabdivrunes := []rune(tabdivchars) + return tabactiverunes, tabinactiverunes, tabdivrunes +} + func (w *TabWindow) Display() { x := -w.hscroll done := false @@ -111,12 +157,27 @@ func (w *TabWindow) Display() { if style, ok := config.Colorscheme["tabbar.active"]; ok { tabBarActiveStyle = style } + tabBarInactiveStyle := tabBarStyle + if style, ok := config.Colorscheme["tabbar.inactive"]; ok { + tabBarInactiveStyle = style + } + tabBarDivStyle := tabBarStyle + if style, ok := config.Colorscheme["tabbar.div"]; ok { + tabBarDivStyle = style + } - draw := func(r rune, n int, active bool, tab bool) { + draw := func(r rune, n int, active bool, tab bool, div bool) { style := tabBarStyle - if active { - style = tabBarActiveStyle + if tab { + if active { + style = tabBarActiveStyle + } else { + style = tabBarInactiveStyle + } + } else if div { + style = tabBarDivStyle } + for i := 0; i < n; i++ { rw := runewidth.RuneWidth(r) for j := 0; j < rw; j++ { @@ -138,15 +199,26 @@ func (w *TabWindow) Display() { } } + tabactiverunes, tabinactiverunes, tabdivrunes := GetTabRunes() + leftactiverunes := tabactiverunes[0 : len(tabactiverunes)/2] + rightactiverunes := tabactiverunes[len(tabactiverunes)/2:] + + leftinactiverunes := tabinactiverunes[0 : len(tabinactiverunes)/2] + rightinactiverunes := tabinactiverunes[len(tabinactiverunes)/2:] + for i, n := range w.Names { if i == w.active { - draw('[', 1, true, true) + for j := 0; j < len(leftactiverunes); j++ { + draw(leftactiverunes[j], 1, true, true, false) + } } else { - draw(' ', 1, false, true) + for j := 0; j < len(leftinactiverunes); j++ { + draw(leftinactiverunes[j], 1, false, true, false) + } } for _, c := range n { - draw(c, 1, i == w.active, true) + draw(c, 1, i == w.active, true, false) } if i == len(w.Names)-1 { @@ -154,11 +226,17 @@ func (w *TabWindow) Display() { } if i == w.active { - draw(']', 1, true, true) - draw(' ', 2, true, false) + for j := 0; j < len(rightactiverunes); j++ { + draw(rightactiverunes[j], 1, true, true, false) + } } else { - draw(' ', 1, false, true) - draw(' ', 2, false, false) + for j := 0; j < len(rightinactiverunes); j++ { + draw(rightinactiverunes[j], 1, false, true, false) + } + } + + for j := 0; j < len(tabdivrunes); j++ { + draw(tabdivrunes[j], 1, false, false, true) } if x >= w.Width { @@ -167,6 +245,6 @@ func (w *TabWindow) Display() { } if x < w.Width { - draw(' ', w.Width-x, false, globalTabReverse) + draw(' ', w.Width-x, false, false, false) } } diff --git a/runtime/help/colors.md b/runtime/help/colors.md index c085919a93..747562bdd3 100644 --- a/runtime/help/colors.md +++ b/runtime/help/colors.md @@ -40,7 +40,7 @@ color support comes in three flavors. same regardless of the configured 16-color palette. However, the color range is fairly limited due to the small number of colors available. Default 256-color colorschemes include `monokai`, `twilight`, `zenburn`, - `darcula` and more. + `dracula` and more. * true-color: Some terminals support displaying "true color" with 16 million colors using standard RGB values. This mode will be able to support @@ -179,6 +179,8 @@ Here is a list of the colorscheme groups that you can use: * statusline.suggestions (Color of the autocomplete suggestions menu) * tabbar (Color of the tabbar that lists open files) * tabbar.active (Color of the active tab in the tabbar) +* tabbar.inactive (Color of the inactive tabs in the tabbar) +* tabbar.div (Color of the space/divider between each tab in the tabbar) * indent-char (Color of the character which indicates tabs if the option is enabled) * line-number diff --git a/runtime/help/options.md b/runtime/help/options.md index 7f27e51b48..607d303eb5 100644 --- a/runtime/help/options.md +++ b/runtime/help/options.md @@ -460,6 +460,19 @@ Here are the available options: default value: `true` +* `tabbarchars`: sets what visual characters to be shown for various tabbar options. + This option is specified in the form of `key1=value1,key2=value2,...`. + + Here are the list of keys: + - `active`: the opening and closing tab characters for the current active tab, + where the values are splitted in half for opening and closing characters. + For example, value of `[[]]` will have `[[` as opening characters and + `]]` as closing characters. + - `div`: the characters to be filled between each tab. + - `inactive`: the opening and closing tab characters for the inactive tabs. + where the values are splitted in half for opening and closing characters. + + default value: `div= ,active=[],inactive= ` * `tabhighlight`: highlighting the current active tab by using the inverted tab bar color. Has no effect if `tabbar.active` is present in the current colorscheme. From 42776dc3d95d15e43e905b2cd1846d314a66bfe8 Mon Sep 17 00:00:00 2001 From: Neko Box Coder Date: Sat, 27 Dec 2025 19:32:29 +0000 Subject: [PATCH 3/3] Changing tab default settings to be more modern --- internal/config/settings.go | 4 ++-- runtime/help/options.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/config/settings.go b/internal/config/settings.go index 895267e387..c93adaa2c8 100644 --- a/internal/config/settings.go +++ b/internal/config/settings.go @@ -129,8 +129,8 @@ var DefaultGlobalOnlySettings = map[string]any{ "savehistory": true, "scrollbarchar": "|", "sucmd": "sudo", - "tabbarchars": "div= ,active=[],inactive= ", - "tabhighlight": false, + "tabbarchars": "div=│,active= [] ,inactive= ", + "tabhighlight": true, "tabreverse": false, "xterm": false, } diff --git a/runtime/help/options.md b/runtime/help/options.md index 607d303eb5..f5f64841e4 100644 --- a/runtime/help/options.md +++ b/runtime/help/options.md @@ -472,12 +472,12 @@ Here are the available options: - `inactive`: the opening and closing tab characters for the inactive tabs. where the values are splitted in half for opening and closing characters. - default value: `div= ,active=[],inactive= ` + default value: `div=│,active= [] ,inactive= ` * `tabhighlight`: highlighting the current active tab by using the inverted tab bar color. Has no effect if `tabbar.active` is present in the current colorscheme. - default value: `false` + default value: `true` * `tabmovement`: navigate spaces at the beginning of lines as if they are tabs (e.g. move over 4 spaces at once). This option only does anything if