Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

In ed_search_[prev|next]_history, make the cursor come to the end of the line when there is no search substr #714

Merged

Conversation

QWYNG
Copy link
Contributor

@QWYNG QWYNG commented May 30, 2024

fix #618

Overview

To solve the problem, I have modified the cursor behavior to move to the end of the line if the search string is empty.
Please let me know if there is anything I am missing.

Thank you for maintaining this great Ruby feature.

@QWYNG QWYNG marked this pull request as draft May 30, 2024 14:24
@QWYNG QWYNG changed the title In ed_search_prev_history, make the cursor come to the end of the line when there is no search substr In ed_search_[prev|next]_history, make the cursor come to the end of the line when there is no search substr May 30, 2024
@QWYNG QWYNG force-pushed the ed_search_prev_history-cursor-end-when-no-substr branch from ef1ef00 to e5b0979 Compare May 30, 2024 14:32
@QWYNG QWYNG marked this pull request as ready for review May 30, 2024 14:33
@line_editor.__send__(:ed_search_prev_history, "\C-p".ord)
assert_line_around_cursor('', '12aaa')
assert_line_around_cursor('12345', '')
Copy link
Member

@tompng tompng Jun 2, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This part should be ('12aaa', '')
#618 might be harder than I first thought.

I checked GNU Readline.

ruby -rreadline -rreline -e "raise if Readline==Reline; loop{p Readline.readline 'prompt> ', true}"
prompt> █
ed_search_prev_history, search with empty string
prompt> 12345█
(A) ed_search_prev_history, search with empty string
prompt> 12aaa█
prompt> █
ed_search_prev_history, search with empty string
prompt> 12345█
Move cursor left and right. Continuous search_xxx_history is reset.
prompt> 12345█
(B) ed_search_prev_history, search with "12345", search fails
prompt> 12345█

There is a difference between (A) and (B). Same input, same cursor position, but there is a hidden state. We need to introduce a new state (instance variable) to achieve this.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding new instance variable for many def ed_[key_action_name] will make maintainability poor, so I think we should introduce a general-purpose feature for passing state to next action.

One idea is:

def input_key
  ...
  # process_key() or normal_char() is called here
  ...
  @prev_action_state, @next_action_state = @next_action_state, nil
end

Key action method can read @prev_action_state.
If the action want to pass a state to next action, set @next_action_state to something like [state_type, state_value].

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your clear comment. To replicate the behavior of Readline, it is best to include information about the before and after states of the current operation. I will give it a try

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed in 7ddd20d

Comment on lines 48 to 49
ActionState = Struct.new(:state_type, :state_value)
NullActionState = ActionState.new(nil, nil)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have used a Struct to make the contents of action_state more understandable, but using a simple Array would also be good.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In ed_search_prev_history and ed_search_next_history, @prev_action_state == ActionState.new(:search_history, :empty) is working great 👍

In general, I think this kind of ideom will appear frequently.

foobar = @prev_action_state.value if @prev_action_state&.type == :foobar

To make it easy to use, can you add a helper method like this?

# get
prev = prev_action_state(:search_history)
# set
set_next_action_state(:search_history, :empty)

Using it, we can just use a simple array internally. It will reduce total struct/class count (complexity).
And we don't need to think of NullActionState wrongly modified.

state = @prev_action_state
state.value = next_value # bug. this might modify NullActionState
@next_action_state = state

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! I tried to represent the state in a 2-element array!
19dae5b

@@ -1133,6 +1135,9 @@ def input_key(key)
else
normal_char(key)
end

@prev_action_state, @next_action_state = @next_action_state, NullActionState
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add an initialization of these instance variables in def reset_variables?
This will properly re-initialize just ater Reline.readline is canceled by Ctrl-C.
Initial state of @prev_action_state will be simple. (Currently, initial value is nil and will be updated to NullActionState)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the advice. I have also added initialization of variables at 19dae5b

Copy link
Member

@tompng tompng left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good 👍 Thank you!

@tompng tompng merged commit 95ee80b into ruby:master Jun 3, 2024
40 checks passed
matzbot pushed a commit to ruby/ruby that referenced this pull request Jun 3, 2024
to the end of the line when there is no search substr
(ruby/reline#714)

* In ed_search_prev_history, make the cursor come to the end of the line when there is no search substr

* In ed_search_next_history, make the cursor come to the end of the line when there is no search substr

* Implemented ActionState to search with empty substr if the previous operation was search with empty string.

* Use a simple 2-element array to represent action_state

ruby/reline@95ee80bd70
@QWYNG QWYNG deleted the ed_search_prev_history-cursor-end-when-no-substr branch June 4, 2024 01:15
@ima1zumi ima1zumi added the bug Something isn't working label Jun 12, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Development

Successfully merging this pull request may close these issues.

history-search-backward places cursor in the beginning of line when there's nothing to search
3 participants