reline 0.0.1 → 0.0.6

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.
@@ -1,6 +1,6 @@
1
1
  class Reline::Unicode::EastAsianWidth
2
2
  # This is based on EastAsianWidth.txt
3
- # http://www.unicode.org/Public/10.0.0/ucd/EastAsianWidth.txt
3
+ # http://www.unicode.org/Public/12.1.0/ucd/EastAsianWidth.txt
4
4
 
5
5
  # Fullwidth
6
6
  TYPE_F = /^(
@@ -1,3 +1,3 @@
1
1
  module Reline
2
- VERSION = '0.0.1'
2
+ VERSION = '0.0.6'
3
3
  end
@@ -9,49 +9,65 @@ class Reline::Windows
9
9
  [224, 83] => :key_delete, # Del
10
10
  [224, 71] => :ed_move_to_beg, # Home
11
11
  [224, 79] => :ed_move_to_end, # End
12
- }.each_key(&:freeze).freeze
13
-
14
- class Win32API
15
- DLL = {}
16
- TYPEMAP = {"0" => Fiddle::TYPE_VOID, "S" => Fiddle::TYPE_VOIDP, "I" => Fiddle::TYPE_LONG}
17
- POINTER_TYPE = Fiddle::SIZEOF_VOIDP == Fiddle::SIZEOF_LONG_LONG ? 'q*' : 'l!*'
18
-
19
- WIN32_TYPES = "VPpNnLlIi"
20
- DL_TYPES = "0SSI"
21
-
22
- def initialize(dllname, func, import, export = "0", calltype = :stdcall)
23
- @proto = [import].join.tr(WIN32_TYPES, DL_TYPES).sub(/^(.)0*$/, '\1')
24
- import = @proto.chars.map {|win_type| TYPEMAP[win_type.tr(WIN32_TYPES, DL_TYPES)]}
25
- export = TYPEMAP[export.tr(WIN32_TYPES, DL_TYPES)]
26
- calltype = Fiddle::Importer.const_get(:CALL_TYPE_TO_ABI)[calltype]
27
-
28
- handle = DLL[dllname] ||=
29
- begin
30
- Fiddle.dlopen(dllname)
31
- rescue Fiddle::DLError
32
- raise unless File.extname(dllname).empty?
33
- Fiddle.dlopen(dllname + ".dll")
34
- end
35
-
36
- @func = Fiddle::Function.new(handle[func], import, export, calltype)
37
- rescue Fiddle::DLError => e
38
- raise LoadError, e.message, e.backtrace
39
- 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
40
51
 
41
- def call(*args)
42
- import = @proto.split("")
43
- args.each_with_index do |x, i|
44
- args[i], = [x == 0 ? nil : x].pack("p").unpack(POINTER_TYPE) if import[i] == "S"
45
- args[i], = [x].pack("I").unpack("i") if import[i] == "I"
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
46
60
  end
47
- ret, = @func.call(*args)
48
- return ret || 0
49
61
  end
50
62
  end
51
63
 
52
64
  VK_MENU = 0x12
65
+ VK_LMENU = 0xA4
66
+ VK_CONTROL = 0x11
53
67
  VK_SHIFT = 0x10
68
+ STD_INPUT_HANDLE = -10
54
69
  STD_OUTPUT_HANDLE = -11
70
+ WINDOW_BUFFER_SIZE_EVENT = 0x04
55
71
  @@getwch = Win32API.new('msvcrt', '_getwch', [], 'I')
56
72
  @@kbhit = Win32API.new('msvcrt', '_kbhit', [], 'I')
57
73
  @@GetKeyState = Win32API.new('user32', 'GetKeyState', ['L'], 'L')
@@ -61,77 +77,101 @@ class Reline::Windows
61
77
  @@FillConsoleOutputCharacter = Win32API.new('kernel32', 'FillConsoleOutputCharacter', ['L', 'L', 'L', 'L', 'P'], 'L')
62
78
  @@ScrollConsoleScreenBuffer = Win32API.new('kernel32', 'ScrollConsoleScreenBuffer', ['L', 'P', 'P', 'L', 'P'], 'L')
63
79
  @@hConsoleHandle = @@GetStdHandle.call(STD_OUTPUT_HANDLE)
64
- @@buf = []
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 = []
65
85
 
66
86
  def self.getwch
87
+ unless @@input_buf.empty?
88
+ return @@input_buf.shift
89
+ end
67
90
  while @@kbhit.call == 0
68
91
  sleep(0.001)
69
92
  end
70
- result = []
71
93
  until @@kbhit.call == 0
72
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
73
101
  begin
74
- result.concat(ret.chr(Encoding::UTF_8).encode(Encoding.default_external).bytes)
102
+ bytes = ret.chr(Encoding::UTF_8).encode(Encoding.default_external).bytes
103
+ @@input_buf.push(*bytes)
75
104
  rescue Encoding::UndefinedConversionError
76
- result << ret
77
- result << @@getwch.call if ret == 224
105
+ @@input_buf << ret
106
+ @@input_buf << @@getwch.call if ret == 224
78
107
  end
79
108
  end
80
- result
109
+ @@input_buf.shift
81
110
  end
82
111
 
83
112
  def self.getc
84
- unless @@buf.empty?
85
- return @@buf.shift
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
86
126
  end
87
127
  input = getwch
88
- alt = (@@GetKeyState.call(VK_MENU) & 0x80) != 0
89
- shift_enter = (@@GetKeyState.call(VK_SHIFT) & 0x80) != 0 && input.first == 0x0D
90
- if shift_enter
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
91
133
  # It's treated as Meta+Enter on Windows
92
- @@buf.concat(["\e".ord])
93
- @@buf.concat(input)
94
- elsif input.size > 1
95
- @@buf.concat(input)
96
- else # single byte
97
- case input[0]
134
+ @@output_buf.push("\e".ord)
135
+ @@output_buf.push(input)
136
+ else
137
+ case input
98
138
  when 0x00
99
- getwch
100
- alt = false
139
+ meta = false
140
+ @@output_buf.push(input)
101
141
  input = getwch
102
- @@buf.concat(input)
142
+ @@output_buf.push(*input)
103
143
  when 0xE0
104
- @@buf.concat(input)
144
+ @@output_buf.push(input)
105
145
  input = getwch
106
- @@buf.concat(input)
146
+ @@output_buf.push(*input)
107
147
  when 0x03
108
- @@buf.concat(input)
148
+ @@output_buf.push(input)
109
149
  else
110
- @@buf.concat(input)
150
+ @@output_buf.push(input)
111
151
  end
112
152
  end
113
- if alt
153
+ if meta
114
154
  "\e".ord
115
155
  else
116
- @@buf.shift
156
+ @@output_buf.shift
117
157
  end
118
158
  end
119
159
 
120
160
  def self.ungetc(c)
121
- @@buf.unshift(c)
161
+ @@output_buf.unshift(c)
122
162
  end
123
163
 
124
164
  def self.get_screen_size
125
- csbi = 0.chr * 24
165
+ csbi = 0.chr * 22
126
166
  @@GetConsoleScreenBufferInfo.call(@@hConsoleHandle, csbi)
127
167
  csbi[0, 4].unpack('SS').reverse
128
168
  end
129
169
 
130
170
  def self.cursor_pos
131
- csbi = 0.chr * 24
171
+ csbi = 0.chr * 22
132
172
  @@GetConsoleScreenBufferInfo.call(@@hConsoleHandle, csbi)
133
173
  x = csbi[4, 2].unpack('s*').first
134
- y = csbi[6, 4].unpack('s*').first
174
+ y = csbi[6, 2].unpack('s*').first
135
175
  Reline::CursorPos.new(x, y)
136
176
  end
137
177
 
@@ -181,6 +221,10 @@ class Reline::Windows
181
221
  raise NotImplementedError
182
222
  end
183
223
 
224
+ def self.set_winch_handler(&handler)
225
+ @@winch_handler = handler
226
+ end
227
+
184
228
  def self.prep
185
229
  # do nothing
186
230
  nil
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: reline
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - aycabta
8
8
  autorequire:
9
- bindir: exe
9
+ bindir: bin
10
10
  cert_chain: []
11
- date: 2019-07-14 00:00:00.000000000 Z
11
+ date: 2019-11-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -98,7 +98,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
98
98
  - !ruby/object:Gem::Version
99
99
  version: '0'
100
100
  requirements: []
101
- rubygems_version: 3.0.4
101
+ rubygems_version: 3.0.6
102
102
  signing_key:
103
103
  specification_version: 4
104
104
  summary: Alternative GNU Readline or Editline implementation by pure Ruby.