rcurses 3.0 → 3.2

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.
Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/lib/rcurses/pane.rb +100 -55
  3. data/lib/rcurses.rb +1 -1
  4. metadata +4 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 706550c12ee9965c33b958c6ce4ec5cb0aa12fb37196b4dd623cea43b982528f
4
- data.tar.gz: 17e20e12a50a34f2d36069041b3f1dfbedbf27ab7dddf8f3681fd8b289e6fe00
3
+ metadata.gz: 79ceb9c8cca6e61988655c520a5b43f5f2a37b95f9c3064b59cefa962795b751
4
+ data.tar.gz: 67ad97d3a492318eff06f393eb4366d575b1cf2de2bc471b02b15a12d3505aaf
5
5
  SHA512:
6
- metadata.gz: 68fe3d1c80b12fae7ad09b49efdec40a889bf36f6d269e68ab09971bf9f057874ac122cff4d1c08c9b0673e13e65857c98e9e888977138a1c51a385544520901
7
- data.tar.gz: aa6d784ef29afbb0b5e09ada56b2caadf2b474e0bf909eaa92dc161f88d6d1e6c33424d3c1ed2c407148d9ce502bd5563bf1eb1118e3b2a7a15444df18494a89
6
+ metadata.gz: b0a668847e6b6f276ed5ee059d3e194184f4313556316ab3c80604d63cc8b99e5a733559b8e6e97da90c6fa2191ecdfc5b15e6639c41caa577f8810b0da87b77
7
+ data.tar.gz: 95a8a6b48bc7399121b50b3cbeae29631feab2b76a537a93c585bf9e654492e8bebbb30bb881b6b8522ec17866209c657a133511d500cdcdb589d17b2a3585c4
data/lib/rcurses/pane.rb CHANGED
@@ -1,4 +1,33 @@
1
1
  module Rcurses
2
+ # A simple display_width function that approximates how many columns a string occupies.
3
+ # This is a simplified version that may need adjustments for full Unicode support.
4
+ def self.display_width(str)
5
+ width = 0
6
+ str.each_char do |char|
7
+ cp = char.ord
8
+ if cp == 0
9
+ # NUL – no width
10
+ elsif cp < 32 || (cp >= 0x7F && cp < 0xA0)
11
+ # Control characters: no width
12
+ width += 0
13
+ # Approximate common wide ranges:
14
+ elsif (cp >= 0x1100 && cp <= 0x115F) ||
15
+ cp == 0x2329 || cp == 0x232A ||
16
+ (cp >= 0x2E80 && cp <= 0xA4CF) ||
17
+ (cp >= 0xAC00 && cp <= 0xD7A3) ||
18
+ (cp >= 0xF900 && cp <= 0xFAFF) ||
19
+ (cp >= 0xFE10 && cp <= 0xFE19) ||
20
+ (cp >= 0xFE30 && cp <= 0xFE6F) ||
21
+ (cp >= 0xFF00 && cp <= 0xFF60) ||
22
+ (cp >= 0xFFE0 && cp <= 0xFFE6)
23
+ width += 2
24
+ else
25
+ width += 1
26
+ end
27
+ end
28
+ width
29
+ end
30
+
2
31
  class Pane
3
32
  require 'clipboard' # Ensure the 'clipboard' gem is installed
4
33
  include Cursor
@@ -8,22 +37,25 @@ module Rcurses
8
37
  attr_accessor :moreup, :moredown
9
38
 
10
39
  def initialize(x = 1, y = 1, w = 1, h = 1, fg = nil, bg = nil)
40
+ @max_h, @max_w = IO.console.winsize
11
41
  @x = x
12
42
  @y = y
13
43
  @w = w
14
44
  @h = h
15
45
  @fg, @bg = fg, bg
16
- @text = "" # Initialize text variable
17
- @align = "l" # Default alignment
18
- @scroll = true # Enable scroll indicators
19
- @prompt = "" # Prompt for editline
20
- @ix = 0 # Starting text line index
21
- @max_h, @max_w = IO.console.winsize
46
+ @text = "" # Initialize text variable
47
+ @align = "l" # Default alignment
48
+ @scroll = true # Enable scroll indicators
49
+ @prompt = "" # Prompt for editline
50
+ @ix = 0 # Starting text line index
51
+ @prev_frame = nil # Holds the previously rendered frame (array of lines)
52
+ @line = 0 # For cursor tracking during editing:
53
+ @pos = 0 # For cursor tracking during editing:
22
54
  end
23
55
 
24
- def move(x, y)
25
- @x += x
26
- @y += y
56
+ def move(dx, dy)
57
+ @x += dx
58
+ @y += dy
27
59
  refresh
28
60
  end
29
61
 
@@ -74,11 +106,13 @@ module Rcurses
74
106
  refresh
75
107
  end
76
108
 
77
- # Optimized refresh using double buffering to minimize flicker.
109
+ # Diff-based refresh that minimizes flicker.
110
+ # (This is your previously best-working code.)
111
+ # We have removed scroll marker insertion from within the double-buffered frame.
112
+ # Instead, after printing the frame we reprint the right border column.
78
113
  def refresh(cont = @text)
79
114
  @max_h, @max_w = IO.console.winsize
80
115
 
81
- # Adjust pane dimensions (unchanged logic)
82
116
  if @border
83
117
  @w = @max_w - 2 if @w > @max_w - 2
84
118
  @h = @max_h - 2 if @h > @max_h - 2
@@ -91,24 +125,24 @@ module Rcurses
91
125
  @y = 1 if @y < 1; @y = @max_h - @h + 1 if @y + @h > @max_h + 1
92
126
  end
93
127
 
94
- # Save current cursor position.
95
128
  o_row, o_col = pos
129
+ STDOUT.print "\e[?25l" # Hide cursor
96
130
 
97
- # Hide cursor and switch to alternate screen buffer (if desired). Hide it any case and use Curses.show to bring it back.
98
- # Note: The alternate screen buffer means your program’s output won’t mix with the normal terminal content.
99
- STDOUT.print "\e[?25l" # hide cursor
100
- # Uncomment the next line to use the alternate screen buffer.
101
- #STDOUT.print "\e[?1049h"
102
-
103
- buf = ""
104
- buf << "\e[#{@y};#{@x}H" # Move cursor to start of pane.
105
131
  fmt = [@fg, @bg].compact.join(',')
106
132
  @txt = cont.split("\n")
107
133
  @txt = textformat(cont) if @txt.any? { |line| line.pure.length >= @w }
108
134
  @ix = @txt.length - 1 if @ix > @txt.length - 1
109
135
  @ix = 0 if @ix < 0
110
136
 
111
- @h.times do |i|
137
+ new_frame = []
138
+ if @border
139
+ top_border = ("┌" + "─" * @w + "┐").c(fmt)
140
+ new_frame << top_border
141
+ end
142
+
143
+ content_rows = @h
144
+ content_rows.times do |i|
145
+ line_str = ""
112
146
  l = @ix + i
113
147
  if @txt[l].to_s != ""
114
148
  pl = @w - @txt[l].pure.length
@@ -116,53 +150,65 @@ module Rcurses
116
150
  hl = pl / 2
117
151
  case @align
118
152
  when "l"
119
- buf << @txt[l].c(fmt) << " ".c(fmt) * pl
153
+ line_str = @txt[l].c(fmt) + " ".c(fmt) * pl
120
154
  when "r"
121
- buf << " ".c(fmt) * pl << @txt[l].c(fmt)
155
+ line_str = " ".c(fmt) * pl + @txt[l].c(fmt)
122
156
  when "c"
123
- buf << " ".c(fmt) * hl << @txt[l].c(fmt) << " ".c(fmt) * (pl - hl)
157
+ line_str = " ".c(fmt) * hl + @txt[l].c(fmt) + " ".c(fmt) * (pl - hl)
124
158
  end
125
159
  else
126
- buf << " ".c(fmt) * @w
160
+ line_str = " ".c(fmt) * @w
127
161
  end
128
- buf << "\e[#{@y + i + 1};#{@x}H" # Next line.
129
- end
130
162
 
131
- # Draw scroll markers.
132
- if @ix > 0 and @scroll
133
- buf << "\e[#{@y};#{@x + @w - 1}H" << "∆".c(fmt)
134
- @moreup = true
135
- else
136
- @moreup = false
137
- end
163
+ if @border
164
+ line_str = "│" + line_str + "│"
165
+ end
138
166
 
139
- if @txt.length - @ix > @h and @scroll
140
- buf << "\e[#{@y + @h - 1};#{@x + @w - 1}H" << "∇".c(fmt)
141
- @moredown = true
142
- else
143
- @moredown = false
167
+ new_frame << line_str
144
168
  end
145
169
 
146
- # Draw border if enabled.
147
170
  if @border
148
- buf << "\e[#{@y - 1};#{@x - 1}H" << ("" + "─" * @w + "").c(fmt)
149
- @h.times do |i|
150
- buf << "\e[#{@y + i};#{@x - 1}H" << "│".c(fmt)
151
- buf << "\e[#{@y + i};#{@x + @w}H" << "│".c(fmt)
152
- end
153
- buf << "\e[#{@y + @h};#{@x - 1}H" << ("└" + "─" * @w + "┘").c(fmt)
171
+ bottom_border = ("" + "─" * @w + "").c(fmt)
172
+ new_frame << bottom_border
154
173
  end
155
174
 
156
- # Restore original cursor position.
157
- buf << "\e[#{o_row};#{o_col}H"
175
+ diff_buf = ""
176
+ new_frame.each_with_index do |line, i|
177
+ row_num = @border ? (@y - 1 + i) : (@y + i)
178
+ col_num = @border ? (@x - 1) : @x
179
+ if @prev_frame.nil? || @prev_frame[i] != line ||
180
+ (@border && (i == 0 || i == new_frame.size - 1))
181
+ diff_buf << "\e[#{row_num};#{col_num}H" << line
182
+ end
183
+ end
158
184
 
159
- # Print the whole buffer at once.
160
- print buf
185
+ diff_buf << "\e[#{o_row};#{o_col}H"
186
+ print diff_buf
187
+ #STDOUT.print "\e[?25h" # We leave the cursor hidden unless explicitly shown
188
+ @prev_frame = new_frame
189
+
190
+ # Now, after printing the frame, draw the scroll markers separately.
191
+ if @scroll
192
+ # Use the same marker column as before.
193
+ marker_col = @border ? (@x + @w - 1) : (@x + @w - 1)
194
+ # Draw top marker at row = @y + 1 (inside the frame)
195
+ if @ix > 0
196
+ print "\e[#{@y};#{marker_col}H" + "∆".c(fmt)
197
+ end
198
+ # Draw bottom marker at row = @y + @h - 1 (inside the frame)
199
+ if (@txt.length - @ix) > @h
200
+ print "\e[#{@y + @h - 1};#{marker_col}H" + "∇".c(fmt)
201
+ end
202
+ end
161
203
 
162
- # Uncomment the next line to switched to the alternate screen buffer.
163
- #STDOUT.print "\e[?1049l"
204
+ # Now, reprint the right border column for each content line to fill any holes.
205
+ if @border
206
+ (0...@h).each do |i|
207
+ print "\e[#{@y + i};#{@x + @w}H" + "│".c(fmt)
208
+ end
209
+ end
164
210
 
165
- @txt
211
+ new_frame.join("\n")
166
212
  end
167
213
 
168
214
  def textformat(cont)
@@ -439,7 +485,7 @@ module Rcurses
439
485
  def calculate_posx
440
486
  total_length = 0
441
487
  (@ix + @line).times do |i|
442
- total_length += @txt[i].pure.length + 1 # +1 for the newline
488
+ total_length += @txt[i].pure.length + 1 # +1 for newline
443
489
  end
444
490
  total_length += @pos
445
491
  total_length
@@ -516,4 +562,3 @@ module Rcurses
516
562
  end
517
563
  end
518
564
  end
519
-
data/lib/rcurses.rb CHANGED
@@ -5,7 +5,7 @@
5
5
  # Web_site: http://isene.com/
6
6
  # Github: https://github.com/isene/rcurses
7
7
  # License: Public domain
8
- # Version: 3.0: Flicker reduction by double screen buffer
8
+ # Version: 3.2: Fixed scroll markers and UTF-8 double-wide characters breaking borders
9
9
 
10
10
  require 'io/console' # Basic gem for rcurses
11
11
  require 'io/wait' # stdin handling
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: '3.0'
4
+ version: '3.2'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Geir Isene
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-04-01 00:00:00.000000000 Z
11
+ date: 2025-04-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: clipboard
@@ -29,8 +29,8 @@ description: 'Create curses applications for the terminal easier than ever. Crea
29
29
  up text (in panes or anywhere in the terminal) in bold, italic, underline, reverse
30
30
  color, blink and in any 256 terminal colors for foreground and background. Use a
31
31
  simple editor to let users edit text in panes. Left, right or center align text
32
- in panes. Cursor movement around the terminal. New in 3.0: Flicker reduction by
33
- double screen buffer.'
32
+ in panes. Cursor movement around the terminal. New in 3.2: Fixed scroll markers
33
+ and UTF-8 double-wide characters breaking borders.'
34
34
  email: g@isene.com
35
35
  executables: []
36
36
  extensions: []