Auto-completion specifications
Warning, work in progress.
Table of Contents
|
I use labels/suggestions/alternatives indiscriminately.
When an option is not marked as choosen or dismissed, it means the choice hasn't been made yet!
TODO: Survey what is done in existing software (Symbos shell, fish shell, …), to leverage muscle memory and prevent frustration.
UI Wise
Requirements
- Non intrusive.
- ReqA. Musn't slow down the editor.
- ReqB. When no special shortcut is used, it must behave like without auto-completion (no automatic injection).
- ReqA. Musn't slow down the editor.
- Intuitive.
- ReqC. All labels starting with typed letters must be available.
- ReqD. Typing more letters shouldn't discard suggestions that still match! (no chrome browser bar weird behavior).
- ReqC. All labels starting with typed letters must be available.
Non-goals
- AI powered suggestions.
How to find the alternatives
Option 1: Beginning of word.
When typing some letters, would only return labels starting with those letters.
Option 2: Fuzzy search.
Would return labels matchings the letters in the same order.
E.g. `gem -> generate_mesh.``
- Pro: Handy when there are a lot of labels with the same prefix.
- Con: May bring too many answers, making the selection process more painful.
Option 3: Restricted fuzzy search.
Like 2, but only works with initials (capital letters or first letter after _).
E.g. g3m -> Generate3dMesh
Cannot be used alone, because we want at least behavior 1 to work.
It could be options 1 + 3.
Option 4: Any other hybrid of these.
Smart search. Depending of the number of results returned by 1, try to make a smarter selection, with the most likely labels first.
How to display the alternatives
Option 1 (chosen): Use status bar.
Display list of options in last line of the status bar, with the current
Option 2 (dismissed): Display window next to cursor.
Dismissed for now since requiring more work (window management!).
How to switch between alternative
TODO: consider 'refining options', especially when we already change a selection. E.g.
- Type ge
- Switch to the 2nd alternative
- Type n
- We want to refresh the alternatives, with pattern gen.
- We where good with the second alternative, and we want to add a n to form another label.
Option 0 (controversial): TAB
Cannot use tab, since already taken to repeat last search.
On the other hand, since it's pretty common, we could either:
- re-assign 'repeat last search' to another shortcut
- make tab smart: cycle suggestions when editing, repeat last search otherwise.
Option 1 (dismissed): CAPS-LOCK
Caps-lock is never used (prove me wrong), so we could reuse it as a special function.
Dismissed: potentially breaking anyway, a bit complex since firmware would get in the way.
Option 2: CONTROL-TAB
- Con: Might be confused with tab?
- Con: Preempt another standard use of CONTROL-TAB (switching between tabs).
Option 3: SHIFT-LEFT / SHIFT-RIGHT
- Con: Counter intuitive when we switch to better display UI (drop-down window, where selections are arranged vertically).
Option 4 (preferred?):
See switch+validation option 1 just below.
How to validate alternative
Option 0: ENTER/RETURN
Cannot use enter/return to respect reqC.
Exception? If there is only one solution (implying the word typed is already complete or doesn't exist as a label), we might want to auto-complete on ENTER/RETURN.
Option 1a: Combined selection-validation with CONTROL-SPACE
CONTROL-SPACE would put the first suggestion, and then we can continue typing.
But if we hit CONTROL-SPACE a second time, it would replace it by the second suggestion.
Pro: Can easily pick first or second suggestions (single or double CONTROL-SPACE respectively).
Pro: Already used by some editors.
- Con: Harder to press for Longshot (arthrosis).
Option 1b: Same with CONTROL-TAB
- Con: Might be confused with tab?
- Con: Preempt another standard use of CONTROL-TAB (switching between tabs).
Option 2 (meh): Cursor right.
That usually respects reqB: no interference with usual editing, thing we never use cursor right for a line being entered.
That's not so true if we are editing an existing line.
Pro: Compatible with https://fishshell.com/
Behaviours
[Can be done for v2]
It depends on precious design choices (selection & validation separated, or combined?).
What happens with the following sequences:
- letter(s), selection, letter
- letter(s), selection, del
- letter(s), selection, ENTER/RETURN
Context sensitive completion
Motivation: when typing IMPORT", we must select a filename, not a label.
Code wise
Genericity
It mustn't be tangled to orgams, and be available for instance to pick a filename.
Option1 (dismissed): Pass an iterator.
- Con: Might be too slow.
- Con: If the underlying data structure is a trie, it would prevent using it as intended.
Option2: Having ad-hoc search routines per data source.
The overall behaviour remains generic, but each data source (e.g. label vs filename) provide its specific search routines:
start_with(pattern, from)
; In: HL=pattern (nt string)
; DE=index labels (0 to start from beginning)
; Out: If found, Carry. DE=index found
; Otherwise, NC (end of table reached)
NB: If necessary, can be replaced by:
init_start_with(pattern)
do_start_with()
fuzzy_search(pattern, from)
# Idem
Which bring us to:
Searching among labels in orgams.
For now, the underlying data-structure is a bag of unsorted labels.
That means we have to scan them all.
TODO: estimate how much time it would take to scan entirely ~500 labels.
Returning the result.
It should be done incrementally: no need to return all the labels starting with "a" if we can only display the first 7. This becomes false if we wish to display the best 7 suggestions rather than the first 7 and/or if we want to display sorted suggestions.
Note: the polishing can and should be done in an ulterior "deluxe" version.
Incrementality will also guarantee a good reactivity.
Interface with editor
The routine must remain generic and reusable.
In particular, in mustn't deal with input (keyboard) and output (display) at all.
It just share a buffer with the editor.
So for instance, to scroll, the characters are shifted in this buffer, and the editor will simply redisplay all the buffer. Takes ~50 line rasters if I recall well, not noticeable anyway.
From the editing point of view, there are 3 main events, already describe in ui section:
- Adding a letter generates new
- Switching to the next suggestions among those generated (e.g. via TAB)
- Validating the selection.
Each of the two first events will call a dedicated routine, specified in the following sections.
Generate new suggestions
refresh_suggestions
; in hl = pattern ; Appele des que la pattern change (par exemple, "GE", puis "GEN", ...)
; out: All registers trashed.
; Side effect: Buffer (known fixed address) filled with suggestions:
; separated by space
; terminated by 0.
; NB: No suggestion is selected yet.
; You must set an internal state, that will be used by the next routine.
; You can store HL, rather than copying the pattern "privately".
Switch suggestions
reset_selection
; in: Nothing
; out: Like if refresh_selections was called again with same pattern.
; Goal: Allow to cycle when last suggestion reached,
; can be more efficient than refresh_selections.
; But in v1, it should be just a call to refresh_selections.
next_selection
; in: Nothing (the current selection is stored in internal state).
; Rationale: easier for the clients, which don't have to store the current selection.
; out: If next_selection exist
; Carry, Buffer refreshed (if scrolling was needed)
; D = start of suggestion in buffer (hence 0 <= D < 96)
; E = end (excluded) in buffer (hence 0 <= D <= 96)
; Otherwise (past the end)
; NC. Rationale: then the client can notify the end is reached, and decide the behaviour:
* Go back to nothing selected
* Go back to first selection
* Crash
* Other
prev_selection
; TODO later.
Exemples (avec un buffer de 12 de large plutot que 96).
; HL pointe sur "s".
call refresh_suggestions
; Buffer contains: "Start Stop S",0
call next_selection
; Carry Set
; Buffer unchanged
; D = 0 (beginning of "Start")
; E = 5 (past "Start" --point on space)
call next_selection
; Carry Set
; Buffer unchanged
; D = 6 (beginning of "Stop")
; E = 10 (past "Start" --point on space)
call next_selection
; Carry Set
; Buffer contains: "Sexy Solefal",0
; D = 0
; E = 4
call next_selection
; Carry Set
; Buffer contains: "Solefald",0
; D = 0
; E = 7
call next_selection
; NC. Buffer and DE: nevermind.
; HL pointe sur "st".
call refresh_suggestions
; Buffer contains: "Start Stop",0
How much to scroll?
- As little as possible:
- Pro: smoother scrolling
- Con: we don't see the following suggestions
- As much as possible (preferred)