From 2aa9187428f34bf97e9d3cca7d7d37d89d198d71 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 8 Mar 2023 20:41:46 +0530 Subject: [PATCH] More work on porting hints --- tools/cmd/hints/main.go | 89 +++++++++++++++++++++++++++++++++++ tools/cmd/hints/marks_test.go | 13 +++++ 2 files changed, 102 insertions(+) create mode 100644 tools/cmd/hints/marks_test.go diff --git a/tools/cmd/hints/main.go b/tools/cmd/hints/main.go index 4066cd9c8..8d7393417 100644 --- a/tools/cmd/hints/main.go +++ b/tools/cmd/hints/main.go @@ -8,12 +8,14 @@ import ( "os" "strconv" "strings" + "unicode" "kitty/tools/cli" "kitty/tools/tty" "kitty/tools/tui" "kitty/tools/tui/loop" "kitty/tools/utils" + "kitty/tools/utils/style" "kitty/tools/wcswidth" ) @@ -85,6 +87,28 @@ type Result struct { Cwd string `json:"cwd"` } +func encode_hint(num int, alphabet string) (res string) { + runes := []rune(alphabet) + d := len(runes) + for res == "" || num > 0 { + res = string(runes[num%d]) + res + num /= d + } + return +} + +func decode_hint(x string, alphabet string) (ans int) { + base := len(alphabet) + index_map := make(map[rune]int, len(alphabet)) + for i, c := range alphabet { + index_map[c] = i + } + for _, char := range x { + ans = ans*base + index_map[char] + } + return +} + func main(_ *cli.Command, o *Options, args []string) (rc int, err error) { output := tui.KittenOutputSerializer() if tty.IsTerminal(os.Stdin.Fd()) { @@ -127,22 +151,87 @@ func main(_ *cli.Command, o *Options, args []string) (rc int, err error) { window_title = "Choose text" } } + current_text := "" + current_input := "" + match_suffix := "" + switch o.AddTrailingSpace { + case "always": + match_suffix = " " + case "never": + default: + if o.Multiple { + match_suffix = " " + } + } + chosen := []*Mark{} lp, err := loop.New(loop.NoAlternateScreen) // no alternate screen reduces flicker on exit if err != nil { return } + fctx := style.Context{AllowEscapeCodes: true} + faint := fctx.SprintFunc("dim") + hint_style := fctx.SprintFunc(fmt.Sprintf("fg=%s bg=%s bold", o.HintsForegroundColor, o.HintsBackgroundColor)) + text_style := fctx.SprintFunc(fmt.Sprintf("fg=bright-%s bold", o.HintsTextColor)) + + highlight_mark := func(m *Mark) string { + hint := encode_hint(m.Index, alphabet) + if current_input != "" && !strings.HasPrefix(hint, current_input) { + return faint(text) + } + hint = hint[len(current_input):] + if hint == "" { + hint = " " + } + text = text[len(hint):] + return hint_style(hint) + text_style(text) + } + + render := func() string { + for i := len(all_marks) - 1; i >= 0; i-- { + mark := &all_marks[i] + if ignore_mark_indices.Has(mark.Index) { + continue + } + mtext := highlight_mark(mark) + text = text[:mark.Start] + mtext + text[mark.End:] + } + text = strings.ReplaceAll(text, "\x00", "") + return strings.TrimRightFunc(strings.NewReplacer("\r", "\r\n", "\n", "\r\n").Replace(text), unicode.IsSpace) + } + + draw_screen := func() { + lp.StartAtomicUpdate() + defer lp.EndAtomicUpdate() + if current_text == "" { + current_text = render() + } + lp.ClearScreen() + lp.QueueWriteString(current_text) + } + lp.OnInitialize = func() (string, error) { lp.SendOverlayReady() lp.SetCursorVisible(false) lp.SetWindowTitle(window_title) lp.AllowLineWrapping(false) + draw_screen() return "", nil } lp.OnFinalize = func() string { lp.SetCursorVisible(true) return "" } + lp.OnResize = func(old_size, new_size loop.ScreenSize) error { + draw_screen() + return nil + } + result.Match = make([]string, len(chosen)) + result.Groupdicts = make([]map[string]string, len(chosen)) + for i, m := range chosen { + result.Match[i] = m.Text + match_suffix + result.Groupdicts[i] = m.Groupdict + } output(result) return } diff --git a/tools/cmd/hints/marks_test.go b/tools/cmd/hints/marks_test.go new file mode 100644 index 000000000..67b3dcd2d --- /dev/null +++ b/tools/cmd/hints/marks_test.go @@ -0,0 +1,13 @@ +// License: GPLv3 Copyright: 2023, Kovid Goyal, + +package hints + +import ( + "fmt" + "testing" +) + +var _ = fmt.Print + +func TestHintMarking(t *testing.T) { +}