reline 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,3 @@
1
+ module Reline
2
+ VERSION = '0.1.3'
3
+ end
@@ -0,0 +1,273 @@
1
+ require 'fiddle/import'
2
+
3
+ class Reline::Windows
4
+ def self.encoding
5
+ Encoding::UTF_8
6
+ end
7
+
8
+ def self.win?
9
+ true
10
+ end
11
+
12
+ RAW_KEYSTROKE_CONFIG = {
13
+ [224, 72] => :ed_prev_history, # ↑
14
+ [224, 80] => :ed_next_history, # ↓
15
+ [224, 77] => :ed_next_char, # →
16
+ [224, 75] => :ed_prev_char, # ←
17
+ [224, 83] => :key_delete, # Del
18
+ [224, 71] => :ed_move_to_beg, # Home
19
+ [224, 79] => :ed_move_to_end, # End
20
+ [ 0, 41] => :ed_unassigned, # input method on/off
21
+ [ 0, 72] => :ed_prev_history, # ↑
22
+ [ 0, 80] => :ed_next_history, # ↓
23
+ [ 0, 77] => :ed_next_char, # →
24
+ [ 0, 75] => :ed_prev_char, # ←
25
+ [ 0, 83] => :key_delete, # Del
26
+ [ 0, 71] => :ed_move_to_beg, # Home
27
+ [ 0, 79] => :ed_move_to_end # End
28
+ }
29
+
30
+ if defined? JRUBY_VERSION
31
+ require 'win32api'
32
+ else
33
+ class Win32API
34
+ DLL = {}
35
+ TYPEMAP = {"0" => Fiddle::TYPE_VOID, "S" => Fiddle::TYPE_VOIDP, "I" => Fiddle::TYPE_LONG}
36
+ POINTER_TYPE = Fiddle::SIZEOF_VOIDP == Fiddle::SIZEOF_LONG_LONG ? 'q*' : 'l!*'
37
+
38
+ WIN32_TYPES = "VPpNnLlIi"
39
+ DL_TYPES = "0SSI"
40
+
41
+ def initialize(dllname, func, import, export = "0", calltype = :stdcall)
42
+ @proto = [import].join.tr(WIN32_TYPES, DL_TYPES).sub(/^(.)0*$/, '\1')
43
+ import = @proto.chars.map {|win_type| TYPEMAP[win_type.tr(WIN32_TYPES, DL_TYPES)]}
44
+ export = TYPEMAP[export.tr(WIN32_TYPES, DL_TYPES)]
45
+ calltype = Fiddle::Importer.const_get(:CALL_TYPE_TO_ABI)[calltype]
46
+
47
+ handle = DLL[dllname] ||=
48
+ begin
49
+ Fiddle.dlopen(dllname)
50
+ rescue Fiddle::DLError
51
+ raise unless File.extname(dllname).empty?
52
+ Fiddle.dlopen(dllname + ".dll")
53
+ end
54
+
55
+ @func = Fiddle::Function.new(handle[func], import, export, calltype)
56
+ rescue Fiddle::DLError => e
57
+ raise LoadError, e.message, e.backtrace
58
+ end
59
+
60
+ def call(*args)
61
+ import = @proto.split("")
62
+ args.each_with_index do |x, i|
63
+ args[i], = [x == 0 ? nil : x].pack("p").unpack(POINTER_TYPE) if import[i] == "S"
64
+ args[i], = [x].pack("I").unpack("i") if import[i] == "I"
65
+ end
66
+ ret, = @func.call(*args)
67
+ return ret || 0
68
+ end
69
+ end
70
+ end
71
+
72
+ VK_MENU = 0x12
73
+ VK_LMENU = 0xA4
74
+ VK_CONTROL = 0x11
75
+ VK_SHIFT = 0x10
76
+ STD_INPUT_HANDLE = -10
77
+ STD_OUTPUT_HANDLE = -11
78
+ WINDOW_BUFFER_SIZE_EVENT = 0x04
79
+ FILE_TYPE_PIPE = 0x0003
80
+ FILE_NAME_INFO = 2
81
+ @@getwch = Win32API.new('msvcrt', '_getwch', [], 'I')
82
+ @@kbhit = Win32API.new('msvcrt', '_kbhit', [], 'I')
83
+ @@GetKeyState = Win32API.new('user32', 'GetKeyState', ['L'], 'L')
84
+ @@GetConsoleScreenBufferInfo = Win32API.new('kernel32', 'GetConsoleScreenBufferInfo', ['L', 'P'], 'L')
85
+ @@SetConsoleCursorPosition = Win32API.new('kernel32', 'SetConsoleCursorPosition', ['L', 'L'], 'L')
86
+ @@GetStdHandle = Win32API.new('kernel32', 'GetStdHandle', ['L'], 'L')
87
+ @@FillConsoleOutputCharacter = Win32API.new('kernel32', 'FillConsoleOutputCharacter', ['L', 'L', 'L', 'L', 'P'], 'L')
88
+ @@ScrollConsoleScreenBuffer = Win32API.new('kernel32', 'ScrollConsoleScreenBuffer', ['L', 'P', 'P', 'L', 'P'], 'L')
89
+ @@hConsoleHandle = @@GetStdHandle.call(STD_OUTPUT_HANDLE)
90
+ @@hConsoleInputHandle = @@GetStdHandle.call(STD_INPUT_HANDLE)
91
+ @@GetNumberOfConsoleInputEvents = Win32API.new('kernel32', 'GetNumberOfConsoleInputEvents', ['L', 'P'], 'L')
92
+ @@ReadConsoleInput = Win32API.new('kernel32', 'ReadConsoleInput', ['L', 'P', 'L', 'P'], 'L')
93
+ @@GetFileType = Win32API.new('kernel32', 'GetFileType', ['L'], 'L')
94
+ @@GetFileInformationByHandleEx = Win32API.new('kernel32', 'GetFileInformationByHandleEx', ['L', 'I', 'P', 'L'], 'I')
95
+
96
+ @@input_buf = []
97
+ @@output_buf = []
98
+
99
+ def self.msys_tty?(io=@@hConsoleInputHandle)
100
+ # check if fd is a pipe
101
+ if @@GetFileType.call(io) != FILE_TYPE_PIPE
102
+ return false
103
+ end
104
+
105
+ bufsize = 1024
106
+ p_buffer = "\0" * bufsize
107
+ res = @@GetFileInformationByHandleEx.call(io, FILE_NAME_INFO, p_buffer, bufsize - 2)
108
+ return false if res == 0
109
+
110
+ # get pipe name: p_buffer layout is:
111
+ # struct _FILE_NAME_INFO {
112
+ # DWORD FileNameLength;
113
+ # WCHAR FileName[1];
114
+ # } FILE_NAME_INFO
115
+ len = p_buffer[0, 4].unpack("L")[0]
116
+ name = p_buffer[4, len].encode(Encoding::UTF_8, Encoding::UTF_16LE, invalid: :replace)
117
+
118
+ # Check if this could be a MSYS2 pty pipe ('\msys-XXXX-ptyN-XX')
119
+ # or a cygwin pty pipe ('\cygwin-XXXX-ptyN-XX')
120
+ name =~ /(msys-|cygwin-).*-pty/ ? true : false
121
+ end
122
+
123
+ def self.getwch
124
+ unless @@input_buf.empty?
125
+ return @@input_buf.shift
126
+ end
127
+ while @@kbhit.call == 0
128
+ sleep(0.001)
129
+ end
130
+ until @@kbhit.call == 0
131
+ ret = @@getwch.call
132
+ if ret == 0 or ret == 0xE0
133
+ @@input_buf << ret
134
+ ret = @@getwch.call
135
+ @@input_buf << ret
136
+ return @@input_buf.shift
137
+ end
138
+ begin
139
+ bytes = ret.chr(Encoding::UTF_8).bytes
140
+ @@input_buf.push(*bytes)
141
+ rescue Encoding::UndefinedConversionError
142
+ @@input_buf << ret
143
+ @@input_buf << @@getwch.call if ret == 224
144
+ end
145
+ end
146
+ @@input_buf.shift
147
+ end
148
+
149
+ def self.getc
150
+ num_of_events = 0.chr * 8
151
+ while @@GetNumberOfConsoleInputEvents.(@@hConsoleInputHandle, num_of_events) != 0 and num_of_events.unpack('L').first > 0
152
+ input_record = 0.chr * 18
153
+ read_event = 0.chr * 4
154
+ if @@ReadConsoleInput.(@@hConsoleInputHandle, input_record, 1, read_event) != 0
155
+ event = input_record[0, 2].unpack('s*').first
156
+ if event == WINDOW_BUFFER_SIZE_EVENT
157
+ @@winch_handler.()
158
+ end
159
+ end
160
+ end
161
+ unless @@output_buf.empty?
162
+ return @@output_buf.shift
163
+ end
164
+ input = getwch
165
+ meta = (@@GetKeyState.call(VK_LMENU) & 0x80) != 0
166
+ control = (@@GetKeyState.call(VK_CONTROL) & 0x80) != 0
167
+ shift = (@@GetKeyState.call(VK_SHIFT) & 0x80) != 0
168
+ force_enter = !input.instance_of?(Array) && (control or shift) && input == 0x0D
169
+ if force_enter
170
+ # It's treated as Meta+Enter on Windows
171
+ @@output_buf.push("\e".ord)
172
+ @@output_buf.push(input)
173
+ else
174
+ case input
175
+ when 0x00
176
+ meta = false
177
+ @@output_buf.push(input)
178
+ input = getwch
179
+ @@output_buf.push(*input)
180
+ when 0xE0
181
+ @@output_buf.push(input)
182
+ input = getwch
183
+ @@output_buf.push(*input)
184
+ when 0x03
185
+ @@output_buf.push(input)
186
+ else
187
+ @@output_buf.push(input)
188
+ end
189
+ end
190
+ if meta
191
+ "\e".ord
192
+ else
193
+ @@output_buf.shift
194
+ end
195
+ end
196
+
197
+ def self.ungetc(c)
198
+ @@output_buf.unshift(c)
199
+ end
200
+
201
+ def self.get_screen_size
202
+ csbi = 0.chr * 22
203
+ @@GetConsoleScreenBufferInfo.call(@@hConsoleHandle, csbi)
204
+ csbi[0, 4].unpack('SS').reverse
205
+ end
206
+
207
+ def self.cursor_pos
208
+ csbi = 0.chr * 22
209
+ @@GetConsoleScreenBufferInfo.call(@@hConsoleHandle, csbi)
210
+ x = csbi[4, 2].unpack('s*').first
211
+ y = csbi[6, 2].unpack('s*').first
212
+ Reline::CursorPos.new(x, y)
213
+ end
214
+
215
+ def self.move_cursor_column(val)
216
+ @@SetConsoleCursorPosition.call(@@hConsoleHandle, cursor_pos.y * 65536 + val)
217
+ end
218
+
219
+ def self.move_cursor_up(val)
220
+ if val > 0
221
+ @@SetConsoleCursorPosition.call(@@hConsoleHandle, (cursor_pos.y - val) * 65536 + cursor_pos.x)
222
+ elsif val < 0
223
+ move_cursor_down(-val)
224
+ end
225
+ end
226
+
227
+ def self.move_cursor_down(val)
228
+ if val > 0
229
+ @@SetConsoleCursorPosition.call(@@hConsoleHandle, (cursor_pos.y + val) * 65536 + cursor_pos.x)
230
+ elsif val < 0
231
+ move_cursor_up(-val)
232
+ end
233
+ end
234
+
235
+ def self.erase_after_cursor
236
+ csbi = 0.chr * 24
237
+ @@GetConsoleScreenBufferInfo.call(@@hConsoleHandle, csbi)
238
+ cursor = csbi[4, 4].unpack('L').first
239
+ written = 0.chr * 4
240
+ @@FillConsoleOutputCharacter.call(@@hConsoleHandle, 0x20, get_screen_size.last - cursor_pos.x, cursor, written)
241
+ end
242
+
243
+ def self.scroll_down(val)
244
+ return if val.zero?
245
+ scroll_rectangle = [0, val, get_screen_size.last, get_screen_size.first].pack('s4')
246
+ destination_origin = 0 # y * 65536 + x
247
+ fill = [' '.ord, 0].pack('SS')
248
+ @@ScrollConsoleScreenBuffer.call(@@hConsoleHandle, scroll_rectangle, nil, destination_origin, fill)
249
+ end
250
+
251
+ def self.clear_screen
252
+ # TODO: Use FillConsoleOutputCharacter and FillConsoleOutputAttribute
253
+ write "\e[2J"
254
+ write "\e[1;1H"
255
+ end
256
+
257
+ def self.set_screen_size(rows, columns)
258
+ raise NotImplementedError
259
+ end
260
+
261
+ def self.set_winch_handler(&handler)
262
+ @@winch_handler = handler
263
+ end
264
+
265
+ def self.prep
266
+ # do nothing
267
+ nil
268
+ end
269
+
270
+ def self.deprep(otio)
271
+ # do nothing
272
+ end
273
+ end
metadata ADDED
@@ -0,0 +1,119 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: reline
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.3
5
+ platform: ruby
6
+ authors:
7
+ - aycabta
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-02-14 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: io-console
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.5'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.5'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: test-unit
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: Alternative GNU Readline or Editline implementation by pure Ruby.
70
+ email:
71
+ - aycabta@gmail.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - BSDL
77
+ - COPYING
78
+ - README.md
79
+ - lib/reline.rb
80
+ - lib/reline/ansi.rb
81
+ - lib/reline/config.rb
82
+ - lib/reline/general_io.rb
83
+ - lib/reline/history.rb
84
+ - lib/reline/key_actor.rb
85
+ - lib/reline/key_actor/base.rb
86
+ - lib/reline/key_actor/emacs.rb
87
+ - lib/reline/key_actor/vi_command.rb
88
+ - lib/reline/key_actor/vi_insert.rb
89
+ - lib/reline/key_stroke.rb
90
+ - lib/reline/kill_ring.rb
91
+ - lib/reline/line_editor.rb
92
+ - lib/reline/unicode.rb
93
+ - lib/reline/unicode/east_asian_width.rb
94
+ - lib/reline/version.rb
95
+ - lib/reline/windows.rb
96
+ homepage: https://github.com/ruby/reline
97
+ licenses:
98
+ - Ruby License
99
+ metadata: {}
100
+ post_install_message:
101
+ rdoc_options: []
102
+ require_paths:
103
+ - lib
104
+ required_ruby_version: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - ">="
107
+ - !ruby/object:Gem::Version
108
+ version: '2.5'
109
+ required_rubygems_version: !ruby/object:Gem::Requirement
110
+ requirements:
111
+ - - ">="
112
+ - !ruby/object:Gem::Version
113
+ version: '0'
114
+ requirements: []
115
+ rubygems_version: 3.1.2
116
+ signing_key:
117
+ specification_version: 4
118
+ summary: Alternative GNU Readline or Editline implementation by pure Ruby.
119
+ test_files: []