-
Notifications
You must be signed in to change notification settings - Fork 88
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
Reline 0.5.0.pre #614
Reline 0.5.0.pre #614
Conversation
bff6012
to
aac06dc
Compare
080869f
to
0b421c5
Compare
961c294
to
3cfc6f5
Compare
end | ||
|
||
if new_lines != rendered_lines | ||
Reline::IOGate.hide_cursor |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For my own learning: when do we need to hide cursor and why? I see there are other operations involving moving cursor around, but this seems to be the only place to hide it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When lines to be rendered changed, reline needs to move cursor and write texts many times. We need to hide cursor because we don't want to show the cursor moving while rendering.
Example of not hiding cursor (Repeating Insert )
and delete)
On the other hand, if we always hide cursor in render_differential, cursor sometimes blink when just moving cursor.
Example of pressing arrow keys with hiding cursor
We need this for comfortable editing, so we don't have to hide cursor in exceptional case like clear screen with C-l
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we have a comment for this?
end | ||
|
||
def rerender | ||
handle_cleared |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this is the only caller of handle_cleared
, how about we just move its content here and remove the method?
It also looks like we could be calling render_differential
twice under the current implementation?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It also looks like we could be calling render_differential twice under the current implementation?
Nice catch. I remove render_differential
from handle_cleared
. Finally when pasting is complete, rerender will be called with @in_pasting == false
from reline.rb
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I want to leave handle_cleared because I want to remove handle_cleared
from rerender
in the future.
But changing it now needs test_key_actor_emacs.rb
that depends on instance variable @cleared
to be changed.
Plan and reason
private def ed_clear_screen(key)
@cleared = true
end
def rerender
handle_cleared
render_differential unless @in_pasting
end
↓
private def ed_clear_screen(key)
@rendered_screen_cache = nil
Reline::IOGate.clear_screen
@screen_size = Reline::IOGate.get_screen_size
@cursor_base_y = 0
@cursor_y = 0
end
# We need handle_resize(`def resize` is implemented) and handle_interrupt(not implemented, causing deadlock and thread problem) to handle signals correctly
# We don't need handle_cleared. clear is not a signal
def rerender
render_differential unless @in_pasting
end
2740c66
to
b541d30
Compare
line_editor.print_nomultiline_prompt(prompt) | ||
line_editor.update_dialogs |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please let me know for study purposes. Why do I need to update dialogs before read_io
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reline has an ability to always show dialog. Reline needs to setup and render dialog on initial render, before first read_io.
irb(main):001> Reline.add_dialog_proc(:FOO,->{Reline::DialogRenderInfo.new contents:['DIALOG'], pos: cursor_pos})
irb(main):002>
DIALOG
This is tested in test_dialog_narrower_than_screen
and test_dialog_with_fullwidth_scrollbar
else | ||
@line = Reline::HISTORY[@history_pointer] | ||
@buffer_of_lines = [Reline::HISTORY[@history_pointer]] | ||
calculate_nearest_cursor(cursor) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For my own learning: Why is it necessary to calculate the cursor position here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When @buffer_of_lines[@line_index]
or @buffer_of_lines
itself is directly modified, we need set byte_pointer to 0
or line.bytesize
, or re-calculate byte_position based on previous cursor position to avoid byte_position being in a middle of grapheme cluster.
For this case, I just found a bug like this which is fixed by this calculate_nearest_cursor.
# prepare history
irb(main):001> "1️⃣"
=> "1️⃣"
irb(main):002> "1
# press PGUP and 2
irb(main):002> "12️⃣"
# press DELETE DELETE
irb(main):002> "(garbled text)"
prompt> 5 | ||
prompt> 6 Ruby is... | ||
prompt> 5 Ruby is... | ||
prompt> 6 A dynamic, open source programming |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this change needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lib/reline/line_editor.rb
Outdated
|
||
# Calculate cursor position in word wrapped content. | ||
def wrapped_cursor_position | ||
line = ' ' * calculate_width(prompt_list[@line_index], true) + whole_lines[@line_index].byteslice(0, @byte_pointer) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about a local variable name of line_before_cursor
? I thought line
here is not the whole line.
end | ||
|
||
if new_lines != rendered_lines | ||
Reline::IOGate.hide_cursor |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we have a comment for this?
|
It only need to clear screen. line_editor.rerender will be called later.
Co-authored-by: Stan Lo <stan001212@gmail.com>
Fix bug updating `@cursor_y`. Do not use `@cursor_y` while updating dialog because it is not current cursor position but cursor position at last rendered time.
These instance variables are already removed from LineEditor
…e unused instance variable
It represents cursor position of word wrapped whole content
b541d30
to
d02b844
Compare
d02b844
to
83232d0
Compare
83232d0
to
97d76d8
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the excellent refactoring! 🌟
This PR has made the rendering much easier to understand and use.
(ruby/reline#614) * Re-architecture LineEditor's internal state and rendering * Fix test related to LineEditor re-architecture * Bump to 0.5.0.pre.1 * Hide cursor only when updating screen. Frequent hide&show makes cursor flickering. * Simplify rerender call from reline.rb * Simplify handle_cleared It only need to clear screen. line_editor.rerender will be called later. * Add description of updating pasting_state inserts continuous_insertion_buffer * Use meaningful block parameter Co-authored-by: Stan Lo <stan001212@gmail.com> * Fix use of `@cursor_y` Fix bug updating `@cursor_y`. Do not use `@cursor_y` while updating dialog because it is not current cursor position but cursor position at last rendered time. * Remove useless instance_variable_set in test These instance variables are already removed from LineEditor * Always initialize instance variables to avoid ruby 2.7 warning, remove unused instance variable * Call update_dialogs from reline.rb before first render * Combine state representing rendered screen information into `@rendered_screen` * Rename editor_cursor_ to wrapped_cursor It represents cursor position of word wrapped whole content * Remove unused code, tweak, add comment --------- ruby/reline@3fa376217d Co-authored-by: Stan Lo <stan001212@gmail.com>
(ruby/reline#614) * Re-architecture LineEditor's internal state and rendering * Fix test related to LineEditor re-architecture * Bump to 0.5.0.pre.1 * Hide cursor only when updating screen. Frequent hide&show makes cursor flickering. * Simplify rerender call from reline.rb * Simplify handle_cleared It only need to clear screen. line_editor.rerender will be called later. * Add description of updating pasting_state inserts continuous_insertion_buffer * Use meaningful block parameter Co-authored-by: Stan Lo <stan001212@gmail.com> * Fix use of `@cursor_y` Fix bug updating `@cursor_y`. Do not use `@cursor_y` while updating dialog because it is not current cursor position but cursor position at last rendered time. * Remove useless instance_variable_set in test These instance variables are already removed from LineEditor * Always initialize instance variables to avoid ruby 2.7 warning, remove unused instance variable * Call update_dialogs from reline.rb before first render * Combine state representing rendered screen information into `@rendered_screen` * Rename editor_cursor_ to wrapped_cursor It represents cursor position of word wrapped whole content * Remove unused code, tweak, add comment --------- ruby/reline@3fa376217d Co-authored-by: Stan Lo <stan001212@gmail.com>
This is a branch to release #595 as 0.5.0.pre.x
See description of #595
Instance variables of cursor and screens
before this pull request
after this pull request