-
Notifications
You must be signed in to change notification settings - Fork 93
Windows fix #775
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
Windows fix #775
Changes from 8 commits
3e1cfa2
8050239
235367d
93a23bc
3875659
9b3ffd8
053bbdb
2429165
060ba14
df70541
eb5959c
5443ab5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -115,7 +115,7 @@ def initialize(dllname, func, import, export = "0", calltype = :stdcall) | |
| def call(*args) | ||
| import = @proto.split("") | ||
| args.each_with_index do |x, i| | ||
| args[i], = [x == 0 ? nil : +x].pack("p").unpack(POINTER_TYPE) if import[i] == "S" | ||
| args[i], = [x == 0 ? nil : x&.+@].pack("p").unpack(POINTER_TYPE) if import[i] == "S" | ||
| args[i], = [x].pack("I").unpack("i") if import[i] == "I" | ||
| end | ||
| ret, = @func.call(*args) | ||
|
|
@@ -157,6 +157,7 @@ def call(*args) | |
| STD_OUTPUT_HANDLE = -11 | ||
| FILE_TYPE_PIPE = 0x0003 | ||
| FILE_NAME_INFO = 2 | ||
| ENABLE_WRAP_AT_EOL_OUTPUT = 2 | ||
| ENABLE_VIRTUAL_TERMINAL_PROCESSING = 4 | ||
|
|
||
| # Calling Win32API with console handle is reported to fail after executing some external command. | ||
|
|
@@ -170,7 +171,7 @@ def call(*args) | |
| end | ||
|
|
||
| private def getconsolemode | ||
| mode = "\000\000\000\000" | ||
| mode = +"\0\0\0\0" | ||
| call_with_console_handle(@GetConsoleMode, mode) | ||
| mode.unpack1('L') | ||
| end | ||
|
|
@@ -350,9 +351,12 @@ def get_console_screen_buffer_info | |
|
|
||
| def get_screen_size | ||
| unless csbi = get_console_screen_buffer_info | ||
| return [1, 1] | ||
| return [24, 80] | ||
| end | ||
| csbi[0, 4].unpack('SS').reverse | ||
| top = csbi[12, 2].unpack1('S') | ||
| bottom = csbi[16, 2].unpack1('S') | ||
| width = csbi[0, 2].unpack1('S') | ||
| [bottom - top + 1, width] | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My understanding by reading the document is: Is this right? If so, I think
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You are right.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done in df70541 .
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thank you 👍 |
||
| end | ||
|
|
||
| def cursor_pos | ||
|
|
@@ -399,31 +403,12 @@ def erase_after_cursor | |
| call_with_console_handle(@FillConsoleOutputAttribute, attributes, get_screen_size.last - cursor_pos.x, cursor, written) | ||
| end | ||
|
|
||
| def scroll_down(val) | ||
| return if val < 0 | ||
| return unless csbi = get_console_screen_buffer_info | ||
| buffer_width, buffer_lines, x, y, attributes, window_left, window_top, window_bottom = csbi.unpack('ssssSssx2s') | ||
| screen_height = window_bottom - window_top + 1 | ||
| val = screen_height if val > screen_height | ||
|
|
||
| if @legacy_console || window_left != 0 | ||
| # unless ENABLE_VIRTUAL_TERMINAL, | ||
| # if srWindow.Left != 0 then it's conhost.exe hosted console | ||
| # and puts "\n" causes horizontal scroll. its glitch. | ||
| # FYI irb write from culumn 1, so this gives no gain. | ||
| scroll_rectangle = [0, val, buffer_width, buffer_lines - val].pack('s4') | ||
| destination_origin = 0 # y * 65536 + x | ||
| fill = [' '.ord, attributes].pack('SS') | ||
| call_with_console_handle(@ScrollConsoleScreenBuffer, scroll_rectangle, nil, destination_origin, fill) | ||
| else | ||
| origin_x = x + 1 | ||
| origin_y = y - window_top + 1 | ||
| @output.write [ | ||
| (origin_y != screen_height) ? "\e[#{screen_height};H" : nil, | ||
| "\n" * val, | ||
| (origin_y != screen_height or !x.zero?) ? "\e[#{origin_y};#{origin_x}H" : nil | ||
| ].join | ||
| end | ||
| # This only works when the cursor is at the bottom of the scroll range | ||
| # For more details, see https://github.com/ruby/reline/pull/577#issuecomment-1646679623 | ||
| def scroll_down(x) | ||
| return if x.zero? | ||
| # We use `\n` instead of CSI + S because CSI + S would cause https://github.com/ruby/reline/issues/576 | ||
| @output.write "\n" * x | ||
| end | ||
|
|
||
| def clear_screen | ||
|
|
@@ -472,6 +457,28 @@ def deprep(otio) | |
| # do nothing | ||
| end | ||
|
|
||
| def disable_auto_linewrap(setting = true, &block) | ||
| mode = getconsolemode | ||
| if 0 == (mode & ENABLE_VIRTUAL_TERMINAL_PROCESSING) | ||
| if block | ||
| begin | ||
| setconsolemode(mode & ~ENABLE_WRAP_AT_EOL_OUTPUT) | ||
| block.call | ||
| ensure | ||
| setconsolemode(mode | ENABLE_WRAP_AT_EOL_OUTPUT) | ||
| end | ||
| else | ||
| if setting | ||
| setconsolemode(mode & ~ENABLE_WRAP_AT_EOL_OUTPUT) | ||
| else | ||
| setconsolemode(mode | ENABLE_WRAP_AT_EOL_OUTPUT) | ||
| end | ||
| end | ||
| else | ||
| block.call if block | ||
| end | ||
| end | ||
|
|
||
| class KeyEventRecord | ||
|
|
||
| attr_reader :virtual_key_code, :char_code, :control_key_state, :control_keys | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -472,8 +472,11 @@ def render_finished | |
| end | ||
|
|
||
| def print_nomultiline_prompt | ||
| Reline::IOGate.disable_auto_linewrap(true) if Reline::IOGate.win? | ||
| # Readline's test `TestRelineAsReadline#test_readline` requires first output to be prompt, not cursor reset escape sequence. | ||
| @output.write Reline::Unicode.strip_non_printing_start_end(@prompt) if @prompt && !@is_multiline | ||
| ensure | ||
| Reline::IOGate.disable_auto_linewrap(false) if Reline::IOGate.win? | ||
| end | ||
|
|
||
| def render | ||
|
|
@@ -509,6 +512,7 @@ def render | |
| # by calculating the difference from the previous render. | ||
|
|
||
| private def render_differential(new_lines, new_cursor_x, new_cursor_y) | ||
| Reline::IOGate.disable_auto_linewrap(true) if Reline::IOGate.win? | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is this needed? I think line_editor does not print line longer than terminal width. If this is needed, moving it to
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The restore in deprep does not work because render_finished outputs a single, long line. If ENABLE_WRAP_AT_EOL_OUTPUT is turned off, no forced line breaks occur. Instead, the cursor stays at the end of the line and subsequent characters overwrite the end of the line. Therefore, it was necessary to insert control of ENABLE_WRAP_AT_EOL_OUTPUT in the appropriate place.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It makes sense. Thank you for the description 👍 |
||
| rendered_lines = @rendered_screen.lines | ||
| cursor_y = @rendered_screen.cursor_y | ||
| if new_lines != rendered_lines | ||
|
|
@@ -539,6 +543,8 @@ def render | |
| Reline::IOGate.move_cursor_column new_cursor_x | ||
| Reline::IOGate.move_cursor_down new_cursor_y - cursor_y | ||
| @rendered_screen.cursor_y = new_cursor_y | ||
| ensure | ||
| Reline::IOGate.disable_auto_linewrap(false) if Reline::IOGate.win? | ||
| end | ||
|
|
||
| private def clear_rendered_screen_cache | ||
|
|
||
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.
This code does not expect x to be non-zero number because
[+3].pack('p')raises error.Zero represents NULL_POINTER, so the possible code would be
By the way, I think if
xis a frozen string, a new mutable string+xmight be garbaged collected before@func.callis called.If the frozen string issue is solved in L174 (
mode = +"\0\0\0\0"), I think removing+@is better.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.
The current patch is the result of a minimization of fixes because I could not figure out the intent of args repacking.
By checking the code around ruby 1.9 to 2.0, I found that DL::CFunc of Ruby/DL (Ruby/DL2), the backend of WIN32API at that time, accepts only integers.
I think the repacking itself is unnecessary because the current Fiddle allows more flexible passing of arguments.
The above may be enough. Is there something I'm missing?
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 think the NULL problem is fixed in 9b3ffd8
String
0.chr * n+"\0\0\0..."seems to be always passed to import[i]=="S" (import is 'P') argument exceptcall_with_console_handle(@ScrollConsoleScreenBuffer, scroll_rectangle, nil, destination_origin, fill)and this line is removed in 9b3ffd8
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.
Thanks for the suggestion. I was not aware of 9b3ffd8 at all.
However, I am worried about touching a code that I don't know the basis for, and I now think that code is unnecessary.
So I think it was done in 060ba14 .
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.
This looks good to me.
However, I don't have confidence that this works in all supported ruby versions and fiddle version. I think it is better to avoid risk since next ruby release is close in time.
How about leaving it as is (as original
[x == 0 ? nil : +x].pack("p")....) for now, and change it after adding windows ci?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 understand your point of consideration.
I also know that there is no specific problem that the patch will solve.
reverted in eb5959c 5443ab5