Proposal to add common prefix completion for autocompletion mode#880
Proposal to add common prefix completion for autocompletion mode#880amatsuda wants to merge 1 commit into
Conversation
Now the first tab press on autocompletion mode performs common prefix
completion, like the tab press on non-autocompletion mode.
For instance, when having candidates %w[ab1 ab2 ab3 c]:
1. User inputs "a"
2. First Tab: Complete to common prefix (e.g., "a" → "ab" with menu displayed)
3. Second Tab: Select first candidate (e.g., "ab" → "ab1")
4. Subsequent Tabs: Cycle through candidates + common prefix ("ab")
| else | ||
| # First tab: complete to common prefix | ||
| pre, target, post, quote = retrieve_completion_block | ||
| result = call_completion_proc(pre, target, post, quote) |
There was a problem hiding this comment.
We can use:
@completion_journey_state = retrieve_completion_journey_state
The computed result can be re-used if there is no common prefix, and fallback to move_completed_list(:down)
| result = call_completion_proc(pre, target, post, quote) | ||
| if result.is_a?(Array) | ||
| @completion_occurs = true | ||
| perform_completion(pre, target, post, quote, result) |
There was a problem hiding this comment.
perform_completion is for Readline-compatible tab completion, not for autocompletion.
irb(main):001> 1.a
1.abs 1.abs2 1.allbits? 1.angle 1.anybits? 1.arg
It may unintentionally set @completion_state to CompletionState::PERFECT_MATCH or CompletionState::MENU which should be only used in noautocomplete mode, especially when set show-all-if-ambiguous on is set in .inputrc.
irb(main):001> 1.a
1.abs 1.a1.abs .allbits? 1.angle 1.anybits? 1.arg
1.abs2
1.allbits?
1.angle
1.anybits?
1.arg
| post_part = post.split("\n", -1).first || '' | ||
| @completion_journey_state = CompletionJourneyState.new( | ||
| @line_index, pre_part, completed, post_part, [completed] + candidates, 0 | ||
| ) |
There was a problem hiding this comment.
How about extract completion applying part from move_completed_list,
calculate common prefix, apply the completion common prefix with the extracted method if exist, and fallback to move_completed_list(:down)?
| if @completion_journey_state && @completion_journey_state.pointer > 0 | ||
| # Already cycling (third+ tab): move to next candidate | ||
| @completion_occurs = move_completed_list(:down) | ||
| elsif @completion_journey_state && @completion_journey_state.pointer == 0 && @autocompletion_first_tab_completed |
There was a problem hiding this comment.
Even if pointer == 0, I think we want to apply common prefix completion only on the first TAB press.
Not on SHIFT-TAB (move to the end of completion candidate list) and then press TAB again.
I think @autocompletion_first_tab_completed can be renamed to started. if completion is started (move_completion_list is called), don't apply common prefix completion.
And this parameter can be moved to @completion_journey_state.started
Perhaps, common prefix can also be a pre-computed property of @completion_journey_state too.
Let me propose to add the "common prefix completion" for the first tab hit on autocompletion mode.
The behavior is similar to the tab hit on non-autocompletion mode, and then it cycles through the candidates just as the current autocompletion mode behaves. I think this is how most of the modern shells e.g., bash, zsh, etc. behave by default.
As a realistic example, when having candidates
now we can get to "instance_variable_get" with the following three steps:
You can confirm this exact behavior with this one liner on this branch:
ruby -Ilib -rreline -e "Reline.autocompletion = true; Reline.completion_proc = proc { |s| %w[instance_of? instance_variable_defined? instance_variable_get instance_variable_set instance_variables].select { |i| i.start_with?(s) } }; puts Reline.readline('> ')"