reline 0.0.1 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -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.