typr 1.1.1 → 1.1.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ddb6c3054fa6559c2a3d531b1711a594445a45dcc91cd4c3c173ba52aed7b51b
4
- data.tar.gz: 7300606b1b8b36f68c547bf2e5ddfff2ae6e63c56528ab7d350040c2230ddba6
3
+ metadata.gz: baf5925e72ba2632808c7ab3b981b00ed2a94cf1f4fbb634768c4b544251b822
4
+ data.tar.gz: 5786405ffab8b20d1bc1623f070483cc6f39d519e1fdc71e8d8ebe9464a7489d
5
5
  SHA512:
6
- metadata.gz: 14a5342cd442e3636396d0645b6d38caae12ff139d0fff5519180269623feff4c63cc95318b1f476e1bdb29be158cac028f3539eb0eb71835c9dbb47e5233fbd
7
- data.tar.gz: ec63c0588f3e22dc9d0fe7159b9ee1b5c4e706361791ba6c4ca32e10084ef3542a053a2c4c4a813ee7fb0699492964bf93a605a31221c21c02aceb3fb05613c9
6
+ metadata.gz: b15ea70ada75c5608a69d55e1220dd93a50dda8ce0af64b44ab0f15e6a6da7d075b70159267313d8cdd1f36495a848c38c8827ce267d2f2db503d46445fb2ed1
7
+ data.tar.gz: d1368cfd4af314c40ca8af3646e4e10facd508281e9e3180b79c30d17c7fd1b2466e0375826be4e86609898eb4253501c4a3540e8904f78a29eabb41146f515b
data/CHANGELOG.md CHANGED
@@ -1,3 +1,40 @@
1
+ # Changelog
2
+
3
+ ## [v1.1.4] — 2026-07-28
4
+
5
+ ### Added
6
+ - `Browser#toggle_hidden` — show/hide dotfiles with `H` key
7
+ - `Browser#help` keybinding (`?h`)
8
+ - `Terminal.on_resize` — trap SIGWINCH for terminal resize
9
+ - `Stack#draw_hints` clears hint area before redrawing
10
+
11
+ ### Changed
12
+ - `Space` boundary methods: per-boundary nil defaults (`left: 0`, `top: 0`, `right: left + @max`, `bottom: rows + headspace`) instead of a single clamped formula
13
+ - `Space#initialize` no longer sets `@left`/`@top` defaults
14
+ - `Browser#initialize` defaults `@left`/`@top` to 0
15
+ - `Browser#cd` filters dotfiles when `@show_hidden` is false
16
+ - `Browser#reset_view` re-calls `cd` to refresh directory listing
17
+ - `Stack#pick` no longer resets `@hints_start` on each call
18
+ - Removed unused `@totals` from Grid, `@highlight` from Stack
19
+ - Removed shebangs and `frozen_string_literal` comments from library files
20
+ - Terminal: graceful non-TTY handling for non-interactive environments
21
+ - Curses and graphical frontends: cleaned up dead code and whitespace
22
+
23
+ ### Fixed
24
+ - `Space` specs check method returns instead of instance variables
25
+
26
+ ---
27
+
28
+ ## [v1.1.3] — 2026-07-27
29
+
30
+ ### Added
31
+
32
+ ### Changed
33
+
34
+ ### Fixed
35
+ - `Stack#draw_hints` compared a relative offset against an absolute position, drawing one extra hint below the data
36
+
37
+ ---
1
38
 
2
39
  ## [v1.1.0] — 2026-07-26
3
40
 
data/example/top500.csv CHANGED
@@ -1,3 +1,4 @@
1
+ rank,word,pos,count,quot
1
2
  1,the,a,22038615,0.98
2
3
  2,be,v,12545825,0.97
3
4
  3,and,c,10741073,0.99
data/lib/browser.rb CHANGED
@@ -1,7 +1,3 @@
1
- #!/usr/bin/env ruby
2
- # coding: utf-8
3
- # frozen_string_literal: true
4
-
5
1
  require 'etc'
6
2
  require 'find'
7
3
  require_relative 'grid.rb'
@@ -42,7 +38,7 @@ module Typr
42
38
 
43
39
  ## Height minus 2 rows reserved for path bar and command line.
44
40
 
45
- def bottom; super - 2 end
41
+ def bottom; super - 1 end
46
42
 
47
43
  ## Top offset plus one row for the path info bar.
48
44
 
@@ -71,7 +67,8 @@ module Typr
71
67
  @dir_history.uniq!
72
68
  end
73
69
  end
74
- data = Dir.new(@directory).children.map.with_index do |file,id|
70
+ data = Dir.new(@directory).children.reject{|f|
71
+ !@show_hidden and f[0] == ?. }.map.with_index do |file,id|
75
72
  if File.symlink? file
76
73
  target = File.readlink( file ) rescue $!.to_s
77
74
  next [file, target] + [??]*7 + ["inode","symlink"] unless File.exist?(file)
@@ -203,6 +200,15 @@ module Typr
203
200
 
204
201
  def home; cd ?~ end
205
202
 
203
+ ## Toggle visibility of hidden files (those starting with a dot).
204
+ #
205
+ # browser.toggle_hidden
206
+
207
+ def toggle_hidden
208
+ @show_hidden = !@show_hidden
209
+ cd @directory
210
+ end
211
+
206
212
  ## Display a help grid listing all keybindings.
207
213
 
208
214
  def help; @user.help end
@@ -222,7 +228,7 @@ module Typr
222
228
  #
223
229
  # browser.reset_view
224
230
 
225
- def reset_view; reset [:display, :selection, :position]; sort end
231
+ def reset_view; cd @directory; reset [:display, :selection, :position]; sort end
226
232
 
227
233
  ## Open a filter popup on the chosen row/column and apply the input.
228
234
  #
@@ -365,8 +371,10 @@ module Typr
365
371
 
366
372
  def initialize args={}
367
373
  @dir_history, @mimetype_db, @mimetype_magic = [], true, true
368
- @view, @sort, @views, @positions = :compact, 0, {}, {}
374
+ @view, @sort, @views, @positions, @show_hidden = :compact, 0, {}, {}, false
369
375
  super
376
+ @left ||= 0
377
+ @top ||= 0
370
378
  @directory ||= ?~
371
379
  @colors[:actions] = { "[f]ilter": :red, "[s]ort": :blue, "[v]iews": :green
372
380
  }.merge @colors[:actions] || {}
@@ -385,9 +393,10 @@ module Typr
385
393
  }.merge( @colors[ :types ] || {} )
386
394
 
387
395
  @keymap = { back: KEY_BACKSPACE, confirm: KEY_RETURN, help: ?h,
388
- home: ?~, root: ?`, views: ?v, sort_view: ?s, dir_history: ?d,
396
+ home: ?~, views: ?v, sort_view: ?s, dir_history: ?d,
389
397
  mark: ?m, mark_range: ?M, mark_all: ?a, mark_invert: ?i,
390
- filter_view: ?f, reset_view: ?r, recurse: ?R}.merge @keymap
398
+ filter_view: ?f, reset_view: ?r, recurse: ?R,
399
+ toggle_hidden: ?H}.merge @keymap
391
400
 
392
401
  self.header = %w[ name target permissions owner group size accessed
393
402
  modified created type subtype ]
@@ -422,8 +431,8 @@ module Typr
422
431
  @user ||= Line.new( parent:self, left:->{@parent.left},top:->{@parent.bottom+1},
423
432
  bindings: %w[ [h]elp ] + @colors[:actions].map{|name,color|
424
433
  color_code( color ) + name.to_s + color_code(@colors[:default]) } +
425
- %w[ [r]eset [d]irectories [m]ark [M]ark\ range mark\ [a]ll
426
- [i]nvert\ mark [`]:root [~]:home [back]:.. [up] [down] [pageup] [pagedown] [home] [end] [esc]:quit [return]:confirm\ ])
434
+ %w[ [H]idden_files [r]eset [d]irectories [m]ark [M]ark_range mark_[a]ll
435
+ [i]nvert_mark [~]:home [back]:.. [up] [down] [pageup] [pagedown] [home] [end] [esc]:quit [return]:confirm\ ])
427
436
  cd @directory
428
437
  end
429
438
  end
data/lib/curses.rb CHANGED
@@ -1,8 +1,6 @@
1
- #!/usr/bin/ruby
2
-
3
1
  require 'ncursesw'
4
2
  require_relative 'frontend'
5
-
3
+
6
4
  module Visuals
7
5
 
8
6
  include Ncurses
@@ -11,50 +9,43 @@ module Visuals
11
9
  KEY_TAB = 9
12
10
  KEY_PAGEDOWN = KEY_NPAGE
13
11
  KEY_PAGEUP = KEY_PPAGE
14
- KEY_INSERT = KEY_IC
15
- KEY_DELETE = KEY_DC
16
-
12
+
17
13
  $colors = COLORS.keys
18
14
  $pairs = []
19
- # COLORS = %w[ black red green yellow blue magenta cyan white grey]
20
- # KEY_TAB = 9
21
- # HEIGHT,WIDTH = IO.console.winsize
22
15
 
23
- %w[color pair].each{ |name| method = <<STR
24
- def %s_for obj; #return unless obj
16
+ %w[color pair].each{ |name| method = <<STR
17
+ def %s_for obj;
25
18
  if id = $%ss.index( obj ) then return id
26
19
  else last = ( $%ss << obj.dup ).count - 1
27
- Ncurses.init_%s( last, *obj )
20
+ Ncurses.init_%s( last, *obj )
28
21
  return last
29
22
  end
30
23
  end
31
24
  STR
32
25
  eval( method % ([name]*4) )
33
26
  }
34
-
27
+
35
28
  def self.width; Ncurses.COLS end
36
29
  def self.height; Ncurses.LINES end
37
- def self.row; Ncurses.getcury $creen end
38
- def self.column; Ncurses.getcurx $creen end
39
-
30
+ def self.row; Ncurses.getcury $screen end
31
+ def self.column; Ncurses.getcurx $screen end
32
+
40
33
  def self.exit
41
34
  Ncurses.echo
42
35
  Ncurses.nocbreak
43
36
  Ncurses.nl
44
37
  Ncurses.endwin
45
- # system "reset"
46
38
  end
47
39
 
48
- def read input
40
+ def read input
49
41
  case input
50
42
  when :key
51
- key = Ncurses.getch
52
- key = key.chr if key.between? 32, 126
43
+ key = Ncurses.getch
44
+ key = key.chr if key.between? 32, 126
53
45
  return key
54
- when :line #string
46
+ when :line
55
47
  Ncurses.echo
56
- Ncurses.curs_set 1
57
- # Ncurses.getstr str=""
48
+ Ncurses.curs_set 1
58
49
  str = Readline.readline
59
50
  Ncurses.curs_set 0
60
51
  Ncurses.noecho
@@ -64,88 +55,64 @@ eval( method % ([name]*4) )
64
55
 
65
56
  def move x=0,y=0; Ncurses.move y, x end
66
57
  def refresh; Ncurses.refresh end
67
- def enable attr; Ncurses.attron attr end
68
- def disable attr; Ncurses.attroff attr end
69
- def clear type=:screen;
70
- case type
58
+ def clear type=:screen;
59
+ case type
71
60
  when :screen; Ncurses.erase
72
61
  when :line; Ncurses.clrtoeol
73
62
  when :down; Ncurses.clrtobot
74
- end
63
+ end
75
64
  end
76
65
  def change; Ncurses.color_set pair_for( $color ), 0 end
77
66
  def show string; Ncurses.addstr string.to_s end
78
67
 
79
68
  def get_background; $color[1] end
80
69
  def get_foreground; $color[0] end
81
- def background color;
82
- $color[1] = (color ? color_for( color ) : $default[1]); change
70
+ def background color;
71
+ $color[1] = (color ? color_for( color ) : $default[1]); change
83
72
  end
84
- def foreground color;
85
- $color[0] = (color ? color_for( color ) : $default[0]); change
73
+ def foreground color;
74
+ $color[0] = (color ? color_for( color ) : $default[0]); change
86
75
  end
87
76
 
88
77
  def color c
89
78
  c = [c] unless c.is_a? Array and c.count == 2
90
- foreground c[0] if c[0]
91
- background c[1] if c[1]
79
+ foreground c[0] if c[0]
80
+ background c[1] if c[1]
92
81
  end
93
82
 
94
- # def color_pair pair
95
- # if id = $color_pairs.index( pair ) return id
96
- # else last = ( $color_pairs << c ).count - 1
97
- # Ncurses.init_pair( last, *pair )
98
- # return last
99
- # end
100
- # pair = p.map{ |col|
101
- # unless id = $colors.index( col )
102
- # id = ($colors << col).count - 1
103
- # Ncurses.init_color id, *col
104
- # end
105
- # id
106
- # }
107
- # unless ( id = $color_pairs.index( pair ) )
108
- # id = ( $color_pairs << pair ).count - 1
109
- # Ncurses.init_pair id, *pair
110
- # end
111
- # id
112
- # end
113
-
114
- def self.init args={}
115
- # SCREEN = Ncurses.initscr
83
+ def self.init args={}
116
84
  $creen = Ncurses.initscr
117
- Ncurses.cbreak # provide unbuffered input
118
- Ncurses.noecho # turn on input echoing
119
- Ncurses.nl # turn on newline translation
120
- # Ncurses.nonl # turn off newline translation
85
+ Ncurses.cbreak
86
+ Ncurses.noecho
87
+ Ncurses.nl
121
88
  Ncurses.curs_set 0
122
89
  Ncurses.start_color
123
- Ncurses.stdscr.intrflush(false) # turn off flush-on-interrupt
124
- Ncurses.stdscr.keypad(true) # turn on keypad mode
90
+ Ncurses.stdscr.intrflush(false)
91
+ Ncurses.stdscr.keypad(true)
125
92
 
126
- $default = [
127
- color_for( args[:foreground] || :grey80 ),
93
+ $default = [
94
+ color_for( args[:foreground] || :grey80 ),
128
95
  color_for( args[:background] || :grey10 ) ]
129
96
  $color = $default.dup
130
97
 
131
- COLORS.each_with_index{ |c,i|
132
- $pairs << [ i, $default[1] ]
133
- Ncurses.init_color i, *c[1]
98
+ COLORS.each_with_index{ |c,i|
99
+ $pairs << [ i, $default[1] ]
100
+ Ncurses.init_color i, *c[1]
134
101
  Ncurses.init_pair i, i, $default[1] }
135
-
102
+
136
103
  Ncurses.bkgd Ncurses::COLOR_PAIR( pair_for $default )
137
104
 
138
- end
105
+ end
139
106
 
140
107
  end
141
108
 
142
109
  if __FILE__ == $0
143
110
  include Visuals
144
- Visuals.init #background: :blue
111
+ Visuals.init
145
112
  characters = (32..126).map(&:chr).join
146
113
  loop do
147
114
  clear
148
- $colors.each_with_index{ |c,i|
115
+ $colors.each_with_index{ |c,i|
149
116
  foreground c; move 0,i; show characters }
150
117
  refresh
151
118
  exit if read(:key) == KEY_ESCAPE
data/lib/frontend.rb CHANGED
@@ -2,18 +2,7 @@ require 'readline'
2
2
 
3
3
  module Visuals
4
4
 
5
- # COLORS = {
6
- # black: [ 0, 0, 0],
7
- # red: [ 700, 400, 400],
8
- # green: [ 400, 700, 400],
9
- # yellow: [ 700, 700, 400],
10
- # blue: [ 400, 400, 700],
11
- # magenta: [ 700, 400, 700],
12
- # cyan: [ 400, 700, 700],
13
- # white: [ 999, 999, 999],
14
- # grey: [ 618, 618, 618] }
15
-
16
- COLORS = {
5
+ COLORS = {
17
6
  black: [ 0, 0, 0],
18
7
  red: [ 180, 100, 100],
19
8
  green: [ 100, 180, 100],
@@ -24,10 +13,7 @@ module Visuals
24
13
  white: [ 255, 255, 255],
25
14
  grey: [ 158, 158, 158] }
26
15
 
27
- COLORS.merge! 1.upto(9).map{ |i|
28
- ["grey#{ i*10 }".to_sym, [i*25]*3 ] }.to_h
29
-
30
- # COLORS.merge! 1.upto(9).map{ |i|
31
- # ["grey#{ i*10 }".to_sym, [i*100]*3 ] }.to_h
16
+ COLORS.merge! 1.upto(9).map{ |i|
17
+ ["grey#{ i*10 }".to_sym, [i*25]*3 ] }.to_h
32
18
 
33
19
  end
data/lib/graphical.rb CHANGED
@@ -1,22 +1,16 @@
1
- #!/usr/bin/ruby
2
1
  require 'sdl2'
3
- #require 'io/console'
4
- #require 'readline'
5
2
  require_relative 'frontend'
6
-
3
+
7
4
  module Visuals
8
5
  include SDL2
9
6
 
10
- public
11
- i=-1
12
- # SDL2.init(SDL2::INIT_EVERYTHING)
13
7
  SDL2.init(SDL2::INIT_VIDEO)
14
8
  TTF.init
15
- WINDOW = Window.create("visuals",
16
- Window::POS_CENTERED, #POS_UNDEFINED,
17
- Window::POS_CENTERED, #POS_UNDEFINED,
9
+ WINDOW = Window.create("visuals",
10
+ Window::POS_CENTERED,
11
+ Window::POS_CENTERED,
18
12
  1324, 768, 0)
19
- GO = WINDOW.create_renderer(-1,
13
+ GO = WINDOW.create_renderer(-1,
20
14
  Renderer::Flags::ACCELERATED|Renderer::Flags::TARGETTEXTURE)
21
15
  Key.constants.each{ |c| c = c.to_s
22
16
  eval 'KEY_'+c.upcase+'=Key::'+c }
@@ -27,8 +21,7 @@ public
27
21
  def self.column; $col end
28
22
  def self.x; $x end
29
23
  def self.y; $y end
30
-
31
-
24
+
32
25
  def color_for c
33
26
  return unless c
34
27
  c = COLORS[c] if c.is_a?( Symbol )
@@ -39,136 +32,93 @@ public
39
32
  def get_foreground; $color[0] end
40
33
  def background color; return unless color
41
34
  $color[1] = color_for( color ) end
42
- def foreground color;
35
+ def foreground color;
43
36
  $color[0] = (color ? color_for( color ) : $default[0]) end
44
37
 
45
- def color c
46
- c = [c] unless c.is_a? Array and c.count == 2 #.flatten
38
+ def color c
39
+ c = [c] unless c.is_a? Array and c.count == 2
47
40
  foreground c[0]
48
41
  background c[1]
49
- # $letters[c] = (32.upto 126).map{ |n| n = n.chr
50
- # [n, $font.render_blended( n, c )] }.to_h unless $letters[c]
51
42
  end
52
43
 
53
44
  def move col, row
54
- $x = ($col = col) * $charsize[1] #width
55
- $y = ($row = row) * $charsize[0] #$height
45
+ $x = ($col = col) * $charsize[1]
46
+ $y = ($row = row) * $charsize[0]
56
47
  end
57
48
 
58
- def clear type = :screen #bg=
59
- GO.draw_color = $default[1] #bg
60
- case type
61
- # when Array; GO.fill_rect Rect.new()
62
- when :screen; GO.fill_rect Rect.new(0, 0, *WINDOW.size)
49
+ def clear type = :screen
50
+ GO.draw_color = $default[1]
51
+ case type
52
+ when :screen; GO.fill_rect Rect.new(0, 0, *WINDOW.size)
63
53
  when :line; GO.fill_rect Rect.new(
64
54
  Visuals.x, Visuals.y, WINDOW.size[0], Visuals.y+$charsize[0])
65
55
  when :down; GO.fill_rect Rect.new(
66
56
  0, Visuals.y, *WINDOW.size)
67
57
  end
68
58
  end
69
-
70
- def show( str ) #solid_blended_shaded(
59
+
60
+ def show( str )
71
61
  return unless str
72
- # chars = str.chars.map{ |char| $letters[foreground][char] }
73
- # width = chars.map( &:w ).sum
74
- # if $color[1] != $default[1] #get_background
75
62
  if get_background
76
63
  GO.draw_color = get_background
77
- GO.fill_rect Rect.new($x, $y, str.size*$charsize[1], $charsize[0])
64
+ GO.fill_rect Rect.new($x, $y, str.size*$charsize[1], $charsize[0])
78
65
  end
79
- # GO.fill_rect Rect.new($x, $y, width, $charsize[0])
80
- # text = Surface.new( width, $charsize[0], 32, 0, 0, 0, 0 )
81
- # x=0
82
- # for char in chars #.each{|c|
83
- # Surface.blit char, nil, text, Rect.new( x, 0, char.w, char.h )
84
- # x += char.w
85
- # end
86
- # GO.copy GO.create_texture_from(text),nil,Rect.new($x, $y, width, $charsize[0])
87
66
  text = str.rstrip
88
67
  unless text.empty?
89
68
  image = $font.render_blended( text, get_foreground )
90
69
  GO.copy GO.create_texture_from( image ), nil,
91
- Rect.new($x, $y, image.w, $charsize[0])
92
- end
70
+ Rect.new($x, $y, image.w, $charsize[0])
71
+ end
93
72
  move $col+str.size, $row
94
73
  end
95
74
 
96
75
  def refresh; GO.present end
97
76
 
98
- def read input
77
+ def read input
99
78
  case input
100
79
  when :event then e = Event.poll until e
101
- when :key then
80
+ when :key then
102
81
  e = Event.poll until e.is_a? Event::KeyDown
103
- return e.sym.between?(32, 126) ? e.sym.chr : e.sym
104
- when :line#; line = ''
105
- # File.mkfifo( 'input' ) unless File.exist? 'input'
106
- # Readline.output=input=open('input')
107
- # Readline.output=input=StringIO.new
108
- # fork{ Readline.readline }
82
+ return e.sym.between?(32, 126) ? e.sym.chr : e.sym
83
+ when :line
109
84
  x, y = Visuals.row, Visuals.column
110
- listen = Thread.new{
111
- # until (char = input.read) == $/
112
- # until (line = Readline.line_buffer)[-1] == $/
85
+ listen = Thread.new{
113
86
  loop do
114
87
  move x, y
115
88
  show line
116
- sleep 0.1
117
- end
118
- }
119
- line = Readline.readline
89
+ sleep 0.1
90
+ end
91
+ }
92
+ line = Readline.readline
120
93
  listen.terminate
121
- # until input.string[-1]==$/
122
94
  return line
123
- # until (key = read :key) == KEY_RETURN
124
- # str << key if key.is_a? String
125
- # end
126
- #
127
- # text = ""
128
- # TextInput.start
129
- # loop do
130
- ## ev = Event.poll
131
- # case ev = read( :event )
132
- # when Event::KeyDown
133
- # if ev.sym == KEY_RETURN
134
- # TextInput.stop
135
- # return text
136
- # end
137
- # when Event::TextInput
138
- # text += ev.text
139
- # show ev.text
140
- # p ev.text
141
- # end
142
- # end
143
95
  end
144
96
  end
145
97
 
146
98
  def self.exit
147
99
  end
148
100
 
149
- def self.init args={}
150
- $default = [
151
- color_for( args[:foreground] || :grey80 ),
101
+ def self.init args={}
102
+ $default = [
103
+ color_for( args[:foreground] || :grey80 ),
152
104
  color_for( args[:background] || :grey10 ) ]
153
105
  $color = $default.dup
154
106
  $charsize = args[:charsize] || [18,11]
155
107
  $font = TTF.open( args[:font] || "/usr/share/fonts/X11/TTF/VeraMono.ttf", $charsize[0] )
156
108
  move 0, 0
157
109
  end
158
-
110
+
159
111
  end
160
112
 
161
113
  if __FILE__ == $0
162
- # require_relative 'base'
163
114
  include Visuals
164
- Visuals.init font:ARGV[0] #[[200,200,200],[20,20,20]], [80,50]
115
+ Visuals.init font:ARGV[0]
165
116
  characters = (32..126).map(&:chr).join
166
117
  loop do
167
118
  clear
168
- COLORS.keys.each_with_index{ |c,i|
119
+ COLORS.keys.each_with_index{ |c,i|
169
120
  foreground c; move 0,i; show characters }
170
121
  refresh
171
- # GO.present
172
122
  exit if read(:key) == KEY_ESCAPE
173
123
  end
174
124
  end
data/lib/grid.rb CHANGED
@@ -1,7 +1,3 @@
1
- #!/usr/bin/env ruby
2
- # coding: utf-8
3
- # frozen_string_literal: true
4
-
5
1
  require_relative 'space.rb'
6
2
 
7
3
  module Typr
@@ -127,8 +123,9 @@ module Typr
127
123
  # @param h [Array<String, Symbol>]
128
124
 
129
125
  def header=( h ); super
130
- h.each_with_index{ |h,i| Typr.module_eval h.upcase+?=+i.to_s } if
131
- h.is_a? Array
126
+ h.each_with_index{ |h,i|
127
+ Typr.const_set(h.upcase, i) unless Typr.const_defined?(h.upcase)
128
+ } if h.is_a? Array
132
129
  end
133
130
 
134
131
  ##
@@ -143,7 +140,7 @@ module Typr
143
140
  def reset type=:all
144
141
  case type
145
142
  when :display; @map = nil; @sort = nil; @filters.clear
146
- when :format; @widths.clear; @maxed = false
143
+ when :format; @widths.clear
147
144
  when :all; reset [:display, :format]
148
145
  end
149
146
  super
@@ -404,8 +401,8 @@ module Typr
404
401
  @columns,@functions = 0,{}
405
402
  @ignore,@rawfilter,@rawsort,@reverse = [],[],[],false
406
403
  @filters,@procs = [],{}
407
- @align,@format,@widths,@totals = [],[],[],[]
408
- super #args
404
+ @align,@format,@widths = [],[],[]
405
+ super
409
406
  @colors = { columns: [], fields: {} }.merge ( @colors )
410
407
  @selected = { fields:[], columns:[] }.merge @selected
411
408
  @functions = {
@@ -414,12 +411,7 @@ module Typr
414
411
  magnitudes: Proc.new{ |size| mag = (size.to_s.length-1) / 3
415
412
  mag>0 ? (size.to_s.insert -(mag*3+1), ?.)[0..4] + %w[B K M G T][mag] :
416
413
  size rescue size },
417
- convert: Proc.new{ |value|
418
- case value.to_s
419
- when /^[\d]+$/ then value.to_s.to_i
420
- when /^\d*[\.\,]\d+$/ then value.to_s.to_f
421
- else value
422
- end } }
414
+ convert: Proc.new{ |value| coerce_type value } }
423
415
 
424
416
  if @input
425
417
  self << @input
data/lib/stack.rb CHANGED
@@ -1,7 +1,3 @@
1
- #!/usr/bin/env ruby
2
- # coding: utf-8
3
- # frozen_string_literal: true
4
-
5
1
  module Typr
6
2
 
7
3
  ##
@@ -85,11 +81,15 @@ module Typr
85
81
  positions( row_id )[ @hints_start..-1 ].each_with_index{ |pos, idx|
86
82
  move( left + pos, top + row_id )
87
83
  show @hints[idx] }
88
- else @hints.chars.each_with_index{ |char, idx|
89
- pos = idx + @hints_start + headspace
90
- break if pos > [height, rows-1+headspace].min
91
- move( left, top + pos )
92
- show char }
84
+ else
85
+ bottom = top + headspace + [height, rows].min - 1
86
+ (top + headspace..bottom).each{ |pos|
87
+ move( left, pos ); show ' ' }
88
+ @hints.chars.each_with_index{ |char, idx|
89
+ pos = idx + @hints_start + headspace
90
+ break if top + pos > bottom
91
+ move( left, top + pos )
92
+ show char }
93
93
  end
94
94
  end
95
95
 
@@ -195,7 +195,6 @@ module Typr
195
195
  # stack.pick "rows" # multi-select rows
196
196
 
197
197
  def pick type = :row, row=0 #, key=nil
198
- @hints_start = 0
199
198
  type = type.to_s
200
199
  multiple = type[-1] == ?s
201
200
  loop do
@@ -262,9 +261,9 @@ module Typr
262
261
 
263
262
  def initialize args={}
264
263
  @keymap, @separator, @selected = {}, " ", {}
265
- @start, @hints_start, @highlight = 0, 0, 0#A_STANDOUT
264
+ @start, @hints_start = 0, 0
266
265
  @alternate = true
267
- super #args
266
+ super
268
267
  @colors = { hints: [255, :black ], header: [232,:grey60 ],
269
268
  selected: :grey25, alternate: :grey10, rows: {} }.merge @colors
270
269
  @selected = { fields:[], columns:[], rows:[] }.merge @selected
data/lib/terminal.rb CHANGED
@@ -1,286 +1,200 @@
1
- #!/usr/bin/ruby
2
-
3
1
  require 'io/console'
4
2
  require 'readline'
5
3
  require 'unicode/display_width'
6
4
 
7
- module Typr
8
- # alias :show :print
5
+ module Typr
9
6
 
10
- INPUT = (IO.new IO.sysopen "/dev/tty", "r")
11
- OUTPUT = (IO.new IO.sysopen "/dev/stdin", "w")
12
- `infocmp -L1`.split.each{ |info| key,value = info[0..-2].split("=")
7
+ INPUT = (IO.new IO.sysopen("/dev/tty", "r")) rescue $stdin
8
+ `infocmp -L1`.split.each{ |info| key,value = info[0..-2].split("=")
13
9
  if value
14
- # p key + value if key[/dis/]
15
- # value[1] = ?e if value[0,2] == "\\E"
16
10
  value.gsub! '\E', '\e'
17
- # value = '\x' + value[/\d+/].to_i(8).to_s(16).upcase if value[/\\\d+/]
18
- # value = "\\x" + value[/\d+/].to_i(8).to_s(16).upcase if value[/\\\d+/]
19
11
  value += "\\" if value[-1] == "\\"
20
- # eval "%s=\'%s\'" % [key.upcase,value] if key
21
- eval "%s=\"%s\"" % [key.upcase,value] if key
22
- #and key.start_with? "key_"
12
+ eval "%s=\"%s\"" % [key.upcase,value] if key
23
13
  end }
24
-
14
+
25
15
  KEY_ESCAPE = "\e"
26
16
  KEY_RETURN = CARRIAGE_RETURN
27
17
  KEY_TAB = "\t"
28
- KEY_ENTER = CARRIAGE_RETURN
29
18
  KEY_PAGEDOWN = KEY_NPAGE
30
19
  KEY_PAGEUP = KEY_PPAGE
31
- KEY_INSERT = KEY_IC
32
- KEY_DELETE = KEY_DC
33
20
 
34
- MODES = %i[ reset bold faint italic underline slow fast invert ]
21
+ MODES = %i[ reset bold italic underline slow fast invert ]
35
22
  COLORS = %i[ black red green yellow blue magenta cyan white ]
36
23
 
37
24
  def prepare str, max, align=:left, side=:right, fade=false
38
25
  stop = width = real_size( str )
39
- # unless str[0..max-1].ascii_only? and width == str.size
40
26
  unless str.ascii_only? and width == str.size
41
27
  stop = width = 0
42
28
  str.each_char do |c|
43
- if c == ?\e
29
+ if c == ?\e
44
30
  width -= str[stop..-1][/^\x1b\[[^m]+m|/].size-1
45
31
  stop += 1
46
32
  elsif (cwidth = (c.ascii_only? ? 1 : Unicode::DisplayWidth.of(c))) +
47
33
  width >= max
48
34
  break
49
35
  else width += cwidth; stop += 1 end
50
- end
36
+ end
51
37
  end
52
- # return
53
- if ( space = ( max - width ) ) > 0 #.clamp 0, max
38
+ if ( space = ( max - width ) ) > 0
54
39
  str = [ str[0..stop-1], " " * space ]
55
40
  str.reverse! if align == :right
56
41
  str.join
57
- else #case align
58
- # when :left; str = str[0..max-1]
59
- # when :right;
42
+ else
60
43
  str = str[side == :left ? -max..-1 : 0..max-1]
61
- # end
62
- # str = fade str, align, str.length / 8 + 1 if fade
63
44
  str = fade str, side, fade if fade
64
45
  return str
65
46
  end
66
- # return str.join
67
47
  end
68
-
48
+
69
49
  def fade str, side=:left, num=3
70
50
  isleft = side == :left
71
- # chars = (side == ? 0..num : (-num-1..-2).to_a.reverse)
72
51
  chars = str[ isleft ? 0..num : -num..-1 ]
73
52
  chars = chars.chars.map.with_index do |char,id|
74
53
  id = chars.size-id unless isleft
75
54
  color_code( "grey#{(80/chars.size)*id+10}".to_sym ) + char
76
55
  end.join
77
- # chars.each.with_index do |pos,id|
78
- # str.insert pos, color_code( "grey#{(80/chars.size)*id+10}".to_sym )
79
- # str.insert pos, color_code( "grey#{(100/id+3)*10}".to_sym )
80
- # end
81
56
  return ( isleft ? chars + color_code($color[0]) + str[num+1..-1] :
82
57
  str[0..-num-1] + chars )
83
-
84
- #+ color_code( $color[1] )
85
- # return str
86
- # length.times{|i|
87
- # color [ ("grey"+((i+3)*10).to_s ).to_sym, @colors[:default][1] ]
88
- # show @directory[-space+i] }
89
- # color @colors[:default]
90
- # show @directory[-space+6..-1]
91
58
  end
92
- # def printables str; str.dump.gsub(/\\e\[.+m|\"/, '') end
59
+
93
60
  def printables str; str.gsub(/\x1b\[[^m]+m|/,'') end
94
- # def real_size str; printables(str).size end
95
61
  def real_size str; Unicode::DisplayWidth.of( printables(str) ) end
96
-
97
- # $>.print "\e[%iJ" % %w[down line screen].index(mode.to_s)
98
- def move x=0,y=0; show move_code( x, y ) end
62
+
63
+ def coerce_type value
64
+ s = value.to_s
65
+ return nil if s.empty? or /\A(?:nil|NULL)\z/i.match(s)
66
+ case value
67
+ when /^-?[\d]+$/ then s.to_i
68
+ when /^-?\d*[\.\,]\d+$/ then s.to_f
69
+ when /\byes\z/i then true
70
+ when /\bno(ot)?\z/i then false
71
+ when /true\z/i then true
72
+ when /false\z/i then false
73
+ else value
74
+ end
75
+ end
76
+
77
+ def move x=0,y=0; show move_code( x, y ) end
99
78
  def move_code x=0,y=0; "\e[%i;%if" % [ y+1, x+1 ] end
100
-
101
- def mode name; show mode_code(name) end
102
- def mode_code name; if id = MODES.index(name.to_s) then "\e[#{ id }m" end end
103
-
79
+
80
+ def mode name; show mode_code(name) end
81
+ def mode_code name; if id = MODES.index(name.to_s) then "\e[#{ id }m" end end
82
+
104
83
  def color_code color, bg=false
105
84
  color = color.to_sym if color.is_a? String
106
85
  case color
107
- when Symbol; #color = color.to_s
86
+ when Symbol;
108
87
  if id = COLORS.index(color); "\e[#{ id + (bg ? 40 : 30) }m"
109
88
  elsif color[/^gr[ae]y\d{,2}$/]
110
89
  "\e[%i;5;%im" % [bg ? 48 : 38, 232 + (color[/\d+/].to_f/100*23).to_i]
111
90
  end
112
91
  when Integer; "\e[%i;5;%im" % [ bg ? 48 : 38, color]
113
92
  when Array; case color.count
114
- when 3; "\e[%i;2;%i;%i;%im" % [ bg ? 48 : 38, *color ]
93
+ when 3; "\e[%i;2;%i;%i;%im" % [ bg ? 48 : 38, *color ]
115
94
  when 2; color_code( color[0] ) + color_code( color[1], true )
116
95
  end
117
96
  end
118
97
  end
119
-
120
- def get_background; $color[1] end
98
+
99
+ def get_background; $color[1] end
121
100
  def get_foreground; $color[0] end
122
101
  def foreground c=$default[0]; $color[0]=c; show color_code(c) end
123
102
  def background c=$default[1]; $color[1]=c; show color_code(c,true) end
124
- # def color c=$default
125
- # c = [c] unless c.is_a? Array and c.count == 2
126
- # show color_code(c)
127
- # end
128
103
  def color c=$default
129
104
  c = [c] unless c.is_a? Array and c.count == 2
130
- foreground c[0] if c[0]
131
- background c[1] if c[1]
105
+ foreground c[0] if c[0]
106
+ background c[1] if c[1]
132
107
  end
133
108
 
134
109
  def show str; $>.print str end
135
- # def enable attr; mode attr end
136
- # def disable attr=nil; mode :reset end
137
- # def refresh; end
138
- def self.clear mode=:screen
110
+ def self.clear mode=:screen
139
111
  $>.print( { screen: CLEAR_SCREEN, line: DELETE_LINE }[mode] )
140
112
  end
141
113
 
142
114
  def self.read obj, prompt=''
143
115
  case obj
144
- when :key then INPUT.raw{ |tty| tty.sysread 6 } rescue return
145
- when :line then line=Readline.readline prompt; print CURSOR_INVISIBLE;line
116
+ when :key
117
+ return INPUT.raw{ |tty| tty.sysread 6 } rescue nil unless INPUT.tty?
118
+ INPUT.raw{ |tty| tty.sysread 6 } rescue return
119
+ when :line
120
+ $stdin.tty? ? (line=Readline.readline prompt; print CURSOR_INVISIBLE; line) : $stdin.gets&.chomp
146
121
  end
147
122
  end
148
123
 
149
124
  def self.position
125
+ return [0, 0] unless $stdin.tty?
150
126
  result = ''
151
127
  $stdin.raw do |stdin|
152
- $stdout << USER7 #"\e[6n"
128
+ $stdout << USER7
153
129
  $stdout.flush
154
130
  until (char = stdin.getc) == 'R'
155
131
  result << char if char
156
132
  end
157
133
  end
158
134
  result[/[\d;]+/].split(?;).map &:to_i
159
- # m = res.match /(?<row>\d+);(?<column>\d+)/
160
- # { row: Integer(m[:row]), column: Integer(m[:column]) }
161
135
  end
162
136
 
163
- def self.size; IO.console.winsize end
137
+ def self.size; IO.console&.winsize || [24, 80] end
164
138
  def self.width; size.last-1 end
165
- def self.height; size.first end
139
+ def self.height; size.first - 1 end
166
140
  def self.row; position.first end
167
141
  def self.column; position.last end
168
- def self.init default=[ :white, :black ]
142
+ def self.on_resize &block
143
+ trap(:WINCH, &block)
144
+ end
145
+ def self.init default=[ :white, :black ]
169
146
  $color = $default = default
170
- # include Typr
171
- # extend self
172
- # Object.undef_method :read
173
- print CURSOR_INVISIBLE
174
- system "tput smkx"
147
+ if $stdin.tty?
148
+ print CURSOR_INVISIBLE
149
+ system "tput smkx"
150
+ end
175
151
  end
176
- def self.exit;
177
- # background
152
+ def self.exit;
178
153
  extend self
179
-
180
- $>.print CURSOR_NORMAL;
181
- $>.print ORIG_COLORS; color; clear
182
-
154
+ if $stdin.tty?
155
+ $>.print CURSOR_NORMAL;
156
+ $>.print ORIG_COLORS; color; clear
157
+ end
183
158
  end
184
159
  end
185
160
 
186
- # include Typr
187
- # extend Typr
188
-
189
161
  if __FILE__ == $0
190
162
  begin
191
163
  include Typr
192
- Typr.init #background: :blue
164
+ Typr.init
193
165
  colors = COLORS + (1..9).map{|i| "grey#{i*10}" }
194
166
  chars = (33..126).map(&:chr)
195
167
  slice = chars.count / colors.count + 1
196
168
  characters = chars.each_slice( slice ).map(&:join)
197
- # key = read :key
198
169
  key,fg,bg = "",150,0
199
170
  Typr.clear
200
171
  loop do
201
- # move 0,0
202
- colors.each_with_index{ |color,y|
203
- characters.each_with_index{ |chars,x|
204
- foreground color.to_sym;
205
- background colors[x].to_sym;
172
+ colors.each_with_index{ |color,y|
173
+ characters.each_with_index{ |chars,x|
174
+ foreground color.to_sym;
175
+ background colors[x].to_sym;
206
176
  move x*slice,y
207
- show chars
177
+ show chars
208
178
  }
209
179
  }
210
180
  (0...256).each{ |i| background i; show ' ' }
211
-
212
- move 0, Typr.height-1
181
+
182
+ move 0, Typr.height
213
183
  color [:white, :black]
214
- # show "KEY: #{key}"
215
184
  p "KEY: %s / %s" % [key, key]
216
- move 15, Typr.height-1
185
+ move 15, Typr.height
217
186
  color [fg,bg]
218
- print " %s / %s " % [fg,bg] #).center 20
187
+ print " %s / %s " % [fg,bg]
219
188
  key = Typr.read(:key)
220
189
  case key
221
190
  when KEY_UP; fg+=1
222
191
  when KEY_DOWN; fg-=1
223
192
  when KEY_LEFT; bg-=1
224
193
  when KEY_RIGHT; bg+=1
225
- when KEY_ESCAPE; exit
194
+ when KEY_ESCAPE; exit
226
195
  end
227
196
  end
228
197
  ensure
229
198
  Typr.exit
230
199
  end
231
200
  end
232
-
233
-
234
- # KEY_ESC = 27
235
- # KEY_TAB =
236
- # KEY_ESC = 27
237
- # A_STANDOUT = :invert
238
- # BG = :black
239
- # `infocmp -L`.read.join.split(', ').each{ |info| }
240
- # .split('=').to_h
241
-
242
- # KEY_PAGEDOWN = "\e[6~"
243
- # KEY_PAGEUP = "\e[5~"
244
- # KEY_LEFT = "\e[D"
245
- # KEY_RIGHT = "\e[C"
246
- # KEY_UP = "\e[A"
247
- # KEY_DOWN = "\e[B"
248
- # KEY_HOME = "\e[H" #xterm
249
- # KEY_END = "\e[F" #xterm
250
- # INSERT = "\e[2~" #xterm
251
- # DELETE = "\e[3~" #xterm
252
- # KEY_BACKSPACE = "\b" #xterm
253
-
254
- # case ENV["TERM"]
255
- # when
256
- # DELETE = "\e[P" #st
257
- # INSERT = "\e[4h" #st
258
- # BACKSPACE = "\x7F" #st
259
- # KEY_END = "\e[4~" #st
260
-
261
- # KEY_HOME = "\e[7~" #urxvt
262
- # KEY_END = "\e[8~" #urxvt
263
-
264
- # HIDE_CURSOR = "\e[?25l"
265
- # SHOW_CURSOR = "\e[?25h"
266
- # HEIGHT,WIDTH = IO.console.winsize
267
-
268
-
269
- # def mod key,char,extra;
270
- # if key.length == 1; key = char + key.upcase
271
- # elsif key[/~$/]; key[0..-2] + char
272
- # else key[0..-2] + extra + key[-1].downcase end
273
- # end
274
- # def shift key; mod key, "$" end
275
- # def ctrl key; mod key, "^", "O" end
276
- # def alt key; KEYMAP[:esc] + key end
277
- # def clear mode=2; IO.console.erase_screen 1 end
278
- # def mode name; "\e[%im" % [(MODES.index name.to_s)] end
279
- # def ansi arg, type, inc=0
280
- # case arg
281
- # when Integer; show "\e[%i;5;%im" % [ inc + 8, arg]
282
- # else show "\e[%im" % [ ( type.index arg.to_s ) + inc ]
283
- # end
284
- # end
285
-
286
-
data/lib/text.rb CHANGED
@@ -1,7 +1,3 @@
1
- #!/usr/bin/env ruby
2
- # coding: utf-8
3
- # frozen_string_literal: true
4
-
5
1
  require 'stringio'
6
2
  require_relative 'stack.rb'
7
3
 
@@ -115,13 +111,6 @@ module Typr
115
111
 
116
112
  def rows; @lines.count end
117
113
 
118
- # Placeholder for text search. Currently unimplemented.
119
- #
120
- # text.search("query") # => nil
121
-
122
- def search query
123
- end
124
-
125
114
  # Creates a new Text widget.
126
115
  #
127
116
  # text = Typr::Text.new(input: "hello", header: "Title")
data/typr.gemspec CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = "typr"
5
- s.version = "1.1.1"
5
+ s.version = "1.1.4"
6
6
  s.date = "2026-07-25"
7
7
  s.homepage = "https://codeberg.org/typr/typr"
8
8
  s.licenses = ["MIT"]
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: typr
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.1
4
+ version: 1.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kilian Reitmayr