reline 0.0.4

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