AutoCompletion

Auto-completion specifications

Warning, work in progress.

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).
  • 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).

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
Does it mean:
  • 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)
Sauf mention contraire, le contenu de cette page est protégé par la licence Creative Commons Attribution-ShareAlike 3.0 License