Implement parsing of map

This commit is contained in:
Kovid Goyal 2023-03-15 22:07:44 +05:30
parent e4fbcb707f
commit 5329546f21
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
4 changed files with 146 additions and 1 deletions

View File

@ -478,10 +478,49 @@ def go_type_data(parser_func: ParserFuncType, ctype: str, is_multiple: bool = Fa
return {int: 'int64', str: 'string', float: 'float64'}[rettype], f'{p}(val)'
mod_map = {
"shift": "shift",
"": "shift",
"alt": "alt",
"option": "alt",
"opt": "alt",
"": "alt",
"super": "super",
"command": "super",
"cmd": "super",
"": "super",
"control": "ctrl",
"ctrl": "ctrl",
"": "ctrl",
"hyper": "hyper",
"meta": "meta",
"num_lock": "num_lock",
"caps_lock": "caps_lock",
}
def normalize_shortcut(spec: str) -> str:
if spec.endswith('+'):
spec = spec[:-1] + 'plus'
parts = spec.lower().split('+')
key = parts[-1]
if len(parts) == 1:
return key
mods = parts[:-1]
return '+'.join(mod_map.get(x, x) for x in mods) + '+' + key
def normalize_shortcuts(spec: str) -> Iterator[str]:
spec = spec.replace('++', '+plus')
spec = re.sub(r'([^+])>', '\\1\0', spec)
for x in spec.split('\0'):
yield normalize_shortcut(x)
def gen_go_code(defn: Definition) -> str:
lines = ['import "fmt"', 'import "strconv"', 'import "kitty/tools/config"', 'import "kitty/tools/utils/style"',
'var _ = fmt.Println', 'var _ = config.StringToBool', 'var _ = strconv.Atoi', 'var _ = style.ParseColor']
a = lines.append
keyboard_shortcuts = tuple(defn.iter_all_maps())
choices = {}
go_types = {}
go_parsers = {}
@ -509,6 +548,8 @@ def gen_go_code(defn: Definition) -> str:
a(f'{name} []{gotype}')
else:
a(f'{name} {gotype}')
if keyboard_shortcuts:
a('KeyboardShortcuts []*config.KeyAction')
a('}')
def cval(x: str) -> str:
@ -540,6 +581,16 @@ def cval(x: str) -> str:
else:
dval = repr(d)
a(f'{name}: {dval},')
if keyboard_shortcuts:
a('KeyboardShortcuts: []*config.KeyAction{')
for sc in keyboard_shortcuts:
aname, aargs = map(serialize_as_go_string, sc.action_def.partition(' ')[::2])
a('{'f'Name: "{aname}", Args: "{aargs}", Normalized_keys: []string''{')
ns = normalize_shortcuts(sc.key_text)
a(', '.join(f'"{serialize_as_go_string(x)}"' for x in ns) + ',')
a('}''},')
a('},')
a('}''}')
for oname, choice_vals in choices.items():
@ -582,6 +633,11 @@ def cval(x: str) -> str:
a(f'c.{oname} = append(c.{oname}, temp_val...)')
else:
a(f'c.{oname} = temp_val')
if keyboard_shortcuts:
a('case "map":')
a('tempsc, err := config.ParseMap(val)')
a('if err != nil { return fmt.Errorf("Failed to parse map = %#v with error: %w", val, err) }')
a('c.KeyboardShortcuts = append(c.KeyboardShortcuts, tempsc)')
a('}')
a('return}')
return '\n'.join(lines)

View File

@ -9,10 +9,11 @@ import (
"fmt"
"io"
"io/fs"
"kitty/tools/utils"
"os"
"path/filepath"
"strings"
"kitty/tools/utils"
)
var _ = fmt.Print

View File

@ -5,6 +5,7 @@ package config
import (
"fmt"
"kitty/tools/utils"
"regexp"
"strconv"
"strings"
)
@ -183,3 +184,72 @@ func StringLiteral(val string) (string, error) {
}
return ans.String(), nil
}
var ModMap = (&utils.Once[map[string]string]{Run: func() map[string]string {
return map[string]string{
"shift": "shift",
"⇧": "shift",
"alt": "alt",
"option": "alt",
"opt": "alt",
"⌥": "alt",
"super": "super",
"command": "super",
"cmd": "super",
"⌘": "super",
"control": "ctrl",
"ctrl": "ctrl",
"⌃": "ctrl",
"hyper": "hyper",
"meta": "meta",
"num_lock": "num_lock",
"caps_lock": "caps_lock",
}
}}).Get
var ShortcutSpecPat = (&utils.Once[*regexp.Regexp]{Run: func() *regexp.Regexp {
return regexp.MustCompile(`([^+])>`)
}}).Get
func NormalizeShortcut(spec string) string {
parts := strings.Split(strings.ToLower(spec), "+")
key := parts[len(parts)-1]
if len(parts) == 1 {
return key
}
mods := parts[:len(parts)-1]
mmap := ModMap()
mods = utils.Map(func(x string) string {
ans := mmap[x]
if ans == "" {
ans = x
}
return ans
}, mods)
utils.Sort(mods, func(a, b string) bool { return a < b })
return strings.Join(mods, "+") + "+" + key
}
func NormalizeShortcuts(spec string) []string {
if strings.HasSuffix(spec, "+") {
spec = spec[:len(spec)-1] + "plus"
}
spec = strings.ReplaceAll(spec, "++", "+plus")
spec = ShortcutSpecPat().ReplaceAllString(spec, "$1\x00")
return utils.Map(NormalizeShortcut, strings.Split(spec, "\x00"))
}
type KeyAction struct {
Normalized_keys []string
Name string
Args string
}
func ParseMap(val string) (*KeyAction, error) {
spec, action, found := strings.Cut(val, " ")
if !found {
return nil, fmt.Errorf("No action specified for shortcut %s", val)
}
action_name, action_args, _ := strings.Cut(action, " ")
return &KeyAction{Name: action_name, Args: action_args, Normalized_keys: NormalizeShortcuts(spec)}, nil
}

View File

@ -4,7 +4,10 @@ package config
import (
"fmt"
"strings"
"testing"
"github.com/google/go-cmp/cmp"
)
var _ = fmt.Print
@ -24,3 +27,18 @@ func TestStringLiteralParsing(t *testing.T) {
}
}
}
func TestNormalizeShortcuts(t *testing.T) {
for q, expected_ := range map[string]string{
`a`: `a`,
`+`: `plus`,
`cmd+b>opt+>`: `super+b alt+>`,
`cmd+>>opt+>`: `super+> alt+>`,
} {
expected := strings.Split(expected_, " ")
actual := NormalizeShortcuts(q)
if diff := cmp.Diff(expected, actual); diff != "" {
t.Fatalf("failed with input: %#v\n%s", q, diff)
}
}
}