-
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
Windows fix #775
Windows fix #775
Conversation
Exception occurred when interrupted with Ctrl+C on legacy conhost
return [window height, buffer width] insted of [buffer height, buffer width]
They internally duplicate arguments so api functions write to another place. This breaks the console mode detection with ruby-head.
#775 #776 does not have CI changes. |
lib/reline/io/windows.rb
Outdated
@@ -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" |
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
# Use 0 as null_pointer
[x == 0 ? nil : +x].pack("p")
@ScrollConsoleScreenBuffer.call(rect, 0, dst, fill)
# Represent NULL_POINTER by nil, not by 0
[x&.+@].pack("p")
@ScrollConsoleScreenBuffer.call(rect, nil, dst, fill)
By the way, I think if x
is a frozen string, a new mutable string +x
might be garbaged collected before @func.call
is called.
If the frozen string issue is solved in L174 (mode = +"\0\0\0\0"
), I think removing +@
is better.
[x == 0 ? nil : x].pack("p").... # x is 0 or string
# or
[x].pack("p").... # x is nil or string
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.
def call(*args)
return @func.call(*args)
end
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.
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.
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.
def call(*args)
return @func.call(*args)
end
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.
@@ -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? |
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 needed? I think line_editor does not print line longer than terminal width.
(Maybe the case line_width == terminal_width case?)
If this is needed, moving it to Reline::Windows#prep
and Reline::Windows#deprep
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 restore in deprep does not work because render_finished outputs a single, long line.
Windows console has mode flags. (https://learn.microsoft.com/en-us/windows/console/high-level-console-modes)
If ENABLE_VIRTUAL_TERMINAL_PROCESSING is set, cursor moves as expected by reline.
In environments where the flag is off or not supported, ENABLE_WRAP_AT_EOL_OUTPUT is on normally, causing a forced line break at the end of a line of output.
For example, outputting 123456
on a 6-column wide terminal would result in the following.
123456
_ #=> cursor moves next 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.
For example, outputting 12345678
on a 6-column wide terminal would result in the following.
123458 #=> cursor stays last column of line
Therefore, it was necessary to insert control of ENABLE_WRAP_AT_EOL_OUTPUT in the appropriate place.
Another reason was that if there was console output in the background, long lines could be destroyed if the flag was not restored while waiting for keystrokes.
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 makes sense. Thank you for the description 👍
top = csbi[12, 2].unpack1('S') | ||
bottom = csbi[16, 2].unpack1('S') | ||
width = csbi[0, 2].unpack1('S') | ||
[bottom - top + 1, width] |
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.
My understanding by reading the document is:
hidden_screen_buffer01
hidden_screen_buffer02
hidden_screen_buffer03
hidden_screen_buffer04
visible_screen_buffer1
visible_screen_buffer2
visible_sc█een_buffer3
visible_screen_buffer4
screen_buffer width = 22, screen_buffer height = 8
cursor x = 10 y = 6 (cursor coord in screen buffer, not coord in visible window)
window left=0 right=21 top=4 bottom=7
Is this right? If so, I think def cursor_pos
should use CursorPos.new(x, y - top)
. Can you check this?
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.
You are right.
I tried to modify cursor_pos, but even the cursor moving functions needed to take csbi.srWindow.Top into consideration. Needs some more work.
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.
done in df70541 .
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 👍
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.
Looks good 👍
Thank you
* test_yamatanooroti: close tempfile before unlink * test_yamatanooroti: omit because of windows does not support job control * test_yamatanooroti: change startup message detection for windows * windows.rb: can call win32api using nil as NULL for pointer argument Exception occurred when interrupted with Ctrl+C on legacy conhost * windows.rb: fix get_screen_size return [window height, buffer width] insted of [buffer height, buffer width] * windows.rb: import scroll_down() from ansi.rb * windows.rb: add auto linewrap control if VT output not supported (legacy console) * unfreeze WIN32API pointer arguments They internally duplicate arguments so api functions write to another place. This breaks the console mode detection with ruby-head. * remove useless code from Win32API#call argument repacking and return value tweaking is not needed for Reline::Windows requirements. * Correctly handle top of console viewport * Revert "remove useless code from Win32API#call" This reverts commit ruby/reline@060ba140ed43. * Revert "windows.rb: can call win32api using nil as NULL for pointer argument" This reverts commit ruby/reline@93a23bc5d0c9. ruby/reline@47c1ffbabe
I'm glad to hear it. |
This is part of supporting windows for reline CI using yamatanooroti.
This PR contains the following changes. There are independent to windows specific yamatanooroti changes.