Start work on porting themes kitten to Go
This commit is contained in:
parent
3741d3d1be
commit
f9b0b54ee5
@ -47,7 +47,7 @@ def main() -> None:
|
||||
all_colors.append(opt.name)
|
||||
patch_color_list('kitty/rc/set_colors.py', nullable_colors, 'NULLABLE')
|
||||
patch_color_list('tools/cmd/at/set_colors.go', nullable_colors, 'NULLABLE')
|
||||
patch_color_list('kittens/themes/collection.py', all_colors, 'ALL', ' ' * 8)
|
||||
patch_color_list('tools/themes/collection.go', all_colors, 'ALL')
|
||||
|
||||
from kittens.diff.options.definition import definition as kd
|
||||
write_output('kittens.diff', kd)
|
||||
|
||||
@ -619,4 +619,5 @@ elif __name__ == '__doc__':
|
||||
cd['usage'] = usage
|
||||
cd['options'] = OPTIONS
|
||||
cd['help_text'] = help_text
|
||||
cd['short_desc'] = 'Manage kitty color schemes easily'
|
||||
cd['args_completion'] = CompletionSpec.from_string('type:special group:complete_themes')
|
||||
|
||||
@ -24,7 +24,7 @@ exec_kitty() {
|
||||
|
||||
|
||||
is_wrapped_kitten() {
|
||||
wrapped_kittens="clipboard icat hyperlinked_grep ask hints unicode_input ssh"
|
||||
wrapped_kittens="clipboard icat hyperlinked_grep ask hints unicode_input ssh themes"
|
||||
[ -n "$1" ] && {
|
||||
case " $wrapped_kittens " in
|
||||
*" $1 "*) printf "%s" "$1" ;;
|
||||
|
||||
@ -4,11 +4,10 @@ package completion
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
"kitty/tools/cli"
|
||||
"kitty/tools/utils"
|
||||
"kitty/tools/themes"
|
||||
)
|
||||
|
||||
var _ = fmt.Print
|
||||
@ -64,20 +63,7 @@ func complete_plus_open(completions *cli.Completions, word string, arg_num int)
|
||||
}
|
||||
|
||||
func complete_themes(completions *cli.Completions, word string, arg_num int) {
|
||||
kitty := utils.KittyExe()
|
||||
if kitty != "" {
|
||||
out, err := exec.Command(kitty, "+runpy", "from kittens.themes.collection import *; print_theme_names()").Output()
|
||||
if err == nil {
|
||||
mg := completions.AddMatchGroup("Themes")
|
||||
scanner := utils.NewLineScanner(utils.UnsafeBytesToString(out))
|
||||
for scanner.Scan() {
|
||||
theme_name := strings.TrimSpace(scanner.Text())
|
||||
if theme_name != "" && strings.HasPrefix(theme_name, word) {
|
||||
mg.AddMatch(theme_name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
themes.CompleteThemes(completions, word, arg_num)
|
||||
}
|
||||
|
||||
func EntryPoint(tool_root *cli.Command) {
|
||||
|
||||
62
tools/cmd/themes/main.go
Normal file
62
tools/cmd/themes/main.go
Normal file
@ -0,0 +1,62 @@
|
||||
// License: GPLv3 Copyright: 2023, Kovid Goyal, <kovid at kovidgoyal.net>
|
||||
|
||||
package themes
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"kitty/tools/cli"
|
||||
"kitty/tools/themes"
|
||||
"kitty/tools/utils"
|
||||
)
|
||||
|
||||
var _ = fmt.Print
|
||||
|
||||
func complete_themes(completions *cli.Completions, word string, arg_num int) {
|
||||
themes.CompleteThemes(completions, word, arg_num)
|
||||
}
|
||||
|
||||
func non_interactive(opts *Options, theme_name string) (rc int, err error) {
|
||||
themes, closer, err := themes.LoadThemes(time.Duration(opts.CacheAge * float64(time.Hour*24)))
|
||||
if err != nil {
|
||||
return 1, err
|
||||
}
|
||||
defer closer.Close()
|
||||
theme := themes.ThemeByName(theme_name)
|
||||
if theme == nil {
|
||||
theme_name = strings.ReplaceAll(theme_name, `\`, ``)
|
||||
theme = themes.ThemeByName(theme_name)
|
||||
if theme == nil {
|
||||
return 1, fmt.Errorf("No theme named: %s", theme_name)
|
||||
}
|
||||
}
|
||||
if opts.DumpTheme {
|
||||
code, err := theme.Code()
|
||||
if err != nil {
|
||||
return 1, err
|
||||
}
|
||||
fmt.Println(code)
|
||||
} else {
|
||||
err = theme.SaveInConf(utils.ConfigDir(), opts.ReloadIn, opts.ConfigFileName)
|
||||
if err != nil {
|
||||
return 1, err
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func main(_ *cli.Command, opts *Options, args []string) (rc int, err error) {
|
||||
if len(args) > 1 {
|
||||
args = []string{strings.Join(args, ` `)}
|
||||
}
|
||||
if len(args) == 1 {
|
||||
return non_interactive(opts, args[0])
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func EntryPoint(parent *cli.Command) {
|
||||
create_cmd(parent, main)
|
||||
}
|
||||
@ -15,6 +15,7 @@ import (
|
||||
"kitty/tools/cmd/icat"
|
||||
"kitty/tools/cmd/pytest"
|
||||
"kitty/tools/cmd/ssh"
|
||||
"kitty/tools/cmd/themes"
|
||||
"kitty/tools/cmd/unicode_input"
|
||||
"kitty/tools/cmd/update_self"
|
||||
"kitty/tools/tui"
|
||||
@ -45,6 +46,8 @@ func KittyToolEntryPoints(root *cli.Command) {
|
||||
ask.EntryPoint(root)
|
||||
// hints
|
||||
hints.EntryPoint(root)
|
||||
// themes
|
||||
themes.EntryPoint(root)
|
||||
// __pytest__
|
||||
pytest.EntryPoint(root)
|
||||
// __hold_till_enter__
|
||||
|
||||
@ -9,9 +9,6 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"kitty/tools/config"
|
||||
"kitty/tools/utils"
|
||||
"kitty/tools/utils/style"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
@ -21,11 +18,304 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"kitty/tools/cli"
|
||||
"kitty/tools/config"
|
||||
"kitty/tools/utils"
|
||||
"kitty/tools/utils/style"
|
||||
|
||||
"github.com/shirou/gopsutil/v3/process"
|
||||
"golang.org/x/exp/maps"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
var _ = fmt.Print
|
||||
|
||||
var AllColorSettingNames = map[string]bool{ // {{{
|
||||
// generated by gen-config.py do not edit
|
||||
// ALL_COLORS_START
|
||||
"active_border_color": true,
|
||||
"active_tab_background": true,
|
||||
"active_tab_foreground": true,
|
||||
"background": true,
|
||||
"bell_border_color": true,
|
||||
"color0": true,
|
||||
"color1": true,
|
||||
"color10": true,
|
||||
"color100": true,
|
||||
"color101": true,
|
||||
"color102": true,
|
||||
"color103": true,
|
||||
"color104": true,
|
||||
"color105": true,
|
||||
"color106": true,
|
||||
"color107": true,
|
||||
"color108": true,
|
||||
"color109": true,
|
||||
"color11": true,
|
||||
"color110": true,
|
||||
"color111": true,
|
||||
"color112": true,
|
||||
"color113": true,
|
||||
"color114": true,
|
||||
"color115": true,
|
||||
"color116": true,
|
||||
"color117": true,
|
||||
"color118": true,
|
||||
"color119": true,
|
||||
"color12": true,
|
||||
"color120": true,
|
||||
"color121": true,
|
||||
"color122": true,
|
||||
"color123": true,
|
||||
"color124": true,
|
||||
"color125": true,
|
||||
"color126": true,
|
||||
"color127": true,
|
||||
"color128": true,
|
||||
"color129": true,
|
||||
"color13": true,
|
||||
"color130": true,
|
||||
"color131": true,
|
||||
"color132": true,
|
||||
"color133": true,
|
||||
"color134": true,
|
||||
"color135": true,
|
||||
"color136": true,
|
||||
"color137": true,
|
||||
"color138": true,
|
||||
"color139": true,
|
||||
"color14": true,
|
||||
"color140": true,
|
||||
"color141": true,
|
||||
"color142": true,
|
||||
"color143": true,
|
||||
"color144": true,
|
||||
"color145": true,
|
||||
"color146": true,
|
||||
"color147": true,
|
||||
"color148": true,
|
||||
"color149": true,
|
||||
"color15": true,
|
||||
"color150": true,
|
||||
"color151": true,
|
||||
"color152": true,
|
||||
"color153": true,
|
||||
"color154": true,
|
||||
"color155": true,
|
||||
"color156": true,
|
||||
"color157": true,
|
||||
"color158": true,
|
||||
"color159": true,
|
||||
"color16": true,
|
||||
"color160": true,
|
||||
"color161": true,
|
||||
"color162": true,
|
||||
"color163": true,
|
||||
"color164": true,
|
||||
"color165": true,
|
||||
"color166": true,
|
||||
"color167": true,
|
||||
"color168": true,
|
||||
"color169": true,
|
||||
"color17": true,
|
||||
"color170": true,
|
||||
"color171": true,
|
||||
"color172": true,
|
||||
"color173": true,
|
||||
"color174": true,
|
||||
"color175": true,
|
||||
"color176": true,
|
||||
"color177": true,
|
||||
"color178": true,
|
||||
"color179": true,
|
||||
"color18": true,
|
||||
"color180": true,
|
||||
"color181": true,
|
||||
"color182": true,
|
||||
"color183": true,
|
||||
"color184": true,
|
||||
"color185": true,
|
||||
"color186": true,
|
||||
"color187": true,
|
||||
"color188": true,
|
||||
"color189": true,
|
||||
"color19": true,
|
||||
"color190": true,
|
||||
"color191": true,
|
||||
"color192": true,
|
||||
"color193": true,
|
||||
"color194": true,
|
||||
"color195": true,
|
||||
"color196": true,
|
||||
"color197": true,
|
||||
"color198": true,
|
||||
"color199": true,
|
||||
"color2": true,
|
||||
"color20": true,
|
||||
"color200": true,
|
||||
"color201": true,
|
||||
"color202": true,
|
||||
"color203": true,
|
||||
"color204": true,
|
||||
"color205": true,
|
||||
"color206": true,
|
||||
"color207": true,
|
||||
"color208": true,
|
||||
"color209": true,
|
||||
"color21": true,
|
||||
"color210": true,
|
||||
"color211": true,
|
||||
"color212": true,
|
||||
"color213": true,
|
||||
"color214": true,
|
||||
"color215": true,
|
||||
"color216": true,
|
||||
"color217": true,
|
||||
"color218": true,
|
||||
"color219": true,
|
||||
"color22": true,
|
||||
"color220": true,
|
||||
"color221": true,
|
||||
"color222": true,
|
||||
"color223": true,
|
||||
"color224": true,
|
||||
"color225": true,
|
||||
"color226": true,
|
||||
"color227": true,
|
||||
"color228": true,
|
||||
"color229": true,
|
||||
"color23": true,
|
||||
"color230": true,
|
||||
"color231": true,
|
||||
"color232": true,
|
||||
"color233": true,
|
||||
"color234": true,
|
||||
"color235": true,
|
||||
"color236": true,
|
||||
"color237": true,
|
||||
"color238": true,
|
||||
"color239": true,
|
||||
"color24": true,
|
||||
"color240": true,
|
||||
"color241": true,
|
||||
"color242": true,
|
||||
"color243": true,
|
||||
"color244": true,
|
||||
"color245": true,
|
||||
"color246": true,
|
||||
"color247": true,
|
||||
"color248": true,
|
||||
"color249": true,
|
||||
"color25": true,
|
||||
"color250": true,
|
||||
"color251": true,
|
||||
"color252": true,
|
||||
"color253": true,
|
||||
"color254": true,
|
||||
"color255": true,
|
||||
"color26": true,
|
||||
"color27": true,
|
||||
"color28": true,
|
||||
"color29": true,
|
||||
"color3": true,
|
||||
"color30": true,
|
||||
"color31": true,
|
||||
"color32": true,
|
||||
"color33": true,
|
||||
"color34": true,
|
||||
"color35": true,
|
||||
"color36": true,
|
||||
"color37": true,
|
||||
"color38": true,
|
||||
"color39": true,
|
||||
"color4": true,
|
||||
"color40": true,
|
||||
"color41": true,
|
||||
"color42": true,
|
||||
"color43": true,
|
||||
"color44": true,
|
||||
"color45": true,
|
||||
"color46": true,
|
||||
"color47": true,
|
||||
"color48": true,
|
||||
"color49": true,
|
||||
"color5": true,
|
||||
"color50": true,
|
||||
"color51": true,
|
||||
"color52": true,
|
||||
"color53": true,
|
||||
"color54": true,
|
||||
"color55": true,
|
||||
"color56": true,
|
||||
"color57": true,
|
||||
"color58": true,
|
||||
"color59": true,
|
||||
"color6": true,
|
||||
"color60": true,
|
||||
"color61": true,
|
||||
"color62": true,
|
||||
"color63": true,
|
||||
"color64": true,
|
||||
"color65": true,
|
||||
"color66": true,
|
||||
"color67": true,
|
||||
"color68": true,
|
||||
"color69": true,
|
||||
"color7": true,
|
||||
"color70": true,
|
||||
"color71": true,
|
||||
"color72": true,
|
||||
"color73": true,
|
||||
"color74": true,
|
||||
"color75": true,
|
||||
"color76": true,
|
||||
"color77": true,
|
||||
"color78": true,
|
||||
"color79": true,
|
||||
"color8": true,
|
||||
"color80": true,
|
||||
"color81": true,
|
||||
"color82": true,
|
||||
"color83": true,
|
||||
"color84": true,
|
||||
"color85": true,
|
||||
"color86": true,
|
||||
"color87": true,
|
||||
"color88": true,
|
||||
"color89": true,
|
||||
"color9": true,
|
||||
"color90": true,
|
||||
"color91": true,
|
||||
"color92": true,
|
||||
"color93": true,
|
||||
"color94": true,
|
||||
"color95": true,
|
||||
"color96": true,
|
||||
"color97": true,
|
||||
"color98": true,
|
||||
"color99": true,
|
||||
"cursor": true,
|
||||
"cursor_text_color": true,
|
||||
"foreground": true,
|
||||
"inactive_border_color": true,
|
||||
"inactive_tab_background": true,
|
||||
"inactive_tab_foreground": true,
|
||||
"macos_titlebar_color": true,
|
||||
"mark1_background": true,
|
||||
"mark1_foreground": true,
|
||||
"mark2_background": true,
|
||||
"mark2_foreground": true,
|
||||
"mark3_background": true,
|
||||
"mark3_foreground": true,
|
||||
"selection_background": true,
|
||||
"selection_foreground": true,
|
||||
"tab_bar_background": true,
|
||||
"tab_bar_margin_color": true,
|
||||
"url_color": true,
|
||||
"visual_bell_color": true,
|
||||
"wayland_titlebar_color": true, // ALL_COLORS_END
|
||||
} // }}}
|
||||
|
||||
type JSONMetadata struct {
|
||||
Etag string `json:"etag"`
|
||||
Timestamp string `json:"timestamp"`
|
||||
@ -233,6 +523,111 @@ func (self *Theme) load_code() (string, error) {
|
||||
return self.code, nil
|
||||
}
|
||||
|
||||
func (self *Theme) Code() (string, error) {
|
||||
return self.load_code()
|
||||
}
|
||||
|
||||
func patch_conf(text, theme_name string) string {
|
||||
addition := fmt.Sprintf("# BEGIN_KITTY_THEME\n# %s\ninclude current-theme.conf\n# END_KITTY_THEME", theme_name)
|
||||
pat := utils.MustCompile(`(?ms)^# BEGIN_KITTY_THEME.+?# END_KITTY_THEME`)
|
||||
replaced := false
|
||||
ntext := pat.ReplaceAllStringFunc(text, func(string) string {
|
||||
replaced = true
|
||||
return addition
|
||||
})
|
||||
if !replaced {
|
||||
if text != "" {
|
||||
text += "\n\n"
|
||||
}
|
||||
ntext = text + addition
|
||||
}
|
||||
pat = utils.MustCompile(fmt.Sprintf(`(?m)^\s*(%s)\b`, strings.Join(maps.Keys(AllColorSettingNames), "|")))
|
||||
return pat.ReplaceAllString(ntext, `# $1`)
|
||||
}
|
||||
func is_kitty_gui_cmdline(cmd ...string) bool {
|
||||
if len(cmd) == 0 {
|
||||
return false
|
||||
}
|
||||
if filepath.Base(cmd[0]) != "kitty" {
|
||||
return false
|
||||
}
|
||||
if len(cmd) == 1 {
|
||||
return true
|
||||
}
|
||||
s := cmd[1][:1]
|
||||
switch s {
|
||||
case `@`:
|
||||
return false
|
||||
case `+`:
|
||||
if cmd[1] == `+` {
|
||||
return len(cmd) > 2 && cmd[2] == `open`
|
||||
}
|
||||
return cmd[1] == `+open`
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
type ReloadDestination string
|
||||
|
||||
const (
|
||||
RELOAD_IN_PARENT ReloadDestination = "parent"
|
||||
RELOAD_IN_ALL = "all"
|
||||
)
|
||||
|
||||
func reload_config(reload_in ReloadDestination) bool {
|
||||
switch reload_in {
|
||||
case RELOAD_IN_PARENT:
|
||||
if pid, err := strconv.Atoi(os.Getenv("KITTY_PID")); err == nil {
|
||||
if p, err := process.NewProcess(int32(pid)); err == nil {
|
||||
if c, err := p.CmdlineSlice(); err == nil && is_kitty_gui_cmdline(c...) {
|
||||
return p.SendSignal(unix.SIGUSR1) == nil
|
||||
}
|
||||
}
|
||||
}
|
||||
case RELOAD_IN_ALL:
|
||||
if all, err := process.Processes(); err == nil {
|
||||
for _, p := range all {
|
||||
if c, err := p.CmdlineSlice(); err == nil && is_kitty_gui_cmdline(c...) {
|
||||
p.SendSignal(unix.SIGUSR1)
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (self *Theme) SaveInConf(config_dir, reload_in, config_file_name string) (err error) {
|
||||
os.MkdirAll(config_dir, 0o755)
|
||||
path := filepath.Join(config_dir, `current-theme.conf`)
|
||||
code, err := self.Code()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = utils.AtomicUpdateFile(path, utils.UnsafeStringToBytes(code), 0o644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
confpath := filepath.Join(config_dir, config_file_name)
|
||||
if q, err := filepath.EvalSymlinks(confpath); err == nil {
|
||||
confpath = q
|
||||
}
|
||||
raw, err := os.ReadFile(confpath)
|
||||
if err != nil && !errors.Is(err, fs.ErrNotExist) {
|
||||
return err
|
||||
}
|
||||
nraw := patch_conf(utils.UnsafeBytesToString(raw), self.metadata.Name)
|
||||
if len(raw) > 0 {
|
||||
os.WriteFile(confpath+".bak", raw, 0o600)
|
||||
}
|
||||
err = utils.AtomicUpdateFile(confpath, utils.UnsafeStringToBytes(nraw), 0o600)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
reload_config(ReloadDestination(reload_in))
|
||||
return
|
||||
}
|
||||
|
||||
func (self *Theme) Settings() (map[string]string, error) {
|
||||
if self.zip_reader != nil {
|
||||
code, err := self.load_code()
|
||||
@ -367,7 +762,7 @@ func (self *Themes) add_from_zip_file(zippath string) (io.Closer, error) {
|
||||
return nil, err
|
||||
}
|
||||
name_map := make(map[string]*zip.File, len(r.File))
|
||||
var themes []ThemeMetadata
|
||||
var themes []*ThemeMetadata
|
||||
theme_dir := ""
|
||||
for _, file := range r.File {
|
||||
name_map[file.Name] = file
|
||||
@ -395,7 +790,7 @@ func (self *Themes) add_from_zip_file(zippath string) (io.Closer, error) {
|
||||
key := path.Join(theme_dir, theme.Filepath)
|
||||
f := name_map[key]
|
||||
if f != nil {
|
||||
t := Theme{metadata: &theme, zip_reader: f}
|
||||
t := Theme{metadata: theme, zip_reader: f}
|
||||
self.name_map[theme.Name] = &t
|
||||
}
|
||||
}
|
||||
@ -403,7 +798,16 @@ func (self *Themes) add_from_zip_file(zippath string) (io.Closer, error) {
|
||||
}
|
||||
|
||||
func (self *Themes) ThemeByName(name string) *Theme {
|
||||
return self.name_map[name]
|
||||
ans := self.name_map[name]
|
||||
if ans == nil {
|
||||
q := strings.ToLower(name)
|
||||
for k, t := range self.name_map {
|
||||
if strings.ToLower(k) == q {
|
||||
return t
|
||||
}
|
||||
}
|
||||
}
|
||||
return ans
|
||||
}
|
||||
|
||||
func LoadThemes(cache_age time.Duration) (ans *Themes, closer io.Closer, err error) {
|
||||
@ -427,3 +831,31 @@ func ThemeFromFile(path string) (*Theme, error) {
|
||||
ans := &Themes{name_map: make(map[string]*Theme)}
|
||||
return ans.AddFromFile(path)
|
||||
}
|
||||
|
||||
func GetThemeNames(cache_age time.Duration) (ans []string, err error) {
|
||||
themes, closer, err := LoadThemes(cache_age)
|
||||
if err != nil {
|
||||
if errors.Is(err, ErrNoCacheFound) {
|
||||
return []string{"Default"}, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
defer closer.Close()
|
||||
for name := range themes.name_map {
|
||||
ans = append(ans, name)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func CompleteThemes(completions *cli.Completions, word string, arg_num int) {
|
||||
names, err := GetThemeNames(-1)
|
||||
if err != nil {
|
||||
mg := completions.AddMatchGroup("Themes")
|
||||
for _, theme_name := range names {
|
||||
theme_name = strings.TrimSpace(theme_name)
|
||||
if theme_name != "" && strings.HasPrefix(theme_name, word) {
|
||||
mg.AddMatch(theme_name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user