rubyterm 0.2.6 → 0.2.8
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/rubyterm/app.rb +95 -23
- data/lib/rubyterm/version.rb +1 -1
- data/lib/window.rb +12 -50
- 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: 1e558fb7c4f76d082d2b12a187b2896da650c41d78c68a7091e087b44da9f05a
|
|
4
|
+
data.tar.gz: 2218f739b992337ebef7a4aa23d4674beba0d98f8aec7b923308b8add330ef8c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: bb871759cd9df280d3ea58f6567901e21e8bc6ece1c0338e9c5aa7c39e80dbfded97d2be82029f716b48b3de1b268afb732071497cd0fb7f51a4c8e6d7b59398
|
|
7
|
+
data.tar.gz: 1d2f2a46619c84ac22cfe8242cc635119a57550b57ea24d37f12dd612c9f7aebebeef157b5eda973950010898e6f55ea4b63678702f29a2feed4b791bcef9276
|
data/lib/rubyterm/app.rb
CHANGED
|
@@ -286,30 +286,10 @@ class RubyTerm
|
|
|
286
286
|
when :"ctrl_+" then adjust_fontsize(1.0)
|
|
287
287
|
when :"ctrl_-" then adjust_fontsize(-1.0)
|
|
288
288
|
when :shift_page_up
|
|
289
|
-
|
|
290
|
-
# Full redraw to show scrollback buffer
|
|
291
|
-
redraw
|
|
289
|
+
scrollback_view_up
|
|
292
290
|
return
|
|
293
291
|
when :shift_page_down
|
|
294
|
-
|
|
295
|
-
return if !@window.scrollback_mode
|
|
296
|
-
|
|
297
|
-
# If we're exiting scrollback mode or still in it
|
|
298
|
-
changed = @window.scrollback_page_down
|
|
299
|
-
|
|
300
|
-
# Redraw everything from scratch
|
|
301
|
-
redraw
|
|
302
|
-
|
|
303
|
-
# Explicitly force cursor to be redrawn if exiting scrollback mode
|
|
304
|
-
if changed
|
|
305
|
-
# Clear cursor if it exists
|
|
306
|
-
@term.clear_cursor
|
|
307
|
-
# Force draw cursor again
|
|
308
|
-
@term.draw_cursor
|
|
309
|
-
# Ensure changes are flushed
|
|
310
|
-
@buffer.draw_flush
|
|
311
|
-
@window.flush
|
|
312
|
-
end
|
|
292
|
+
scrollback_view_down
|
|
313
293
|
return
|
|
314
294
|
when :XK_Insert # Paste primary selection
|
|
315
295
|
# FIXME: Giant hack
|
|
@@ -380,6 +360,82 @@ class RubyTerm
|
|
|
380
360
|
redraw if @window.scrollback_reset
|
|
381
361
|
end
|
|
382
362
|
|
|
363
|
+
# Lines the view moves per mouse wheel tick (Shift+PageUp/Down move a
|
|
364
|
+
# full page of 10).
|
|
365
|
+
WHEEL_SCROLL_LINES = 3
|
|
366
|
+
|
|
367
|
+
# Move the scrollback view up/down by +lines+ and repaint incrementally:
|
|
368
|
+
# blit the rows that stay on screen (the same CopyArea mechanism live
|
|
369
|
+
# scrolling uses) and repaint only the newly exposed ones. The previous
|
|
370
|
+
# full clear+redraw per step made wheel scrolling visibly jerky. Shared
|
|
371
|
+
# by Shift+PageUp/Down and the wheel.
|
|
372
|
+
#
|
|
373
|
+
# The blit carries the selection-highlight pixels along with their text
|
|
374
|
+
# (the selection is pinned to buffer content), so only the freshly
|
|
375
|
+
# repainted rows need the overlay re-stamped - reapply_selection does
|
|
376
|
+
# that at the end.
|
|
377
|
+
def scrollback_view_up(lines = 10)
|
|
378
|
+
# Nothing above the view: don't touch the cursor or repaint at all
|
|
379
|
+
# (wheel ticks arrive far more often than Shift+PageUp ever did).
|
|
380
|
+
return if @window.scrollback_count >= @window.scrollback_buffer_size
|
|
381
|
+
if !@window.scrollback_mode
|
|
382
|
+
# Leaving the live screen: repaint the cursor cell first - cursor
|
|
383
|
+
# redraws are suppressed once scrolled back, and the blit below would
|
|
384
|
+
# otherwise drag the cursor overlay along as if it were content.
|
|
385
|
+
@term.clear_cursor
|
|
386
|
+
@buffer.draw_flush
|
|
387
|
+
end
|
|
388
|
+
moved = @window.scrollback_scroll(lines)
|
|
389
|
+
rows = @term.height
|
|
390
|
+
# A jump of a screenful or more retains nothing worth blitting.
|
|
391
|
+
return redraw if moved >= rows
|
|
392
|
+
# Shift the surviving rows down by +moved+ (this also clears the
|
|
393
|
+
# vacated top band and re-draws the scrollback indicator over row 0).
|
|
394
|
+
@window.scroll_down(0, @window.width, (rows - moved) * char_h, moved * char_h)
|
|
395
|
+
# Repaint the newly exposed history rows. Row 0 stays the indicator
|
|
396
|
+
# line, so start at 1; include row +moved+, where the old top row's
|
|
397
|
+
# indicator-overlay pixels landed.
|
|
398
|
+
(1..moved).each { |sy| repaint_view_row(sy) }
|
|
399
|
+
@buffer.draw_flush
|
|
400
|
+
@window.flush
|
|
401
|
+
reapply_selection
|
|
402
|
+
end
|
|
403
|
+
|
|
404
|
+
def scrollback_view_down(lines = 10)
|
|
405
|
+
# Don't do anything if not in scrollback mode
|
|
406
|
+
return if !@window.scrollback_mode
|
|
407
|
+
moved = @window.scrollback_scroll(-lines)
|
|
408
|
+
return if moved == 0
|
|
409
|
+
exited = !@window.scrollback_mode # landed back on the live screen
|
|
410
|
+
rows = @term.height
|
|
411
|
+
if moved >= rows
|
|
412
|
+
redraw
|
|
413
|
+
else
|
|
414
|
+
# Shift the surviving rows up (clears the vacated bottom band; the
|
|
415
|
+
# indicator is re-drawn only while still scrolled back).
|
|
416
|
+
@window.scroll_up(moved * char_h, @window.width, (rows - moved) * char_h, moved * char_h)
|
|
417
|
+
# Repaint the rows that scrolled into view at the bottom.
|
|
418
|
+
(rows - moved...rows).each { |sy| repaint_view_row(sy) }
|
|
419
|
+
@buffer.draw_flush
|
|
420
|
+
@window.flush
|
|
421
|
+
reapply_selection
|
|
422
|
+
end
|
|
423
|
+
# Explicitly force cursor to be redrawn if exiting scrollback mode
|
|
424
|
+
if exited
|
|
425
|
+
@term.clear_cursor
|
|
426
|
+
@term.draw_cursor
|
|
427
|
+
@buffer.draw_flush
|
|
428
|
+
@window.flush
|
|
429
|
+
end
|
|
430
|
+
end
|
|
431
|
+
|
|
432
|
+
# Repaint one on-screen row from the buffer at the current view offset
|
|
433
|
+
# (blank cells paint as spaces, so this also erases stale pixels).
|
|
434
|
+
def repaint_view_row(sy)
|
|
435
|
+
sb = @window.scrollback_count
|
|
436
|
+
(0...@term.width).each { |x| @buffer.redraw_display(x, sy, sb) }
|
|
437
|
+
end
|
|
438
|
+
|
|
383
439
|
def redraw_positions(positions) = positions.each { |pos| @buffer.redraw(*pos) }
|
|
384
440
|
|
|
385
441
|
# The selection's [start, end] boundary pairs, expanded so a double-width
|
|
@@ -500,6 +556,19 @@ class RubyTerm
|
|
|
500
556
|
shift = pkt.state.anybits?(0x01) # ShiftMask
|
|
501
557
|
case shift ? nil : @term.mouse_mode
|
|
502
558
|
when nil
|
|
559
|
+
# Wheel ticks (buttons 4/5) scroll the local scrollback view, the way
|
|
560
|
+
# every other terminal scrolls natively - this is what an app that
|
|
561
|
+
# does not grab the mouse (e.g. a shell, or claude's inline mode)
|
|
562
|
+
# relies on. Handled before the selection logic below so a wheel tick
|
|
563
|
+
# never starts or clears a selection. With Shift held this branch is
|
|
564
|
+
# forced even when an app owns the mouse, so Shift+wheel always
|
|
565
|
+
# scrolls history - the same override as Shift+select.
|
|
566
|
+
if button >= 4
|
|
567
|
+
return if release # each tick is a press+release pair; act on press
|
|
568
|
+
scrollback_view_up(WHEEL_SCROLL_LINES) if button == 4
|
|
569
|
+
scrollback_view_down(WHEEL_SCROLL_LINES) if button == 5
|
|
570
|
+
return
|
|
571
|
+
end
|
|
503
572
|
# Selection coordinates are cell *boundaries* (round to the nearest
|
|
504
573
|
# column edge, not the floor cell), so dragging across a single cell
|
|
505
574
|
# selects exactly that cell and a click (no boundary crossed) selects
|
|
@@ -535,9 +604,12 @@ class RubyTerm
|
|
|
535
604
|
clear_selection_if_set
|
|
536
605
|
end
|
|
537
606
|
end
|
|
538
|
-
when :vt200, :btn_event
|
|
607
|
+
when :vt200, :btn_event, :any_event
|
|
539
608
|
# FIXME: This is only right for @mouse_reporting == :digits
|
|
540
609
|
# FIXME: Report modifiers.
|
|
610
|
+
# FIXME: Motion reporting is the same for all three modes; strictly
|
|
611
|
+
# :vt200 (1000) reports no motion and :any_event (1003) reports all
|
|
612
|
+
# motion, not just with a button held.
|
|
541
613
|
# Not reporting release for scroll wheel
|
|
542
614
|
return if release && button >= 4
|
|
543
615
|
event = [0,1,2,64,65][button-1]
|
data/lib/rubyterm/version.rb
CHANGED
data/lib/window.rb
CHANGED
|
@@ -41,31 +41,19 @@ class Window
|
|
|
41
41
|
@buffer.scrollback_size
|
|
42
42
|
end
|
|
43
43
|
|
|
44
|
-
#
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
@scrollback_count += 10
|
|
55
|
-
if @scrollback_count > max_scrollback
|
|
56
|
-
@scrollback_count = max_scrollback
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
# Calculate how many new lines we've scrolled and clear them
|
|
60
|
-
new_lines = @scrollback_count - previous_count
|
|
61
|
-
if new_lines > 0
|
|
62
|
-
# Clear the area where new scrollback lines will appear
|
|
63
|
-
clear(0, 0, @width, new_lines * char_h)
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
draw_scrollback_indicator if @scrollback_count <= 10
|
|
44
|
+
# Move the scrollback view by +lines+ (positive = further back into
|
|
45
|
+
# history, negative = towards the live screen), clamped to
|
|
46
|
+
# [0, history size]. This is a pure model update - repainting (a blit of
|
|
47
|
+
# the surviving rows plus a repaint of the exposed ones, or a full
|
|
48
|
+
# redraw) is the caller's job. Returns the number of lines actually
|
|
49
|
+
# moved, 0 when already at the corresponding end.
|
|
50
|
+
def scrollback_scroll(lines)
|
|
51
|
+
was = @scrollback_count
|
|
52
|
+
@scrollback_count = (was + lines).clamp(0, scrollback_buffer_size)
|
|
53
|
+
(@scrollback_count - was).abs
|
|
67
54
|
end
|
|
68
|
-
|
|
55
|
+
|
|
56
|
+
|
|
69
57
|
# Snap straight back to the live screen (bottom of scrollback). Returns
|
|
70
58
|
# true if we were scrolled back, so the caller knows a redraw is needed.
|
|
71
59
|
def scrollback_reset
|
|
@@ -84,32 +72,6 @@ class Window
|
|
|
84
72
|
@scrollback_count += 1
|
|
85
73
|
end
|
|
86
74
|
|
|
87
|
-
# Decrease scrollback counter
|
|
88
|
-
def scrollback_page_down
|
|
89
|
-
return false if @scrollback_count <= 0
|
|
90
|
-
|
|
91
|
-
# Remember previous count
|
|
92
|
-
previous_count = @scrollback_count
|
|
93
|
-
|
|
94
|
-
@scrollback_count -= 10
|
|
95
|
-
if @scrollback_count <= 0
|
|
96
|
-
# Exiting scrollback mode
|
|
97
|
-
@scrollback_count = 0
|
|
98
|
-
@dirty = true
|
|
99
|
-
|
|
100
|
-
# Clear entire scrollback area that was showing
|
|
101
|
-
clear(0, 0, @width, previous_count * char_h)
|
|
102
|
-
return true
|
|
103
|
-
else
|
|
104
|
-
# Clear area that was occupied by lines no longer in scrollback
|
|
105
|
-
lines_removed = previous_count - @scrollback_count
|
|
106
|
-
if lines_removed > 0
|
|
107
|
-
clear(0, 0, @width, lines_removed * char_h)
|
|
108
|
-
end
|
|
109
|
-
end
|
|
110
|
-
false
|
|
111
|
-
end
|
|
112
|
-
|
|
113
75
|
def initialize(**opts)
|
|
114
76
|
@scrollback_count = 0
|
|
115
77
|
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rubyterm
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.2.
|
|
4
|
+
version: 0.2.8
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Vidar Hokstad
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-07-03 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: pure-x11
|