diff kitten: Automatically change colors on terminal color scheme change

This commit is contained in:
Kovid Goyal
2025-01-05 06:00:24 +05:30
parent 98c1e0f7aa
commit f3db7e7554
9 changed files with 113 additions and 35 deletions

View File

@@ -20,7 +20,8 @@ var path_name_map, remote_dirs map[string]string
var mimetypes_cache, data_cache, hash_cache *utils.LRUCache[string, string]
var size_cache *utils.LRUCache[string, int64]
var lines_cache *utils.LRUCache[string, []string]
var highlighted_lines_cache *utils.LRUCache[string, []string]
var light_highlighted_lines_cache *utils.LRUCache[string, []string]
var dark_highlighted_lines_cache *utils.LRUCache[string, []string]
var is_text_cache *utils.LRUCache[string, bool]
func init_caches() {
@@ -32,7 +33,8 @@ func init_caches() {
data_cache = utils.NewLRUCache[string, string](sz)
is_text_cache = utils.NewLRUCache[string, bool](sz)
lines_cache = utils.NewLRUCache[string, []string](sz)
highlighted_lines_cache = utils.NewLRUCache[string, []string](sz)
light_highlighted_lines_cache = utils.NewLRUCache[string, []string](sz)
dark_highlighted_lines_cache = utils.NewLRUCache[string, []string](sz)
hash_cache = utils.NewLRUCache[string, string](sz)
}
@@ -150,7 +152,14 @@ func highlighted_lines_for_path(path string) ([]string, error) {
if err != nil {
return nil, err
}
if ans, found := highlighted_lines_cache.Get(path); found && len(ans) == len(plain_lines) {
var ans []string
var found bool
if use_light_colors {
ans, found = light_highlighted_lines_cache.Get(path)
} else {
ans, found = dark_highlighted_lines_cache.Get(path)
}
if found && len(ans) == len(plain_lines) {
return ans, nil
}
return plain_lines, nil

View File

@@ -158,8 +158,8 @@ func ansi_formatter(w io.Writer, style *chroma.Style, it chroma.Iterator) (err e
return nil
}
func resolved_chroma_style() *chroma.Style {
name := utils.IfElse(use_dark_colors, conf.Dark_pygments_style, conf.Pygments_style)
func resolved_chroma_style(use_light_colors bool) *chroma.Style {
name := utils.IfElse(use_light_colors, conf.Pygments_style, conf.Dark_pygments_style)
var style *chroma.Style
if name == "default" {
style = DefaultStyle()
@@ -185,7 +185,7 @@ func resolved_chroma_style() *chroma.Style {
var tokens_map map[string][]chroma.Token
var mu sync.Mutex
func highlight_file(path string) (highlighted string, err error) {
func highlight_file(path string, use_light_colors bool) (highlighted string, err error) {
defer func() {
if r := recover(); r != nil {
e, ok := r.(error)
@@ -235,19 +235,24 @@ func highlight_file(path string) (highlighted string, err error) {
formatter := chroma.FormatterFunc(ansi_formatter)
w := strings.Builder{}
w.Grow(len(text) * 2)
err = formatter.Format(&w, resolved_chroma_style(), chroma.Literator(tokens...))
err = formatter.Format(&w, resolved_chroma_style(use_light_colors), chroma.Literator(tokens...))
// os.WriteFile(filepath.Base(path+".highlighted"), []byte(w.String()), 0o600)
return w.String(), err
}
func highlight_all(paths []string) {
func highlight_all(paths []string, light bool) {
ctx := images.Context{}
ctx.Parallel(0, len(paths), func(nums <-chan int) {
for i := range nums {
path := paths[i]
raw, err := highlight_file(path)
if err == nil {
highlighted_lines_cache.Set(path, text_to_lines(raw))
raw, err := highlight_file(path, light)
if err != nil {
continue
}
if light {
light_highlighted_lines_cache.Set(path, text_to_lines(raw))
} else {
dark_highlighted_lines_cache.Set(path, text_to_lines(raw))
}
}
})

View File

@@ -139,6 +139,7 @@ func main(_ *cli.Command, opts_ *Options, args []string) (rc int, err error) {
if err != nil {
return 1, err
}
lp.ColorSchemeChangeNotifications()
h := Handler{left: left, right: right, lp: lp}
lp.OnInitialize = func() (string, error) {
lp.SetCursorVisible(false)

View File

@@ -160,7 +160,7 @@ var format_as_sgr struct {
}
var statusline_format, added_count_format, removed_count_format, message_format func(...any) string
var use_dark_colors bool = true
var use_light_colors bool = false
type ResolvedColors struct {
Added_bg style.RGBA
@@ -189,7 +189,7 @@ var resolved_colors ResolvedColors
func create_formatters() {
rc := &resolved_colors
if use_dark_colors {
if !use_light_colors {
rc.Added_bg = conf.Dark_added_bg
rc.Added_margin_bg = conf.Dark_added_margin_bg
rc.Background = conf.Dark_background

View File

@@ -124,6 +124,7 @@ func set_terminal_colors(lp *loop.Loop) {
}
func (self *Handler) on_capabilities_received(tc loop.TerminalCapabilities) {
var use_dark_colors bool
switch conf.Color_scheme {
case Color_scheme_auto:
use_dark_colors = tc.ColorPreference != loop.LIGHT_COLOR_PREFERENCE
@@ -132,14 +133,30 @@ func (self *Handler) on_capabilities_received(tc loop.TerminalCapabilities) {
case Color_scheme_dark:
use_dark_colors = true
}
use_light_colors = !use_dark_colors
set_terminal_colors(self.lp)
self.terminal_capabilities_received = true
self.draw_screen()
}
func (self *Handler) on_color_scheme_change(cp loop.ColorPreference) error {
if conf.Color_scheme != Color_scheme_auto {
return nil
}
light := cp == loop.LIGHT_COLOR_PREFERENCE
if use_light_colors != light {
use_light_colors = light
set_terminal_colors(self.lp)
self.highlight_all()
self.draw_screen()
}
return nil
}
func (self *Handler) initialize() {
self.rl = readline.New(self.lp, readline.RlInit{DontMarkPrompts: true, Prompt: "/"})
self.lp.OnEscapeCode = self.on_escape_code
self.lp.OnColorSchemeChange = self.on_color_scheme_change
image_collection = graphics.NewImageCollection()
self.current_context_count = opts.Context
if self.current_context_count < 0 {
@@ -195,11 +212,22 @@ func (self *Handler) on_wakeup() error {
}
}
var dark_highlight_started bool
var light_highlight_started bool
func (self *Handler) highlight_all() {
if (use_light_colors && light_highlight_started) || (!use_light_colors && dark_highlight_started) {
return
}
if use_light_colors {
light_highlight_started = true
} else {
dark_highlight_started = true
}
text_files := utils.Filter(self.collection.paths_to_highlight.AsSlice(), is_path_text)
go func() {
r := AsyncResult{rtype: HIGHLIGHT}
highlight_all(text_files)
highlight_all(text_files, use_light_colors)
self.async_results <- r
self.lp.WakeupMainThread()
}()