More work on porting hints

This commit is contained in:
Kovid Goyal 2023-03-10 06:58:10 +05:30
parent 5b3f5dd02d
commit 2e1eebd998
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
3 changed files with 107 additions and 20 deletions

View File

@ -124,8 +124,8 @@ func main(_ *cli.Command, o *Options, args []string) (rc int, err error) {
tui.ReportError(fmt.Errorf("Extra command line arguments present: %s", strings.Join(args, " "))) tui.ReportError(fmt.Errorf("Extra command line arguments present: %s", strings.Join(args, " ")))
return 1, nil return 1, nil
} }
text := parse_input(utils.UnsafeBytesToString(stdin)) input_text := parse_input(utils.UnsafeBytesToString(stdin))
all_marks, index_map, err := find_marks(text, o) text, all_marks, index_map, err := find_marks(input_text, o)
if err != nil { if err != nil {
tui.ReportError(err) tui.ReportError(err)
return 1, nil return 1, nil
@ -141,7 +141,6 @@ func main(_ *cli.Command, o *Options, args []string) (rc int, err error) {
alphabet = DEFAULT_HINT_ALPHABET alphabet = DEFAULT_HINT_ALPHABET
} }
ignore_mark_indices := utils.NewSet[int](8) ignore_mark_indices := utils.NewSet[int](8)
_, _, _ = all_marks, index_map, ignore_mark_indices
window_title := o.WindowTitle window_title := o.WindowTitle
if window_title == "" { if window_title == "" {
switch o.Type { switch o.Type {
@ -173,30 +172,31 @@ func main(_ *cli.Command, o *Options, args []string) (rc int, err error) {
hint_style := fctx.SprintFunc(fmt.Sprintf("fg=%s bg=%s bold", o.HintsForegroundColor, o.HintsBackgroundColor)) 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)) text_style := fctx.SprintFunc(fmt.Sprintf("fg=bright-%s bold", o.HintsTextColor))
highlight_mark := func(m *Mark) string { highlight_mark := func(m *Mark, mark_text string) string {
hint := encode_hint(m.Index, alphabet) hint := encode_hint(m.Index, alphabet)
if current_input != "" && !strings.HasPrefix(hint, current_input) { if current_input != "" && !strings.HasPrefix(hint, current_input) {
return faint(text) return faint(mark_text)
} }
hint = hint[len(current_input):] hint = hint[len(current_input):]
if hint == "" { if hint == "" {
hint = " " hint = " "
} }
text = text[len(hint):] mark_text = mark_text[len(hint):]
return hint_style(hint) + text_style(text) return hint_style(hint) + text_style(mark_text)
} }
render := func() string { render := func() string {
ans := text
for i := len(all_marks) - 1; i >= 0; i-- { for i := len(all_marks) - 1; i >= 0; i-- {
mark := &all_marks[i] mark := &all_marks[i]
if ignore_mark_indices.Has(mark.Index) { if ignore_mark_indices.Has(mark.Index) {
continue continue
} }
mtext := highlight_mark(mark) mtext := highlight_mark(mark, ans[mark.Start:mark.End])
text = text[:mark.Start] + mtext + text[mark.End:] ans = ans[:mark.Start] + mtext + ans[mark.End:]
} }
text = strings.ReplaceAll(text, "\x00", "") ans = strings.ReplaceAll(ans, "\x00", "")
return strings.TrimRightFunc(strings.NewReplacer("\r", "\r\n", "\n", "\r\n").Replace(text), unicode.IsSpace) return strings.TrimRightFunc(strings.NewReplacer("\r", "\r\n", "\n", "\r\n").Replace(ans), unicode.IsSpace)
} }
draw_screen := func() { draw_screen := func() {
@ -208,6 +208,10 @@ func main(_ *cli.Command, o *Options, args []string) (rc int, err error) {
lp.ClearScreen() lp.ClearScreen()
lp.QueueWriteString(current_text) lp.QueueWriteString(current_text)
} }
reset := func() {
current_input = ""
current_text = ""
}
lp.OnInitialize = func() (string, error) { lp.OnInitialize = func() (string, error) {
lp.SendOverlayReady() lp.SendOverlayReady()
@ -225,7 +229,89 @@ func main(_ *cli.Command, o *Options, args []string) (rc int, err error) {
draw_screen() draw_screen()
return nil return nil
} }
lp.OnText = func(text string, _, _ bool) error {
changed := false
for _, ch := range text {
if strings.ContainsRune(alphabet, ch) {
current_input += string(ch)
changed = true
}
}
if changed {
matches := []*Mark{}
for idx, m := range index_map {
if eh := encode_hint(idx, alphabet); strings.HasPrefix(eh, current_input) {
matches = append(matches, m)
}
}
if len(matches) == 1 {
chosen = append(chosen, matches[0])
if o.Multiple {
ignore_mark_indices.Add(matches[0].Index)
reset()
} else {
lp.Quit(0)
return nil
}
}
current_text = ""
draw_screen()
}
return nil
}
lp.OnKeyEvent = func(ev *loop.KeyEvent) error {
if ev.MatchesPressOrRepeat("backspace") {
ev.Handled = true
r := []rune(current_input)
if len(r) > 0 {
r = r[:len(r)-1]
current_input = string(r)
current_text = ""
}
draw_screen()
} else if ev.MatchesPressOrRepeat("enter") || ev.MatchesPressOrRepeat("space") {
ev.Handled = true
if current_input != "" {
idx := decode_hint(current_input, alphabet)
if m := index_map[idx]; m != nil {
chosen = append(chosen, m)
ignore_mark_indices.Add(idx)
if o.Multiple {
reset()
draw_screen()
} else {
lp.Quit(0)
}
} else {
current_input = ""
current_text = ""
draw_screen()
}
}
} else if ev.MatchesPressOrRepeat("esc") {
if o.Multiple {
lp.Quit(1)
} else {
lp.Quit(0)
}
}
return nil
}
err = lp.Run()
if err != nil {
return 1, err
}
ds := lp.DeathSignalName()
if ds != "" {
fmt.Println("Killed by signal: ", ds)
lp.KillIfSignalled()
return 1, nil
}
if lp.ExitCode() != 0 {
return lp.ExitCode(), nil
}
result.Match = make([]string, len(chosen)) result.Match = make([]string, len(chosen))
result.Groupdicts = make([]map[string]string, len(chosen)) result.Groupdicts = make([]map[string]string, len(chosen))
for i, m := range chosen { for i, m := range chosen {

View File

@ -322,31 +322,32 @@ func (self *ErrNoMatches) Error() string {
return fmt.Sprintf("No %s found", none_of) return fmt.Sprintf("No %s found", none_of)
} }
func find_marks(text string, opts *Options) (ans []Mark, index_map map[int]*Mark, err error) { func find_marks(text string, opts *Options) (sanitized_text string, ans []Mark, index_map map[int]*Mark, err error) {
text, hyperlinks := process_escape_codes(text) sanitized_text, hyperlinks := process_escape_codes(text)
pattern, post_processors, group_processors := functions_for(opts) pattern, post_processors, group_processors := functions_for(opts)
if opts.Type == "hyperlink" { if opts.Type == "hyperlink" {
ans = hyperlinks ans = hyperlinks
} else { } else {
r, err := regexp.Compile(pattern) r, err := regexp.Compile(pattern)
if err != nil { if err != nil {
return nil, nil, fmt.Errorf("Failed to compile the regex pattern: %#v with error: %w", pattern, err) return "", nil, nil, fmt.Errorf("Failed to compile the regex pattern: %#v with error: %w", pattern, err)
} }
ans = mark(r, post_processors, group_processors, text, opts) ans = mark(r, post_processors, group_processors, sanitized_text, opts)
} }
if len(ans) == 0 { if len(ans) == 0 {
return nil, nil, &ErrNoMatches{Type: opts.Type} return "", nil, nil, &ErrNoMatches{Type: opts.Type}
} }
largest_index := ans[len(ans)-1].Index largest_index := ans[len(ans)-1].Index
offset := utils.Max(0, opts.HintsOffset) offset := utils.Max(0, opts.HintsOffset)
index_map = make(map[int]*Mark, len(ans)) index_map = make(map[int]*Mark, len(ans))
for _, m := range ans { for i := range ans {
m := &ans[i]
if opts.Ascending { if opts.Ascending {
m.Index += offset m.Index += offset
} else { } else {
m.Index = largest_index - m.Index + offset m.Index = largest_index - m.Index + offset
} }
index_map[m.Index] = &m index_map[m.Index] = m
} }
return return
} }

View File

@ -21,7 +21,7 @@ func TestHintMarking(t *testing.T) {
cols := 20 cols := 20
r := func(text string, url ...string) { r := func(text string, url ...string) {
ptext := convert_text(text, cols) ptext := convert_text(text, cols)
marks, _, err := find_marks(ptext, opts) _, marks, _, err := find_marks(ptext, opts)
if err != nil { if err != nil {
var e *ErrNoMatches var e *ErrNoMatches
if len(url) != 0 || !errors.As(err, &e) { if len(url) != 0 || !errors.As(err, &e) {
@ -51,7 +51,7 @@ func TestHintMarking(t *testing.T) {
opts.Type = "linenum" opts.Type = "linenum"
m := func(text, path string, line int) { m := func(text, path string, line int) {
ptext := convert_text(text, cols) ptext := convert_text(text, cols)
marks, _, err := find_marks(ptext, opts) _, marks, _, err := find_marks(ptext, opts)
if err != nil { if err != nil {
t.Fatalf("%#v failed with error: %s", text, err) t.Fatalf("%#v failed with error: %s", text, err)
} }