reline 0.1.0 → 0.1.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +4 -0
- data/lib/reline.rb +41 -25
- data/lib/reline/ansi.rb +79 -18
- data/lib/reline/config.rb +69 -10
- data/lib/reline/general_io.rb +8 -0
- data/lib/reline/history.rb +33 -13
- data/lib/reline/key_actor/emacs.rb +7 -7
- data/lib/reline/key_actor/vi_command.rb +2 -2
- data/lib/reline/key_actor/vi_insert.rb +2 -2
- data/lib/reline/key_stroke.rb +2 -0
- data/lib/reline/line_editor.rb +305 -119
- data/lib/reline/unicode.rb +68 -0
- data/lib/reline/version.rb +1 -1
- data/lib/reline/windows.rb +51 -5
- metadata +7 -7
data/lib/reline/unicode.rb
CHANGED
@@ -35,6 +35,12 @@ class Reline::Unicode
|
|
35
35
|
}
|
36
36
|
EscapedChars = EscapedPairs.keys.map(&:chr)
|
37
37
|
|
38
|
+
CSI_REGEXP = /\e\[[\d;]*[ABCDEFGHJKSTfminsuhl]/
|
39
|
+
OSC_REGEXP = /\e\]\d+(?:;[^;]+)*\a/
|
40
|
+
NON_PRINTING_START = "\1"
|
41
|
+
NON_PRINTING_END = "\2"
|
42
|
+
WIDTH_SCANNER = /\G(?:#{NON_PRINTING_START}|#{NON_PRINTING_END}|#{CSI_REGEXP}|#{OSC_REGEXP}|\X)/
|
43
|
+
|
38
44
|
def self.get_mbchar_byte_size_by_first_char(c)
|
39
45
|
# Checks UTF-8 character byte size
|
40
46
|
case c.ord
|
@@ -85,6 +91,68 @@ class Reline::Unicode
|
|
85
91
|
end
|
86
92
|
end
|
87
93
|
|
94
|
+
def self.calculate_width(str, allow_escape_code = false)
|
95
|
+
if allow_escape_code
|
96
|
+
width = 0
|
97
|
+
rest = str.encode(Encoding::UTF_8)
|
98
|
+
in_zero_width = false
|
99
|
+
rest.scan(WIDTH_SCANNER) do |gc|
|
100
|
+
case gc
|
101
|
+
when NON_PRINTING_START
|
102
|
+
in_zero_width = true
|
103
|
+
when NON_PRINTING_END
|
104
|
+
in_zero_width = false
|
105
|
+
when CSI_REGEXP, OSC_REGEXP
|
106
|
+
else
|
107
|
+
unless in_zero_width
|
108
|
+
width += get_mbchar_width(gc)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
width
|
113
|
+
else
|
114
|
+
str.encode(Encoding::UTF_8).grapheme_clusters.inject(0) { |w, gc|
|
115
|
+
w + get_mbchar_width(gc)
|
116
|
+
}
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def self.split_by_width(str, max_width, encoding = str.encoding)
|
121
|
+
lines = [String.new(encoding: encoding)]
|
122
|
+
height = 1
|
123
|
+
width = 0
|
124
|
+
rest = str.encode(Encoding::UTF_8)
|
125
|
+
in_zero_width = false
|
126
|
+
rest.scan(WIDTH_SCANNER) do |gc|
|
127
|
+
case gc
|
128
|
+
when NON_PRINTING_START
|
129
|
+
in_zero_width = true
|
130
|
+
when NON_PRINTING_END
|
131
|
+
in_zero_width = false
|
132
|
+
when CSI_REGEXP, OSC_REGEXP
|
133
|
+
lines.last << gc
|
134
|
+
else
|
135
|
+
unless in_zero_width
|
136
|
+
mbchar_width = get_mbchar_width(gc)
|
137
|
+
if (width += mbchar_width) > max_width
|
138
|
+
width = mbchar_width
|
139
|
+
lines << nil
|
140
|
+
lines << String.new(encoding: encoding)
|
141
|
+
height += 1
|
142
|
+
end
|
143
|
+
end
|
144
|
+
lines.last << gc
|
145
|
+
end
|
146
|
+
end
|
147
|
+
# The cursor moves to next line in first
|
148
|
+
if width == max_width
|
149
|
+
lines << nil
|
150
|
+
lines << String.new(encoding: encoding)
|
151
|
+
height += 1
|
152
|
+
end
|
153
|
+
[lines, height]
|
154
|
+
end
|
155
|
+
|
88
156
|
def self.get_next_mbchar_size(line, byte_pointer)
|
89
157
|
grapheme = line.byteslice(byte_pointer..-1).grapheme_clusters.first
|
90
158
|
grapheme ? grapheme.bytesize : 0
|
data/lib/reline/version.rb
CHANGED
data/lib/reline/windows.rb
CHANGED
@@ -1,6 +1,14 @@
|
|
1
1
|
require 'fiddle/import'
|
2
2
|
|
3
3
|
class Reline::Windows
|
4
|
+
def self.encoding
|
5
|
+
Encoding::UTF_8
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.win?
|
9
|
+
true
|
10
|
+
end
|
11
|
+
|
4
12
|
RAW_KEYSTROKE_CONFIG = {
|
5
13
|
[224, 72] => :ed_prev_history, # ↑
|
6
14
|
[224, 80] => :ed_next_history, # ↓
|
@@ -68,6 +76,8 @@ class Reline::Windows
|
|
68
76
|
STD_INPUT_HANDLE = -10
|
69
77
|
STD_OUTPUT_HANDLE = -11
|
70
78
|
WINDOW_BUFFER_SIZE_EVENT = 0x04
|
79
|
+
FILE_TYPE_PIPE = 0x0003
|
80
|
+
FILE_NAME_INFO = 2
|
71
81
|
@@getwch = Win32API.new('msvcrt', '_getwch', [], 'I')
|
72
82
|
@@kbhit = Win32API.new('msvcrt', '_kbhit', [], 'I')
|
73
83
|
@@GetKeyState = Win32API.new('user32', 'GetKeyState', ['L'], 'L')
|
@@ -80,9 +90,37 @@ class Reline::Windows
|
|
80
90
|
@@hConsoleInputHandle = @@GetStdHandle.call(STD_INPUT_HANDLE)
|
81
91
|
@@GetNumberOfConsoleInputEvents = Win32API.new('kernel32', 'GetNumberOfConsoleInputEvents', ['L', 'P'], 'L')
|
82
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
|
+
@@FillConsoleOutputAttribute = Win32API.new('kernel32', 'FillConsoleOutputAttribute', ['L', 'L', 'L', 'L', 'P'], 'L')
|
96
|
+
|
83
97
|
@@input_buf = []
|
84
98
|
@@output_buf = []
|
85
99
|
|
100
|
+
def self.msys_tty?(io=@@hConsoleInputHandle)
|
101
|
+
# check if fd is a pipe
|
102
|
+
if @@GetFileType.call(io) != FILE_TYPE_PIPE
|
103
|
+
return false
|
104
|
+
end
|
105
|
+
|
106
|
+
bufsize = 1024
|
107
|
+
p_buffer = "\0" * bufsize
|
108
|
+
res = @@GetFileInformationByHandleEx.call(io, FILE_NAME_INFO, p_buffer, bufsize - 2)
|
109
|
+
return false if res == 0
|
110
|
+
|
111
|
+
# get pipe name: p_buffer layout is:
|
112
|
+
# struct _FILE_NAME_INFO {
|
113
|
+
# DWORD FileNameLength;
|
114
|
+
# WCHAR FileName[1];
|
115
|
+
# } FILE_NAME_INFO
|
116
|
+
len = p_buffer[0, 4].unpack("L")[0]
|
117
|
+
name = p_buffer[4, len].encode(Encoding::UTF_8, Encoding::UTF_16LE, invalid: :replace)
|
118
|
+
|
119
|
+
# Check if this could be a MSYS2 pty pipe ('\msys-XXXX-ptyN-XX')
|
120
|
+
# or a cygwin pty pipe ('\cygwin-XXXX-ptyN-XX')
|
121
|
+
name =~ /(msys-|cygwin-).*-pty/ ? true : false
|
122
|
+
end
|
123
|
+
|
86
124
|
def self.getwch
|
87
125
|
unless @@input_buf.empty?
|
88
126
|
return @@input_buf.shift
|
@@ -99,7 +137,7 @@ class Reline::Windows
|
|
99
137
|
return @@input_buf.shift
|
100
138
|
end
|
101
139
|
begin
|
102
|
-
bytes = ret.chr(Encoding::UTF_8).
|
140
|
+
bytes = ret.chr(Encoding::UTF_8).bytes
|
103
141
|
@@input_buf.push(*bytes)
|
104
142
|
rescue Encoding::UndefinedConversionError
|
105
143
|
@@input_buf << ret
|
@@ -205,16 +243,24 @@ class Reline::Windows
|
|
205
243
|
|
206
244
|
def self.scroll_down(val)
|
207
245
|
return if val.zero?
|
208
|
-
scroll_rectangle = [0, val, get_screen_size.
|
246
|
+
scroll_rectangle = [0, val, get_screen_size.last, get_screen_size.first].pack('s4')
|
209
247
|
destination_origin = 0 # y * 65536 + x
|
210
248
|
fill = [' '.ord, 0].pack('SS')
|
211
249
|
@@ScrollConsoleScreenBuffer.call(@@hConsoleHandle, scroll_rectangle, nil, destination_origin, fill)
|
212
250
|
end
|
213
251
|
|
214
252
|
def self.clear_screen
|
215
|
-
|
216
|
-
|
217
|
-
|
253
|
+
csbi = 0.chr * 22
|
254
|
+
return if @@GetConsoleScreenBufferInfo.call(@@hConsoleHandle, csbi) == 0
|
255
|
+
buffer_width = csbi[0, 2].unpack('S').first
|
256
|
+
attributes = csbi[8, 2].unpack('S').first
|
257
|
+
_window_left, window_top, _window_right, window_bottom = *csbi[10,8].unpack('S*')
|
258
|
+
fill_length = buffer_width * (window_bottom - window_top + 1)
|
259
|
+
screen_topleft = window_top * 65536
|
260
|
+
written = 0.chr * 4
|
261
|
+
@@FillConsoleOutputCharacter.call(@@hConsoleHandle, 0x20, fill_length, screen_topleft, written)
|
262
|
+
@@FillConsoleOutputAttribute.call(@@hConsoleHandle, attributes, fill_length, screen_topleft, written)
|
263
|
+
@@SetConsoleCursorPosition.call(@@hConsoleHandle, screen_topleft)
|
218
264
|
end
|
219
265
|
|
220
266
|
def self.set_screen_size(rows, columns)
|
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.1.
|
4
|
+
version: 0.1.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- aycabta
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-09-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: io-console
|
@@ -95,9 +95,9 @@ files:
|
|
95
95
|
- lib/reline/windows.rb
|
96
96
|
homepage: https://github.com/ruby/reline
|
97
97
|
licenses:
|
98
|
-
- Ruby
|
98
|
+
- Ruby
|
99
99
|
metadata: {}
|
100
|
-
post_install_message:
|
100
|
+
post_install_message:
|
101
101
|
rdoc_options: []
|
102
102
|
require_paths:
|
103
103
|
- lib
|
@@ -112,8 +112,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
112
112
|
- !ruby/object:Gem::Version
|
113
113
|
version: '0'
|
114
114
|
requirements: []
|
115
|
-
rubygems_version: 3.1.
|
116
|
-
signing_key:
|
115
|
+
rubygems_version: 3.1.2
|
116
|
+
signing_key:
|
117
117
|
specification_version: 4
|
118
118
|
summary: Alternative GNU Readline or Editline implementation by pure Ruby.
|
119
119
|
test_files: []
|