reline 0.3.0 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2e8c2181e5eb21934546d6b768715cb47eab6e1ea1edb2fd2300f43af62dc2b1
4
- data.tar.gz: 99a61e2729d4b5d150f6f59d99d6de235ea4f1aab6ac262c92fff6a77101b85f
3
+ metadata.gz: 8198104fe3ad27c73acaaffc9c8b1c8b9a5c50069a26a71cd940dd2b5dc13afc
4
+ data.tar.gz: 171ff8cdf2ae4aebaf4cfb6cea131e2d90e5eb56a2c09dbe19acfa8765522ffc
5
5
  SHA512:
6
- metadata.gz: 96ceefe0bf71e7e44ccd2a5970b35fc44019af9d7da4d2e04ac1d827eb6bc6a201e679a5e40c4db976554159286f16e39cdeac68bcf69c2c5abeb00a2045e563
7
- data.tar.gz: 251c2029df6b3073010ad6a591fb216990124ed4f9e00f533e79461be66c6a2383ea56c1554dd273e4af3cfc9358dee37b76a1b4bff25a1867972201bfebace3
6
+ metadata.gz: e3411f0086a0445d2d805fc46528a86b947c58b8e61a664dc08b437596702ef1f360cd7e85a1dab64bf159f6f39691b9d5110f951bd5376f4fce0439e9557532
7
+ data.tar.gz: 968ac4a376ba350590fd37d05525a5a2e5e26c44e159b5fd9b0c7400e260850e91088357c007651373d44b7b7d37c699852014d07258428be86081581baf0229
data/lib/reline/ansi.rb CHANGED
@@ -150,7 +150,7 @@ class Reline::ANSI
150
150
  until c = @@input.raw(intr: true) { @@input.wait_readable(0.1) && @@input.getbyte }
151
151
  Reline.core.line_editor.resize
152
152
  end
153
- (c == 0x16 && @@input.raw(min: 0, tim: 0, &:getbyte)) || c
153
+ (c == 0x16 && @@input.raw(min: 0, time: 0, &:getbyte)) || c
154
154
  rescue Errno::EIO
155
155
  # Maybe the I/O has been closed.
156
156
  nil
data/lib/reline/config.rb CHANGED
@@ -45,6 +45,8 @@ class Reline::Config
45
45
  attr_accessor v
46
46
  end
47
47
 
48
+ attr_accessor :autocompletion
49
+
48
50
  def initialize
49
51
  @additional_key_bindings = {} # from inputrc
50
52
  @additional_key_bindings[:emacs] = {}
@@ -55,6 +57,7 @@ class Reline::Config
55
57
  @if_stack = nil
56
58
  @editing_mode_label = :emacs
57
59
  @keymap_label = :emacs
60
+ @keymap_prefix = []
58
61
  @key_actors = {}
59
62
  @key_actors[:emacs] = Reline::KeyActor::Emacs.new
60
63
  @key_actors[:vi_insert] = Reline::KeyActor::ViInsert.new
@@ -93,14 +96,6 @@ class Reline::Config
93
96
  (val.respond_to?(:any?) ? val : [val]).any?(@editing_mode_label)
94
97
  end
95
98
 
96
- def autocompletion=(val)
97
- @autocompletion = val
98
- end
99
-
100
- def autocompletion
101
- @autocompletion
102
- end
103
-
104
99
  def keymap
105
100
  @key_actors[@keymap_label]
106
101
  end
@@ -221,7 +216,7 @@ class Reline::Config
221
216
  key, func_name = $1, $2
222
217
  keystroke, func = bind_key(key, func_name)
223
218
  next unless keystroke
224
- @additional_key_bindings[@keymap_label][keystroke] = func
219
+ @additional_key_bindings[@keymap_label][@keymap_prefix + keystroke] = func
225
220
  end
226
221
  end
227
222
  unless @if_stack.empty?
@@ -292,18 +287,29 @@ class Reline::Config
292
287
  when 'emacs'
293
288
  @editing_mode_label = :emacs
294
289
  @keymap_label = :emacs
290
+ @keymap_prefix = []
295
291
  when 'vi'
296
292
  @editing_mode_label = :vi_insert
297
293
  @keymap_label = :vi_insert
294
+ @keymap_prefix = []
298
295
  end
299
296
  when 'keymap'
300
297
  case value
301
- when 'emacs', 'emacs-standard', 'emacs-meta', 'emacs-ctlx'
298
+ when 'emacs', 'emacs-standard'
299
+ @keymap_label = :emacs
300
+ @keymap_prefix = []
301
+ when 'emacs-ctlx'
302
+ @keymap_label = :emacs
303
+ @keymap_prefix = [?\C-x.ord]
304
+ when 'emacs-meta'
302
305
  @keymap_label = :emacs
306
+ @keymap_prefix = [?\e.ord]
303
307
  when 'vi', 'vi-move', 'vi-command'
304
308
  @keymap_label = :vi_command
309
+ @keymap_prefix = []
305
310
  when 'vi-insert'
306
311
  @keymap_label = :vi_insert
312
+ @keymap_prefix = []
307
313
  end
308
314
  when 'keyseq-timeout'
309
315
  @keyseq_timeout = value.to_i
@@ -57,6 +57,12 @@ class Reline::GeneralIO
57
57
  Reline::CursorPos.new(1, 1)
58
58
  end
59
59
 
60
+ def self.hide_cursor
61
+ end
62
+
63
+ def self.show_cursor
64
+ end
65
+
60
66
  def self.move_cursor_column(val)
61
67
  end
62
68
 
@@ -43,7 +43,7 @@ class Reline::KeyActor::Emacs < Reline::KeyActor::Base
43
43
  # 20 ^T
44
44
  :ed_transpose_chars,
45
45
  # 21 ^U
46
- :ed_kill_line,
46
+ :unix_line_discard,
47
47
  # 22 ^V
48
48
  :ed_quoted_insert,
49
49
  # 23 ^W
@@ -466,15 +466,17 @@ class Reline::LineEditor
466
466
  new_highest_in_this = calculate_height_by_width(prompt_width + calculate_width(@line.nil? ? '' : @line))
467
467
  rendered = false
468
468
  if @add_newline_to_end_of_buffer
469
+ clear_dialog_with_content
469
470
  rerender_added_newline(prompt, prompt_width)
470
471
  @add_newline_to_end_of_buffer = false
471
472
  else
472
473
  if @just_cursor_moving and not @rerender_all
474
+ clear_dialog_with_content
473
475
  rendered = just_move_cursor
474
- render_dialog((prompt_width + @cursor) % @screen_size.last)
475
476
  @just_cursor_moving = false
476
477
  return
477
478
  elsif @previous_line_index or new_highest_in_this != @highest_in_this
479
+ clear_dialog_with_content
478
480
  rerender_changed_current_line
479
481
  @previous_line_index = nil
480
482
  rendered = true
@@ -653,7 +655,10 @@ class Reline::LineEditor
653
655
  end
654
656
 
655
657
  private def padding_space_with_escape_sequences(str, width)
656
- str + (' ' * (width - calculate_width(str, true)))
658
+ padding_width = width - calculate_width(str, true)
659
+ # padding_width should be only positive value. But macOS and Alacritty returns negative value.
660
+ padding_width = 0 if padding_width < 0
661
+ str + (' ' * padding_width)
657
662
  end
658
663
 
659
664
  private def render_each_dialog(dialog, cursor_column)
@@ -741,24 +746,21 @@ class Reline::LineEditor
741
746
  Reline::IOGate.move_cursor_column(dialog.column)
742
747
  dialog.contents.each_with_index do |item, i|
743
748
  if i == pointer
744
- bg_color = '45'
749
+ fg_color = dialog_render_info.pointer_fg_color
750
+ bg_color = dialog_render_info.pointer_bg_color
745
751
  else
746
- if dialog_render_info.bg_color
747
- bg_color = dialog_render_info.bg_color
748
- else
749
- bg_color = '46'
750
- end
752
+ fg_color = dialog_render_info.fg_color
753
+ bg_color = dialog_render_info.bg_color
751
754
  end
752
755
  str_width = dialog.width - (dialog.scrollbar_pos.nil? ? 0 : @block_elem_width)
753
756
  str = padding_space_with_escape_sequences(Reline::Unicode.take_range(item, 0, str_width), str_width)
754
- @output.write "\e[#{bg_color}m#{str}"
757
+ @output.write "\e[#{bg_color}m\e[#{fg_color}m#{str}"
755
758
  if dialog.scrollbar_pos and (dialog.scrollbar_pos != old_dialog.scrollbar_pos or dialog.column != old_dialog.column)
756
759
  @output.write "\e[37m"
757
760
  if dialog.scrollbar_pos <= (i * 2) and (i * 2 + 1) < (dialog.scrollbar_pos + bar_height)
758
761
  @output.write @full_block
759
762
  elsif dialog.scrollbar_pos <= (i * 2) and (i * 2) < (dialog.scrollbar_pos + bar_height)
760
763
  @output.write @upper_half_block
761
- str += ''
762
764
  elsif dialog.scrollbar_pos <= (i * 2 + 1) and (i * 2) < (dialog.scrollbar_pos + bar_height)
763
765
  @output.write @lower_half_block
764
766
  else
@@ -883,6 +885,14 @@ class Reline::LineEditor
883
885
  end
884
886
  end
885
887
 
888
+ private def clear_dialog_with_content
889
+ @dialogs.each do |dialog|
890
+ clear_each_dialog(dialog)
891
+ dialog.contents = nil
892
+ dialog.trap_key = nil
893
+ end
894
+ end
895
+
886
896
  private def clear_each_dialog(dialog)
887
897
  dialog.trap_key = nil
888
898
  return unless dialog.contents
@@ -1420,7 +1430,7 @@ class Reline::LineEditor
1420
1430
  if @waiting_operator_proc
1421
1431
  if VI_MOTIONS.include?(method_symbol)
1422
1432
  old_cursor, old_byte_pointer = @cursor, @byte_pointer
1423
- @vi_arg = @waiting_operator_vi_arg if @waiting_operator_vi_arg > 1
1433
+ @vi_arg = @waiting_operator_vi_arg if @waiting_operator_vi_arg&.> 1
1424
1434
  block.(true)
1425
1435
  unless @waiting_proc
1426
1436
  cursor_diff, byte_pointer_diff = @cursor - old_cursor, @byte_pointer - old_byte_pointer
@@ -2223,6 +2233,8 @@ class Reline::LineEditor
2223
2233
  @buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
2224
2234
  @line_index = @buffer_of_lines.size - 1
2225
2235
  @line = @buffer_of_lines.last
2236
+ @byte_pointer = @line.bytesize
2237
+ @cursor = @cursor_max = calculate_width(@line)
2226
2238
  @rerender_all = true
2227
2239
  @searching_prompt = "(%s)`%s'" % [prompt_name, search_word]
2228
2240
  else
@@ -35,7 +35,7 @@ module Reline::Terminfo
35
35
  # Gem module isn't defined in test-all of the Ruby repository, and
36
36
  # Fiddle in Ruby 3.0.0 or later supports Fiddle::TYPE_VARIADIC.
37
37
  fiddle_supports_variadic = true
38
- elsif Fiddle.const_defined?(:VERSION) and Gem::Version.create(Fiddle::VERSION) >= Gem::Version.create('1.0.1')
38
+ elsif Fiddle.const_defined?(:VERSION,false) and Gem::Version.create(Fiddle::VERSION) >= Gem::Version.create('1.0.1')
39
39
  # Fiddle::TYPE_VARIADIC is supported from Fiddle 1.0.1.
40
40
  fiddle_supports_variadic = true
41
41
  else
@@ -74,12 +74,27 @@ module Reline::Terminfo
74
74
  #extern 'char *tparm(const char *str, ...)'
75
75
  @tiparm = Fiddle::Function.new(curses_dl['tparm'], [Fiddle::TYPE_VOIDP, Fiddle::TYPE_VARIADIC], Fiddle::TYPE_VOIDP)
76
76
  end
77
- # TODO: add int tigetflag(char *capname) and int tigetnum(char *capname)
77
+ begin
78
+ #extern 'int tigetflag(char *str)'
79
+ @tigetflag = Fiddle::Function.new(curses_dl['tigetflag'], [Fiddle::TYPE_VOIDP], Fiddle::TYPE_INT)
80
+ rescue Fiddle::DLError
81
+ # OpenBSD lacks tigetflag
82
+ #extern 'int tgetflag(char *str)'
83
+ @tigetflag = Fiddle::Function.new(curses_dl['tgetflag'], [Fiddle::TYPE_VOIDP], Fiddle::TYPE_INT)
84
+ end
85
+ begin
86
+ #extern 'int tigetnum(char *str)'
87
+ @tigetnum = Fiddle::Function.new(curses_dl['tigetnum'], [Fiddle::TYPE_VOIDP], Fiddle::TYPE_INT)
88
+ rescue Fiddle::DLError
89
+ # OpenBSD lacks tigetnum
90
+ #extern 'int tgetnum(char *str)'
91
+ @tigetnum = Fiddle::Function.new(curses_dl['tgetnum'], [Fiddle::TYPE_VOIDP], Fiddle::TYPE_INT)
92
+ end
78
93
 
79
94
  def self.setupterm(term, fildes)
80
- errret_int = String.new("\x00" * 8, encoding: 'ASCII-8BIT')
95
+ errret_int = Fiddle::Pointer.malloc(Fiddle::SIZEOF_INT)
81
96
  ret = @setupterm.(term, fildes, errret_int)
82
- errret = errret_int.unpack1('i')
97
+ errret = errret_int[0, Fiddle::SIZEOF_INT].unpack1('i')
83
98
  case ret
84
99
  when 0 # OK
85
100
  0
@@ -106,6 +121,7 @@ module Reline::Terminfo
106
121
  end
107
122
 
108
123
  def self.tigetstr(capname)
124
+ raise TerminfoError, "capname is not String: #{capname.inspect}" unless capname.is_a?(String)
109
125
  capability = @tigetstr.(capname)
110
126
  case capability.to_i
111
127
  when 0, -1
@@ -122,6 +138,30 @@ module Reline::Terminfo
122
138
  @tiparm.(str, *new_args).to_s
123
139
  end
124
140
 
141
+ def self.tigetflag(capname)
142
+ raise TerminfoError, "capname is not String: #{capname.inspect}" unless capname.is_a?(String)
143
+ flag = @tigetflag.(capname).to_i
144
+ case flag
145
+ when -1
146
+ raise TerminfoError, "not boolean capability: #{capname}"
147
+ when 0
148
+ raise TerminfoError, "can't find capability: #{capname}"
149
+ end
150
+ flag
151
+ end
152
+
153
+ def self.tigetnum(capname)
154
+ raise TerminfoError, "capname is not String: #{capname.inspect}" unless capname.is_a?(String)
155
+ num = @tigetnum.(capname).to_i
156
+ case num
157
+ when -2
158
+ raise TerminfoError, "not numeric capability: #{capname}"
159
+ when -1
160
+ raise TerminfoError, "can't find capability: #{capname}"
161
+ end
162
+ num
163
+ end
164
+
125
165
  def self.enabled?
126
166
  true
127
167
  end
@@ -1,3 +1,3 @@
1
1
  module Reline
2
- VERSION = '0.3.0'
2
+ VERSION = '0.3.2'
3
3
  end
@@ -95,7 +95,7 @@ class Reline::Windows
95
95
  end
96
96
 
97
97
  VK_RETURN = 0x0D
98
- VK_MENU = 0x12
98
+ VK_MENU = 0x12 # ALT key
99
99
  VK_LMENU = 0xA4
100
100
  VK_CONTROL = 0x11
101
101
  VK_SHIFT = 0x10
@@ -249,7 +249,7 @@ class Reline::Windows
249
249
  # no char, only control keys
250
250
  return if key.char_code == 0 and key.control_keys.any?
251
251
 
252
- @@output_buf.push("\e".ord) if key.control_keys.include?(:ALT)
252
+ @@output_buf.push("\e".ord) if key.control_keys.include?(:ALT) and !key.control_keys.include?(:CTRL)
253
253
 
254
254
  @@output_buf.concat(key.char.bytes)
255
255
  end
@@ -386,7 +386,7 @@ class Reline::Windows
386
386
  def self.scroll_down(val)
387
387
  return if val < 0
388
388
  return unless csbi = get_console_screen_buffer_info
389
- buffer_width, x, y, buffer_lines, attributes, window_left, window_top, window_bottom = csbi.unpack('ssssSssx2s')
389
+ buffer_width, buffer_lines, x, y, attributes, window_left, window_top, window_bottom = csbi.unpack('ssssSssx2s')
390
390
  screen_height = window_bottom - window_top + 1
391
391
  val = screen_height if val > screen_height
392
392
 
data/lib/reline.rb CHANGED
@@ -33,7 +33,18 @@ module Reline
33
33
  alias_method :==, :match?
34
34
  end
35
35
  CursorPos = Struct.new(:x, :y)
36
- DialogRenderInfo = Struct.new(:pos, :contents, :bg_color, :width, :height, :scrollbar, keyword_init: true)
36
+ DialogRenderInfo = Struct.new(
37
+ :pos,
38
+ :contents,
39
+ :bg_color,
40
+ :pointer_bg_color,
41
+ :fg_color,
42
+ :pointer_fg_color,
43
+ :width,
44
+ :height,
45
+ :scrollbar,
46
+ keyword_init: true
47
+ )
37
48
 
38
49
  class Core
39
50
  ATTR_READER_NAMES = %i(
@@ -58,6 +69,11 @@ module Reline
58
69
  attr_accessor :last_incremental_search
59
70
  attr_reader :output
60
71
 
72
+ extend Forwardable
73
+ def_delegators :config,
74
+ :autocompletion,
75
+ :autocompletion=
76
+
61
77
  def initialize
62
78
  self.output = STDOUT
63
79
  @dialog_proc_list = {}
@@ -123,14 +139,6 @@ module Reline
123
139
  @completion_proc = p
124
140
  end
125
141
 
126
- def autocompletion
127
- @config.autocompletion
128
- end
129
-
130
- def autocompletion=(val)
131
- @config.autocompletion = val
132
- end
133
-
134
142
  def output_modifier_proc=(p)
135
143
  raise ArgumentError unless p.respond_to?(:call) or p.nil?
136
144
  @output_modifier_proc = p
@@ -243,7 +251,16 @@ module Reline
243
251
  context.push(cursor_pos_to_render, result, pointer, dialog)
244
252
  end
245
253
  dialog.pointer = pointer
246
- DialogRenderInfo.new(pos: cursor_pos_to_render, contents: result, scrollbar: true, height: 15)
254
+ DialogRenderInfo.new(
255
+ pos: cursor_pos_to_render,
256
+ contents: result,
257
+ scrollbar: true,
258
+ height: 15,
259
+ bg_color: 46,
260
+ pointer_bg_color: 45,
261
+ fg_color: 37,
262
+ pointer_fg_color: 37
263
+ )
247
264
  }
248
265
  Reline::DEFAULT_DIALOG_CONTEXT = Array.new
249
266
 
@@ -466,7 +483,7 @@ module Reline
466
483
  end
467
484
 
468
485
  private def may_req_ambiguous_char_width
469
- @ambiguous_width = 2 if Reline::IOGate == Reline::GeneralIO or STDOUT.is_a?(File)
486
+ @ambiguous_width = 2 if Reline::IOGate == Reline::GeneralIO or !STDOUT.tty?
470
487
  return if defined? @ambiguous_width
471
488
  Reline::IOGate.move_cursor_column(0)
472
489
  begin
@@ -563,24 +580,21 @@ module Reline
563
580
  end
564
581
 
565
582
  require 'reline/general_io'
566
- if RbConfig::CONFIG['host_os'] =~ /mswin|msys|mingw|cygwin|bccwin|wince|emc/
567
- require 'reline/windows'
568
- if Reline::Windows.msys_tty?
569
- Reline::IOGate = if ENV['TERM'] == 'dumb'
570
- Reline::GeneralIO
571
- else
572
- require 'reline/ansi'
573
- Reline::ANSI
574
- end
583
+ io = Reline::GeneralIO
584
+ unless ENV['TERM'] == 'dumb'
585
+ case RbConfig::CONFIG['host_os']
586
+ when /mswin|msys|mingw|cygwin|bccwin|wince|emc/
587
+ require 'reline/windows'
588
+ tty = (io = Reline::Windows).msys_tty?
575
589
  else
576
- Reline::IOGate = Reline::Windows
590
+ tty = $stdout.tty?
577
591
  end
592
+ end
593
+ Reline::IOGate = if tty
594
+ require 'reline/ansi'
595
+ Reline::ANSI
578
596
  else
579
- Reline::IOGate = if $stdout.isatty
580
- require 'reline/ansi'
581
- Reline::ANSI
582
- else
583
- Reline::GeneralIO
584
- end
597
+ io
585
598
  end
599
+
586
600
  Reline::HISTORY = Reline::History.new(Reline.core.config)
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.3.0
4
+ version: 0.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - aycabta
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-12-24 00:00:00.000000000 Z
11
+ date: 2022-12-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: io-console
@@ -47,7 +47,6 @@ files:
47
47
  - lib/reline/key_stroke.rb
48
48
  - lib/reline/kill_ring.rb
49
49
  - lib/reline/line_editor.rb
50
- - lib/reline/sibori.rb
51
50
  - lib/reline/terminfo.rb
52
51
  - lib/reline/unicode.rb
53
52
  - lib/reline/unicode/east_asian_width.rb
@@ -66,14 +65,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
66
65
  requirements:
67
66
  - - ">="
68
67
  - !ruby/object:Gem::Version
69
- version: '2.5'
68
+ version: '2.6'
70
69
  required_rubygems_version: !ruby/object:Gem::Requirement
71
70
  requirements:
72
71
  - - ">="
73
72
  - !ruby/object:Gem::Version
74
73
  version: '0'
75
74
  requirements: []
76
- rubygems_version: 3.2.22
75
+ rubygems_version: 3.4.0.dev
77
76
  signing_key:
78
77
  specification_version: 4
79
78
  summary: Alternative GNU Readline or Editline implementation by pure Ruby.
data/lib/reline/sibori.rb DELETED
@@ -1,170 +0,0 @@
1
- require 'reline/unicode'
2
-
3
- =begin
4
-
5
- \ |
6
- \ | <--- whipped cream
7
- \ |
8
- \ |
9
- \-~~|
10
- \ | <--- shibori kutigane (piping nozzle in Japanese)
11
- \Ml
12
- (\ __ __
13
- ( \--( ) )
14
- (__(__)__) <--- compressed whipped cream
15
- =end
16
-
17
- class Sibori
18
- attr_writer :output
19
-
20
- def initialize(width, height, cursor_pos)
21
- @width = width
22
- @height = height
23
- @cursor_pos = cursor_pos
24
- @screen = [String.new]
25
- @line_index = 0
26
- @byte_pointer_in_line = 0
27
- @cleared = false
28
- clone_screen
29
- end
30
-
31
- def clone_screen
32
- @prev_screen = @screen.map { |line|
33
- line.dup
34
- }
35
- @prev_cursor_pos = @cursor_pos.dup
36
- @prev_line_index = @line_index
37
- end
38
-
39
- def print(str)
40
- #$stderr.puts "print #{str.inspect}"
41
- line = @screen[@line_index]
42
- before = line.byteslice(0, @byte_pointer_in_line)
43
- str_width = Reline::Unicode.calculate_width(str, true)
44
- after_cursor = line.byteslice(@byte_pointer_in_line..-1)
45
- after_cursor_width = Reline::Unicode.calculate_width(after_cursor, true)
46
- rest = ''
47
- if after_cursor_width > str_width
48
- rest_byte_pointer = @byte_pointer_in_line + width_to_bytesize(after_cursor, str_width)
49
- rest = line.byteslice(rest_byte_pointer..-1)
50
- end
51
- @screen[@line_index] = before + str + rest
52
- @byte_pointer_in_line += str.bytesize
53
- @cursor_pos.x += Reline::Unicode.calculate_width(str, true)
54
- end
55
-
56
- def move_cursor_column(col)
57
- #$stderr.puts "move_cursor_column(#{col})"
58
- @byte_pointer_in_line = width_to_bytesize(@screen[@line_index], col)
59
- @cursor_pos.x = col
60
- end
61
-
62
- def move_cursor_up(val)
63
- #$stderr.puts "move_cursor_up(#{val})"
64
- if @line_index.positive?
65
- @line_index -= val
66
- @byte_pointer_in_line = width_to_bytesize(@screen[@line_index], @cursor_pos.x)
67
- @cursor_pos.y -= val
68
- end
69
- end
70
-
71
- def move_cursor_down(val)
72
- #$stderr.puts "move_cursor_down(#{val})"
73
- if @line_index < @height - 1
74
- #$stderr.puts "@line_index #{@line_index} @screen.size #{@screen.size} @height #{@height}"
75
- #$stderr.puts @screen.inspect
76
- @line_index += val
77
- @screen[@line_index] = String.new if @line_index == @screen.size
78
- @byte_pointer_in_line = width_to_bytesize(@screen[@line_index], @cursor_pos.x)
79
- @cursor_pos.y += val
80
- end
81
- end
82
-
83
- def scroll_down(val)
84
- #$stderr.puts "scroll_down(#{val})"
85
- if val >= @height
86
- clear_screen
87
- @line_index = @screen.size - 1
88
- return
89
- end
90
- @screen.size.times do |n|
91
- if n < @screen.size - val
92
- #$stderr.puts "A @screen[#{val} + #{n}] (#{@screen[val + n].inspect}) to @screen[#{n}]"
93
- @screen[n] = @screen[val + n]
94
- else
95
- #$stderr.puts "B String.new to @screen[#{n}]"
96
- @screen[n] = String.new
97
- end
98
- end
99
- @line_index += val
100
- end
101
-
102
- def erase_after_cursor
103
- #$stderr.puts "erase_after_cursor"
104
- @screen[@line_index] = @screen[@line_index].byteslice(0, @byte_pointer_in_line)
105
- end
106
-
107
- def clear_screen
108
- #$stderr.puts "clear_screen"
109
- @screen = [String.new]
110
- @line_index = 0
111
- @byte_pointer_in_line = 0
112
- @cursor_pos.x = @cursor_pos.y = 0
113
- @cleared = true
114
- Reline::IOGate.clear_screen
115
- end
116
-
117
- private def width_to_bytesize(str, width)
118
- lines, _ = Reline::Unicode.split_by_width(str, width)
119
- lines.first.bytesize
120
- end
121
-
122
- def render
123
- #$stderr.puts ?* * 100
124
- Reline::IOGate.move_cursor_up(@prev_line_index) if @prev_line_index.positive?
125
- #$stderr.puts "! move_cursor_up(#{@prev_line_index})" if @prev_line_index.positive?
126
- #$stderr.puts "@prev_line_index #{@prev_line_index} @line_index #{@line_index}"
127
- if @screen.size > @prev_screen.size
128
- #$stderr.puts ?a * 100
129
- down = @screen.size - @prev_screen.size
130
- #$stderr.puts "#{@prev_cursor_pos.y} #{down} #{@height}"
131
- if @prev_cursor_pos.y + down > (@height - 1)
132
- #$stderr.puts ?b * 100
133
- scroll = (@prev_cursor_pos.y + down) - (@height - 1)
134
- Reline::IOGate.scroll_down(scroll)
135
- #$stderr.puts "! scroll_down(#{scroll})"
136
- #$stderr.puts "down #{down}"
137
- Reline::IOGate.move_cursor_up(@screen.size - 1 - scroll)
138
- #$stderr.puts "! move_cursor_up(#{@screen.size - 1})"
139
- else
140
- #$stderr.puts ?c * 100
141
- end
142
- end
143
- @screen.size.times do |n|
144
- Reline::IOGate.move_cursor_column(0)
145
- #$stderr.puts "! move_cursor_column(0)"
146
- @output.write @screen[n]
147
- #$stderr.puts "! print #{@screen[n].inspect}"
148
- Reline::IOGate.erase_after_cursor
149
- #$stderr.puts "! erase_after_cursor"
150
- Reline::IOGate.move_cursor_down(1) if n != (@screen.size - 1)
151
- #$stderr.puts "! move_cursor_down(1)" if n != (@screen.size - 1)
152
- end
153
- up = @screen.size - 1 - @line_index
154
- Reline::IOGate.move_cursor_up(up) if up.positive?
155
- #$stderr.puts "! move_cursor_up(#{up})" if up.positive?
156
- column = Reline::Unicode.calculate_width(@screen[@line_index].byteslice(0, @byte_pointer_in_line), true)
157
- Reline::IOGate.move_cursor_column(column)
158
- #$stderr.puts "! move_cursor_column(#{column}) #{@byte_pointer_in_line}"
159
- clone_screen
160
- #$stderr.puts ?- * 10
161
- end
162
-
163
- def prep
164
- Reline::IOGate.prep
165
- end
166
-
167
- def deprep
168
- Reline::IOGate.deprep
169
- end
170
- end