rcurses 6.3.1 → 6.3.3
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.
- checksums.yaml +4 -4
- data/lib/rcurses/general.rb +13 -1
- data/lib/rcurses/pane.rb +28 -7
- data/lib/string_extensions.rb +4 -3
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8da51fe4d11778fce9941e08a03f67ec108f3f09e0625a32335a6ea1a953375d
|
|
4
|
+
data.tar.gz: 1379e2f96f8fa20d20e73111ac47df90aab71ecd1897cf3816fb78bb5294c5d1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 761fd3c178607f530c6b9fe0ad4bc997fb2c3872e70068b21c913d719c941ed766222d75efc16fa5fcd5de3131fe6f5859b07c269c7c59ea831fa612d9313252
|
|
7
|
+
data.tar.gz: 0b110d9d36765c614b01539af2ec38b85cf8237888d297667e736e6711a1d0a68aa10ff107fc05e61f02cbd2c07765df8d15a3cb2adaf442abfe447929a78154
|
data/lib/rcurses/general.rb
CHANGED
|
@@ -58,9 +58,19 @@ module Rcurses
|
|
|
58
58
|
end
|
|
59
59
|
end
|
|
60
60
|
|
|
61
|
-
#
|
|
61
|
+
# Display width cache
|
|
62
|
+
@dw_cache = {}
|
|
63
|
+
DW_CACHE_MAX = 2000
|
|
64
|
+
|
|
65
|
+
def self.clear_dw_cache
|
|
66
|
+
@dw_cache.clear
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Simple, fast display_width function (cached)
|
|
62
70
|
def self.display_width(str)
|
|
63
71
|
return 0 if str.nil? || str.empty?
|
|
72
|
+
cached = @dw_cache[str]
|
|
73
|
+
return cached if cached
|
|
64
74
|
|
|
65
75
|
width = 0
|
|
66
76
|
prev_regional = false
|
|
@@ -162,6 +172,8 @@ module Rcurses
|
|
|
162
172
|
prev_regional = false
|
|
163
173
|
after_zwj = false
|
|
164
174
|
end
|
|
175
|
+
@dw_cache.clear if @dw_cache.size >= DW_CACHE_MAX
|
|
176
|
+
@dw_cache[str] = width
|
|
165
177
|
width
|
|
166
178
|
end
|
|
167
179
|
|
data/lib/rcurses/pane.rb
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
module Rcurses
|
|
2
|
+
ANSI_RE = /\e\[[0-9;]*m/.freeze
|
|
3
|
+
ANSI_CSI_RE = /\e\[[0-9;]*[A-HJKSTfhlnr]/.freeze
|
|
4
|
+
|
|
2
5
|
class Pane
|
|
3
6
|
require 'clipboard' # Ensure the 'clipboard' gem is installed
|
|
4
7
|
include Cursor
|
|
@@ -60,6 +63,11 @@ module Rcurses
|
|
|
60
63
|
@history.shift while @history.size > @max_history_size
|
|
61
64
|
end
|
|
62
65
|
@text = new_text
|
|
66
|
+
@line_count = nil # Invalidate cache
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def line_count
|
|
70
|
+
@line_count ||= @text.to_s.count("\n") + 1
|
|
63
71
|
end
|
|
64
72
|
|
|
65
73
|
def ask(prompt, text)
|
|
@@ -113,7 +121,7 @@ module Rcurses
|
|
|
113
121
|
|
|
114
122
|
def linedown
|
|
115
123
|
@ix += 1
|
|
116
|
-
@ix =
|
|
124
|
+
@ix = line_count - 1 if @ix > line_count - 1
|
|
117
125
|
refresh
|
|
118
126
|
end
|
|
119
127
|
|
|
@@ -125,7 +133,8 @@ module Rcurses
|
|
|
125
133
|
|
|
126
134
|
def pagedown
|
|
127
135
|
@ix = @ix + @h - 1
|
|
128
|
-
|
|
136
|
+
max = line_count - @h
|
|
137
|
+
@ix = max if @ix > max
|
|
129
138
|
refresh
|
|
130
139
|
end
|
|
131
140
|
|
|
@@ -136,7 +145,7 @@ module Rcurses
|
|
|
136
145
|
end
|
|
137
146
|
|
|
138
147
|
def bottom
|
|
139
|
-
@ix =
|
|
148
|
+
@ix = line_count - @h
|
|
140
149
|
refresh
|
|
141
150
|
end
|
|
142
151
|
|
|
@@ -334,12 +343,12 @@ module Rcurses
|
|
|
334
343
|
|
|
335
344
|
# Strip non-SGR ANSI sequences (cursor movement, clear, etc.)
|
|
336
345
|
# Keep only SGR sequences (ending in 'm') for colors/styles
|
|
337
|
-
line_str = line_str.gsub(
|
|
346
|
+
line_str = line_str.gsub(ANSI_CSI_RE, '')
|
|
338
347
|
# Strip any raw control characters (except tab and ANSI ESC sequences)
|
|
339
348
|
line_str = line_str.gsub(/[\x00-\x08\x0b-\x1a\x7f]/, '?')
|
|
340
349
|
|
|
341
350
|
# Hard-clip line to pane width to prevent overflow into adjacent panes
|
|
342
|
-
visible_w = Rcurses.display_width(line_str.respond_to?(:pure) ? line_str.pure : line_str.gsub(
|
|
351
|
+
visible_w = Rcurses.display_width(line_str.respond_to?(:pure) ? line_str.pure : line_str.gsub(ANSI_RE, ''))
|
|
343
352
|
if visible_w > @w
|
|
344
353
|
line_str = line_str.respond_to?(:shorten) ? line_str.shorten(@w) : line_str[0, @w]
|
|
345
354
|
end
|
|
@@ -566,10 +575,16 @@ module Rcurses
|
|
|
566
575
|
right
|
|
567
576
|
end
|
|
568
577
|
|
|
569
|
-
# Handle any buffered input
|
|
578
|
+
# Handle any buffered input (multi-line paste)
|
|
570
579
|
while IO.select([$stdin], nil, nil, 0)
|
|
571
580
|
input_char = $stdin.read_nonblock(1) rescue nil
|
|
572
581
|
break unless input_char
|
|
582
|
+
# ESC byte starts an escape sequence (arrow key, etc.)
|
|
583
|
+
# Push it back for getchr to parse properly on next iteration
|
|
584
|
+
if input_char == "\e"
|
|
585
|
+
$stdin.ungetbyte(0x1b)
|
|
586
|
+
break
|
|
587
|
+
end
|
|
573
588
|
posx = calculate_posx
|
|
574
589
|
content.insert(posx, input_char)
|
|
575
590
|
right
|
|
@@ -719,6 +734,12 @@ module Rcurses
|
|
|
719
734
|
while IO.select([$stdin], nil, nil, 0)
|
|
720
735
|
chr = $stdin.read_nonblock(1) rescue nil
|
|
721
736
|
break unless chr
|
|
737
|
+
# ESC byte starts an escape sequence (arrow key, etc.)
|
|
738
|
+
# Push it back for getchr to parse properly on next iteration
|
|
739
|
+
if chr == "\e"
|
|
740
|
+
$stdin.ungetbyte(0x1b)
|
|
741
|
+
break
|
|
742
|
+
end
|
|
722
743
|
# Normalize \r\n to a single newline: skip \n after \r
|
|
723
744
|
if chr == "\n" && last_was_cr
|
|
724
745
|
last_was_cr = false
|
|
@@ -799,7 +820,7 @@ module Rcurses
|
|
|
799
820
|
begin
|
|
800
821
|
return [""] if line.nil? || w <= 0
|
|
801
822
|
|
|
802
|
-
ansi_regex =
|
|
823
|
+
ansi_regex = ANSI_RE
|
|
803
824
|
result = []
|
|
804
825
|
tokens = line.scan(/(\e\[[0-9;]*m|[^\e]+)/).flatten.compact
|
|
805
826
|
current_line = ''
|
data/lib/string_extensions.rb
CHANGED
|
@@ -92,8 +92,9 @@ class String
|
|
|
92
92
|
end
|
|
93
93
|
|
|
94
94
|
# Strip all ANSI SGR sequences
|
|
95
|
+
ANSI_SGR_RE = /\e\[\d+(?:;\d+)*m/.freeze
|
|
95
96
|
def pure
|
|
96
|
-
gsub(
|
|
97
|
+
gsub(ANSI_SGR_RE, '')
|
|
97
98
|
end
|
|
98
99
|
|
|
99
100
|
# Remove stray leading/trailing reset if the string has no other styling
|
|
@@ -162,7 +163,7 @@ class String
|
|
|
162
163
|
def safe_gsub(pattern, replacement = nil, &block)
|
|
163
164
|
# Store all ANSI sequences and replace with placeholders
|
|
164
165
|
ansi_sequences = []
|
|
165
|
-
placeholder_text = self.gsub(
|
|
166
|
+
placeholder_text = self.gsub(Rcurses::ANSI_RE) do |match|
|
|
166
167
|
ansi_sequences << match
|
|
167
168
|
"⟨ANSI#{ansi_sequences.length - 1}⟩"
|
|
168
169
|
end
|
|
@@ -190,7 +191,7 @@ class String
|
|
|
190
191
|
|
|
191
192
|
# Check if string contains ANSI codes
|
|
192
193
|
def has_ansi?
|
|
193
|
-
!!(self =~
|
|
194
|
+
!!(self =~ Rcurses::ANSI_RE)
|
|
194
195
|
end
|
|
195
196
|
|
|
196
197
|
# Get the visible length (without ANSI codes)
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rcurses
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 6.3.
|
|
4
|
+
version: 6.3.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Geir Isene
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-03-
|
|
11
|
+
date: 2026-03-29 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: clipboard
|