rcurses 4.9.0 → 4.9.1

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.
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rcurses
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.9.0
4
+ version: 4.9.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Geir Isene
@@ -29,9 +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. 4.9.0: Major performance improvements
33
- - memory leak fixes, terminal dimension caching, batch updates, better Unicode support,
34
- enhanced error handling.'
32
+ in panes. Cursor movement around the terminal. 4.9.1: Critical fix - preserve existing
33
+ ANSI codes in Pane text rendering.'
35
34
  email: g@isene.com
36
35
  executables: []
37
36
  extensions: []
@@ -39,14 +38,6 @@ extra_rdoc_files: []
39
38
  files:
40
39
  - LICENSE
41
40
  - README.md
42
- - examples/basic_panes.rb
43
- - examples/focus_panes.rb
44
- - lib/rcurses.rb
45
- - lib/rcurses/cursor.rb
46
- - lib/rcurses/general.rb
47
- - lib/rcurses/input.rb
48
- - lib/rcurses/pane.rb
49
- - lib/string_extensions.rb
50
41
  homepage: https://isene.com/
51
42
  licenses:
52
43
  - Unlicense
@@ -1,43 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require 'rcurses'
4
-
5
- @max_h, @max_w = IO.console.winsize
6
-
7
- # Start by creating the panes; Format:
8
- # pane = Rcurses::Pane.new( startx, starty, width, height, fg, bg)
9
- pane_top = Rcurses::Pane.new( 1, 1, @max_w, 1, 255, 236)
10
- pane_bottom = Rcurses::Pane.new( 1, @max_h, @max_w, 1, 236, 254)
11
- pane_left = Rcurses::Pane.new( 2, 3, @max_w/2 - 2, @max_h - 4, 52, nil)
12
- pane_right = Rcurses::Pane.new(@max_w/2 + 1, 2, @max_w/2, @max_h - 2, 255, 52)
13
-
14
- pane_left.border = true # Adding a border to the left pane
15
-
16
- # Add content to the panes
17
- pane_top.text = Time.now.to_s[0..15].b + " Welcome to the rcurses example program"
18
- pane_left.text = `ls --color`
19
- pane_right.text = "Output of free:\n\n" + `free`
20
- pane_bottom.prompt = "Enter any text and press ENTER: ".b # The prompt text before the user starts writing content
21
-
22
- pane_top.refresh # This is the order of drawing/refreshing the panes
23
- pane_left.refresh # ...then the left pane
24
- pane_right.refresh # ...and the right pane
25
- pane_bottom.editline # Do not use a refresh before editline
26
-
27
- # Then create a "pop-up" pane in the middle of the screen
28
- pane_mid = Rcurses::Pane.new(@max_w/2 - 10, @max_h/2 - 5, 20, 10, 18, 254)
29
- pane_mid.border = true
30
- pane_mid.text = "You wrote:" + "\n" + pane_bottom.text.i
31
- pane_mid.align = "c"
32
- pane_mid.refresh
33
-
34
- # Then ask the user to hit ENTER before exiting the program
35
- pane_bottom.prompt = "Now hit ENTER again "
36
- pane_bottom.text = ""
37
- pane_bottom.editline
38
-
39
- # Reset terminal
40
- $stdin.cooked!
41
- $stdin.echo = true
42
- Rcurses::clear_screen
43
- Rcurses::Cursor.show
@@ -1,42 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require 'rcurses'
4
- include Rcurses::Input
5
- include Rcurses::Cursor
6
-
7
- @max_h, @max_w = IO.console.winsize
8
- @pane = []
9
- @focused = 3 # Start with pane 3 so that the first keypress focuses back to Pane 0
10
- Rcurses::Cursor.hide
11
-
12
- # Start by creating the panes; Format:
13
- # pane = Rcurses::Pane.new( startx, starty, width, height, fg, bg)
14
- pane_back = Rcurses::Pane.new( 1, 1, @max_w, @max_h, nil, 236)
15
- @pane[0] = Rcurses::Pane.new( 4, 4, 20, 10, 236, 254)
16
- @pane[1] = Rcurses::Pane.new( 30, 10, 16, 12, 232, 132)
17
- @pane[2] = Rcurses::Pane.new( 8, 20, 30, 20, 136, 54)
18
- @pane[3] = Rcurses::Pane.new( 50, 30, 24, 10, 206, 24)
19
-
20
- pane_back.text = "PRESS ANY KEY TO SHIFT FOCUS. PRESS 'ESC' TO QUIT."
21
- @pane.each_index { |i| @pane[i].text = "This is pane " + i.to_s }
22
- pane_back.full_refresh
23
- @pane.each_index { |i| @pane[i].refresh }
24
-
25
- input = ''
26
- while input != 'ESC'
27
- input = getchr
28
- pane_back.full_refresh
29
- @focused += 1
30
- @focused = 0 if @focused == @pane.size
31
- @pane.each_index {|i| @pane[i].border = false}
32
- @pane.each_index {|i| @pane[i].full_refresh}
33
- @pane[@focused].border = true
34
- @pane[@focused].full_refresh
35
- end
36
-
37
- # Always end an application with these lines:
38
- $stdin.cooked!
39
- $stdin.echo = true
40
- Rcurses.clear_screen
41
- Rcurses::Cursor.show
42
-
@@ -1,53 +0,0 @@
1
- module Rcurses
2
- module Cursor
3
- # Terminal cursor movement ANSI codes (inspired by https://github.com/piotrmurach/tty-cursor)
4
- module_function
5
- ESC = "\e".freeze
6
- CSI = "\e[".freeze
7
- def save; print(Gem.win_platform? ? CSI + 's' : ESC + '7'); end # Save current position
8
- def restore; print(Gem.win_platform? ? CSI + 'u' : ESC + '8'); end # Restore cursor position
9
- def pos # Query cursor current position
10
- res = ''
11
- begin
12
- $stdin.raw do |stdin|
13
- $stdout << CSI + '6n' # The actual ANSI get-position
14
- $stdout.flush
15
- while (c = stdin.getc) != 'R'
16
- res << c if c
17
- end
18
- end
19
- m = res.match(/(?<row>\d+);(?<col>\d+)/)
20
- return m[:row].to_i, m[:col].to_i
21
- rescue Errno::EIO, Errno::ENOTTY, IOError
22
- # Return safe defaults if terminal state is compromised
23
- return 1, 1
24
- end
25
- end
26
- def rowget
27
- row, _col = pos
28
- row
29
- end
30
- def colget
31
- _row, col = pos
32
- col
33
- end
34
- def set(r = 1, c = 1); print(CSI + "#{r}d"); print(CSI + "#{c}G"); end # Set cursor position to Row, Col (y,x)
35
- def up(n = 1); print(CSI + "#{(n)}A"); end # Move cursor up by n
36
- def down(n = 1); print(CSI + "#{(n)}B"); end # Move the cursor down by n
37
- def left(n = 1); print(CSI + "#{n}D"); end # Move the cursor backward by n
38
- def right(n = 1); print(CSI + "#{n}C"); end # Move the cursor forward by n
39
- def col(c = 1); print(CSI + "#{c}G"); end # Cursor moves to nth position horizontally in the current line
40
- def row(r = 1); print(CSI + "#{r}d"); end # Cursor moves to the nth position vertically in the current column
41
- def next_line; print(CSI + 'E' + CSI + "1G"); end # Move cursor down to beginning of next line
42
- def prev_line; print(CSI + 'A' + CSI + "1G"); end # Move cursor up to beginning of previous line
43
- def clear_char(n = 1); print(CSI + "#{n}X"); end # Erase n characters from the current cursor position
44
- def clear_line; print(CSI + '2K' + CSI + "1G"); end # Erase the entire current line and return to beginning of the line
45
- def clear_line_before; print(CSI + '1K'); end # Erase from the beginning of the line up to and including the current cursor position.
46
- def clear_line_after; print(CSI + '0K'); end # Erase from the current position (inclusive) to the end of the line
47
- def clear_screen_down; print(CSI + 'J'); end # Clear screen down from current row
48
- def scroll_up; print(ESC + 'M'); end # Scroll display up one line
49
- def scroll_down; print(ESC + 'D'); end # Scroll display down one line
50
- def hide; print(CSI + '?25l'); end # Scroll display down one line
51
- def show; print(CSI + '?25h'); end # Scroll display down one line
52
- end
53
- end
@@ -1,6 +0,0 @@
1
- module Rcurses
2
- def self.clear_screen
3
- # ANSI code \e[2J clears the screen, and \e[H moves the cursor to the top left.
4
- print "\e[2J\e[H"
5
- end
6
- end
data/lib/rcurses/input.rb DELETED
@@ -1,132 +0,0 @@
1
- module Rcurses
2
- module Input
3
- def getchr(t = nil, flush: true)
4
- begin
5
- # 1) Read a byte (with optional timeout)
6
- begin
7
- c = t ? Timeout.timeout(t) { $stdin.getch } : $stdin.getch
8
- rescue Timeout::Error
9
- return nil
10
- rescue Errno::EIO, Errno::ENOTTY, IOError => e
11
- # Handle terminal focus loss or disconnection gracefully
12
- return "ESC"
13
- end
14
-
15
- # 2) If it's ESC, grab any quick trailing bytes
16
- seq = c
17
- if c == "\e"
18
- if IO.select([$stdin], nil, nil, 0.05)
19
- begin
20
- seq << $stdin.read_nonblock(16)
21
- rescue IO::WaitReadable, EOFError, Errno::EIO, Errno::ENOTTY
22
- # Handle various terminal state errors gracefully
23
- end
24
- end
25
- end
26
-
27
- # 3) Single ESC alone
28
- return "ESC" if seq == "\e"
29
-
30
- # 4) Shift‑TAB
31
- return "S-TAB" if seq == "\e[Z"
32
-
33
- # 5) Legacy single‑char shift‑arrows (your old working ones)
34
- case seq
35
- when "\e[a" then return "S-UP"
36
- when "\e[b" then return "S-DOWN"
37
- when "\e[c" then return "S-RIGHT"
38
- when "\e[d" then return "S-LEFT"
39
- end
40
-
41
- # 6) CSI style shift‑arrows (e.g. ESC [1;2A )
42
- if m = seq.match(/\A\e\[\d+;2([ABCD])\z/)
43
- return { 'A' => "S-UP", 'B' => "S-DOWN", 'C' => "S-RIGHT", 'D' => "S-LEFT" }[m[1]]
44
- end
45
-
46
- # 7) Plain arrows
47
- if m = seq.match(/\A\e\[([ABCD])\z/)
48
- return { 'A' => "UP", 'B' => "DOWN", 'C' => "RIGHT", 'D' => "LEFT" }[m[1]]
49
- end
50
-
51
- # 8) CSI + '~' sequences (Ins, Del, Home, End, PgUp, PgDn, F5-F12)
52
- if seq.start_with?("\e[") && seq.end_with?("~")
53
- num = seq[/\d+(?=~)/].to_i
54
- return case num
55
- when 1, 7 then "HOME"
56
- when 2 then "INS"
57
- when 3 then "DEL"
58
- when 4, 8 then "END"
59
- when 5 then "PgUP"
60
- when 6 then "PgDOWN"
61
- when 15 then "F5"
62
- when 17 then "F6"
63
- when 18 then "F7"
64
- when 19 then "F8"
65
- when 20 then "F9"
66
- when 21 then "F10"
67
- when 23 then "F11"
68
- when 24 then "F12"
69
- else ""
70
- end
71
- end
72
-
73
- # 9) SS3 function keys F1-F4
74
- if seq.start_with?("\eO") && seq.length == 3
75
- return case seq[2]
76
- when 'P' then "F1"
77
- when 'Q' then "F2"
78
- when 'R' then "F3"
79
- when 'S' then "F4"
80
- else ""
81
- end
82
- end
83
-
84
- # 10) Single / Ctrl-char mappings
85
- return case seq
86
- when "\r", "\n" then "ENTER"
87
- when "\t" then "TAB"
88
- when "\u007F", "\b" then "BACK"
89
- when "\u0000" then "C-SPACE"
90
- when "\u0001" then "C-A"
91
- when "\u0002" then "C-B"
92
- when "\u0003" then "C-C"
93
- when "\u0004" then "C-D"
94
- when "\u0005" then "C-E"
95
- when "\u0006" then "C-F"
96
- when "\u0007" then "C-G"
97
- when "\u0008" then "C-H"
98
- when "\u000B" then "C-K"
99
- when "\u000C" then "C-L"
100
- when "\u000D" then "C-M"
101
- when "\u000E" then "C-N"
102
- when "\u000F" then "C-O"
103
- when "\u0010" then "C-P"
104
- when "\u0011" then "C-Q"
105
- when "\u0012" then "C-R"
106
- when "\u0013" then "C-S"
107
- when "\u0014" then "C-T"
108
- when "\u0015" then "C-U"
109
- when "\u0016" then "C-V"
110
- when "\u0018" then "C-X"
111
- when "\u0019" then "C-Y"
112
- when "\u001A" then "C-Z"
113
- when "\u0017" then "WBACK"
114
- when /\A[[:print:]]\z/ then seq
115
- else ""
116
- end
117
- ensure
118
- if flush
119
- while IO.select([$stdin], nil, nil, 0)
120
- begin
121
- $stdin.read_nonblock(4096)
122
- rescue IO::WaitReadable, EOFError, Errno::EIO, Errno::ENOTTY
123
- # Handle terminal state errors during flush
124
- break
125
- end
126
- end
127
- end
128
- end
129
- end
130
- end
131
- end
132
-