Skip to content

Commit 653f3ed

Browse files
author
Jeremie Dimino
committed
Add next-search
Closes #22
1 parent a27e7df commit 653f3ed

File tree

2 files changed

+96
-51
lines changed

2 files changed

+96
-51
lines changed

src/lTerm_read_line.ml

Lines changed: 94 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ type action =
6363
| Accept
6464
| Clear_screen
6565
| Prev_search
66+
| Next_search
6667
| Cancel_search
6768
| Break
6869
| Suspend
@@ -81,6 +82,7 @@ let doc_of_action = function
8182
| Accept -> "accept the current input."
8283
| Clear_screen -> "clear the screen."
8384
| Prev_search -> "search backward in the history."
85+
| Next_search -> "search forward in the history."
8486
| Cancel_search -> "cancel search mode."
8587
| Break -> "cancel edition."
8688
| Suspend -> "suspend edition."
@@ -98,6 +100,7 @@ let actions = [
98100
Accept, "accept";
99101
Clear_screen, "clear-screen";
100102
Prev_search, "prev-search";
103+
Next_search, "next-search";
101104
Cancel_search, "cancel-search";
102105
Break, "break";
103106
Suspend, "suspend";
@@ -164,6 +167,7 @@ let () =
164167
bind [{ control = true; meta = false; shift = false; code = Char(UChar.of_char 'm') }] [Accept];
165168
bind [{ control = true; meta = false; shift = false; code = Char(UChar.of_char 'l') }] [Clear_screen];
166169
bind [{ control = true; meta = false; shift = false; code = Char(UChar.of_char 'r') }] [Prev_search];
170+
bind [{ control = true; meta = false; shift = false; code = Char(UChar.of_char 's') }] [Next_search];
167171
bind [{ control = true; meta = false; shift = false; code = Char(UChar.of_char 'd') }] [Interrupt_or_delete_next_char];
168172
bind [{ control = false; meta = true; shift = false; code = Char(UChar.of_char 'p') }] [History_prev];
169173
bind [{ control = false; meta = true; shift = false; code = Char(UChar.of_char 'n') }] [History_next];
@@ -217,6 +221,14 @@ let no_completion = {
217221
count = 0;
218222
}
219223

224+
type direction = Forward | Backward
225+
226+
type search_status =
227+
{ before : Zed_utf8.t list
228+
; after : Zed_utf8.t list
229+
; match_ : (Zed_utf8.t * int) option
230+
}
231+
220232
class virtual ['a] engine ?(history = []) ?(clipboard = LTerm_edit.clipboard) ?(macro = macro) () =
221233
let edit : unit Zed_edit.t = Zed_edit.create ~clipboard () in
222234
let context = Zed_edit.context edit (Zed_edit.new_cursor edit) in
@@ -300,41 +312,86 @@ object(self)
300312
(* The event which search for the string in the history. *)
301313
val mutable search_event = E.never
302314

303-
(* The result of the search. If the search was successful it
304-
contains the matched history entry, the position of the substring
305-
in this entry and the rest of the history. *)
306-
val mutable search_result = None
315+
val mutable search_status = None
307316

308317
initializer
309-
search_event <- E.map (fun _ -> search_result <- None; self#search) (E.when_ (S.map (fun mode -> mode = Search) mode) (Zed_edit.changes edit))
310-
311-
method private search =
312-
let input = Zed_rope.to_string (Zed_edit.text edit) in
313-
let rec loop = function
314-
| [] ->
315-
search_result <- None;
318+
let reset_search _ =
319+
search_status <- None;
320+
self#search Backward
321+
in
322+
search_event <-
323+
E.map reset_search
324+
(E.when_ (S.map (fun mode -> mode = Search) mode)
325+
(Zed_edit.changes edit))
326+
327+
method private search direction =
328+
let do_search direction =
329+
let set_status other_entries entries match_ =
330+
let before, after =
331+
match direction with
332+
| Backward -> (other_entries, entries)
333+
| Forward -> (entries, other_entries)
334+
in
335+
search_status <- Some { before; after; match_ }
336+
in
337+
let input = Zed_rope.to_string (Zed_edit.text edit) in
338+
let rec loop other_entries entries =
339+
match entries with
340+
| [] ->
341+
set_status other_entries entries None;
316342
set_message (Some(LTerm_text.of_string "Reverse search: not found"))
317-
| entry :: rest ->
343+
| entry :: rest ->
318344
match search_string entry input with
319-
| Some pos -> begin
320-
match search_result with
321-
| Some(entry', _, _) when entry = entry' ->
322-
loop rest
323-
| _ ->
324-
search_result <- Some(entry, pos, rest);
325-
let txt = LTerm_text.of_string entry in
326-
for i = pos to pos + Zed_rope.length (Zed_edit.text edit) - 1 do
327-
let ch, style = txt.(i) in
328-
txt.(i) <- (ch, { style with underline = Some true })
329-
done;
330-
set_message (Some(Array.append (LTerm_text.of_string "Reverse search: ") txt))
331-
end
332-
| None ->
333-
loop rest
345+
| Some pos -> begin
346+
match search_status with
347+
| Some { match_ = Some (entry', _) } when entry = entry' ->
348+
loop (entry :: other_entries) rest
349+
| _ ->
350+
set_status other_entries rest (Some (entry, pos));
351+
let txt = LTerm_text.of_string entry in
352+
for i = pos to pos + Zed_rope.length (Zed_edit.text edit) - 1 do
353+
let ch, style = txt.(i) in
354+
txt.(i) <- (ch, { style with underline = Some true })
355+
done;
356+
set_message
357+
(Some (Array.append (LTerm_text.of_string "Reverse search: ") txt))
358+
end
359+
| None ->
360+
loop (entry :: other_entries) rest
361+
in
362+
match search_status with
363+
| None ->
364+
let hist = fst (S.value history) in
365+
loop []
366+
(match direction with
367+
| Backward -> hist
368+
| Forward -> List.rev hist)
369+
| Some { before; after; match_ } ->
370+
let other_entries, entries =
371+
match direction with
372+
| Backward -> (before, after)
373+
| Forward -> (after, before)
374+
in
375+
let other_entries =
376+
match match_ with
377+
| None -> other_entries
378+
| Some (entry, _) -> entry :: other_entries
379+
in
380+
loop other_entries entries
334381
in
335-
match search_result with
336-
| Some(entry, pos, rest) -> loop rest
337-
| None -> loop (fst (S.value history))
382+
match S.value mode with
383+
| Search -> do_search direction
384+
| Edition ->
385+
let text = Zed_edit.text edit in
386+
Zed_edit.goto context 0;
387+
Zed_edit.remove context (Zed_rope.length text);
388+
let prev, next = S.value history in
389+
set_history (Zed_rope.to_string text :: (List.rev_append next prev), []);
390+
search_status <- None;
391+
set_mode Search;
392+
do_search direction
393+
| _ ->
394+
()
338395

339396
method insert ch =
340397
Zed_edit.insert context (Zed_rope.singleton ch)
@@ -345,13 +402,13 @@ object(self)
345402
| (Complete | Complete_bar | Accept) when S.value mode = Search -> begin
346403
set_mode Edition;
347404
set_message None;
348-
match search_result with
349-
| Some(entry, pos, rest) ->
350-
search_result <- None;
405+
match search_status with
406+
| Some { match_ = Some (entry, pos) } ->
407+
search_status <- None;
351408
Zed_edit.goto context 0;
352409
Zed_edit.remove context (Zed_rope.length (Zed_edit.text edit));
353410
Zed_edit.insert context (Zed_rope.of_string entry)
354-
| None ->
411+
| Some { match_ = None } | None ->
355412
()
356413
end
357414

@@ -422,22 +479,8 @@ object(self)
422479
Zed_edit.insert context (Zed_rope.of_string line)
423480
end
424481

425-
| Prev_search -> begin
426-
match S.value mode with
427-
| Search ->
428-
self#search
429-
| Edition ->
430-
let text = Zed_edit.text edit in
431-
Zed_edit.goto context 0;
432-
Zed_edit.remove context (Zed_rope.length text);
433-
let prev, next = S.value history in
434-
set_history (Zed_rope.to_string text :: (List.rev_append next prev), []);
435-
search_result <- None;
436-
set_mode Search;
437-
self#search
438-
| _ ->
439-
()
440-
end
482+
| Prev_search -> self#search Backward
483+
| Next_search -> self#search Forward
441484

442485
| Cancel_search ->
443486
if S.value mode = Search then begin
@@ -580,7 +623,7 @@ class read_password () = object(self)
580623
method show_box = false
581624

582625
method send_action = function
583-
| Prev_search -> ()
626+
| Prev_search | Next_search -> ()
584627
| action -> super#send_action action
585628
end
586629

src/lTerm_read_line.mli

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ type action =
7171
(** Clear the screen. *)
7272
| Prev_search
7373
(** Search backward in the history. *)
74+
| Next_search
75+
(** Search forward in the history. *)
7476
| Cancel_search
7577
(** Cancel search mode. *)
7678
| Break

0 commit comments

Comments
 (0)