typr 1.1.2 → 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: 756f4c526a47e141947600b8ab1f712f5f55809709415bdc08182f7c84a02885
4
- data.tar.gz: 0ffb023fb815985b242d77c95e0b7fb314ffe1025c3eaa309b1df615ee7575bd
3
+ metadata.gz: baf5925e72ba2632808c7ab3b981b00ed2a94cf1f4fbb634768c4b544251b822
4
+ data.tar.gz: 5786405ffab8b20d1bc1623f070483cc6f39d519e1fdc71e8d8ebe9464a7489d
5
5
  SHA512:
6
- metadata.gz: f5bcf29384273fe9a5fbdf47474b7160485d180b0c29ddb963644a38eaf3a9695cd54d74dc7a2955fa8e25331701f3bc0295f0a8570f85a66c9b8250ef460290
7
- data.tar.gz: a05c2a49dfaf00d42510e9961ba21eb0a5075ee9f37fb2be685b212dd91a17c10e4622bbac1b958c44f5fdb385e5895f3f4d8dbbb68e8b31b949fc70252fb192
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,285 +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
- `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("=")
12
9
  if value
13
- # p key + value if key[/dis/]
14
- # value[1] = ?e if value[0,2] == "\\E"
15
10
  value.gsub! '\E', '\e'
16
- # value = '\x' + value[/\d+/].to_i(8).to_s(16).upcase if value[/\\\d+/]
17
- # value = "\\x" + value[/\d+/].to_i(8).to_s(16).upcase if value[/\\\d+/]
18
11
  value += "\\" if value[-1] == "\\"
19
- # eval "%s=\'%s\'" % [key.upcase,value] if key
20
- eval "%s=\"%s\"" % [key.upcase,value] if key
21
- #and key.start_with? "key_"
12
+ eval "%s=\"%s\"" % [key.upcase,value] if key
22
13
  end }
23
-
14
+
24
15
  KEY_ESCAPE = "\e"
25
16
  KEY_RETURN = CARRIAGE_RETURN
26
17
  KEY_TAB = "\t"
27
- KEY_ENTER = CARRIAGE_RETURN
28
18
  KEY_PAGEDOWN = KEY_NPAGE
29
19
  KEY_PAGEUP = KEY_PPAGE
30
- KEY_INSERT = KEY_IC
31
- KEY_DELETE = KEY_DC
32
20
 
33
- MODES = %i[ reset bold faint italic underline slow fast invert ]
21
+ MODES = %i[ reset bold italic underline slow fast invert ]
34
22
  COLORS = %i[ black red green yellow blue magenta cyan white ]
35
23
 
36
24
  def prepare str, max, align=:left, side=:right, fade=false
37
25
  stop = width = real_size( str )
38
- # unless str[0..max-1].ascii_only? and width == str.size
39
26
  unless str.ascii_only? and width == str.size
40
27
  stop = width = 0
41
28
  str.each_char do |c|
42
- if c == ?\e
29
+ if c == ?\e
43
30
  width -= str[stop..-1][/^\x1b\[[^m]+m|/].size-1
44
31
  stop += 1
45
32
  elsif (cwidth = (c.ascii_only? ? 1 : Unicode::DisplayWidth.of(c))) +
46
33
  width >= max
47
34
  break
48
35
  else width += cwidth; stop += 1 end
49
- end
36
+ end
50
37
  end
51
- # return
52
- if ( space = ( max - width ) ) > 0 #.clamp 0, max
38
+ if ( space = ( max - width ) ) > 0
53
39
  str = [ str[0..stop-1], " " * space ]
54
40
  str.reverse! if align == :right
55
41
  str.join
56
- else #case align
57
- # when :left; str = str[0..max-1]
58
- # when :right;
42
+ else
59
43
  str = str[side == :left ? -max..-1 : 0..max-1]
60
- # end
61
- # str = fade str, align, str.length / 8 + 1 if fade
62
44
  str = fade str, side, fade if fade
63
45
  return str
64
46
  end
65
- # return str.join
66
47
  end
67
-
48
+
68
49
  def fade str, side=:left, num=3
69
50
  isleft = side == :left
70
- # chars = (side == ? 0..num : (-num-1..-2).to_a.reverse)
71
51
  chars = str[ isleft ? 0..num : -num..-1 ]
72
52
  chars = chars.chars.map.with_index do |char,id|
73
53
  id = chars.size-id unless isleft
74
54
  color_code( "grey#{(80/chars.size)*id+10}".to_sym ) + char
75
55
  end.join
76
- # chars.each.with_index do |pos,id|
77
- # str.insert pos, color_code( "grey#{(80/chars.size)*id+10}".to_sym )
78
- # str.insert pos, color_code( "grey#{(100/id+3)*10}".to_sym )
79
- # end
80
56
  return ( isleft ? chars + color_code($color[0]) + str[num+1..-1] :
81
57
  str[0..-num-1] + chars )
82
-
83
- #+ color_code( $color[1] )
84
- # return str
85
- # length.times{|i|
86
- # color [ ("grey"+((i+3)*10).to_s ).to_sym, @colors[:default][1] ]
87
- # show @directory[-space+i] }
88
- # color @colors[:default]
89
- # show @directory[-space+6..-1]
90
58
  end
91
- # def printables str; str.dump.gsub(/\\e\[.+m|\"/, '') end
59
+
92
60
  def printables str; str.gsub(/\x1b\[[^m]+m|/,'') end
93
- # def real_size str; printables(str).size end
94
61
  def real_size str; Unicode::DisplayWidth.of( printables(str) ) end
95
-
96
- # $>.print "\e[%iJ" % %w[down line screen].index(mode.to_s)
97
- 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
98
78
  def move_code x=0,y=0; "\e[%i;%if" % [ y+1, x+1 ] end
99
-
100
- def mode name; show mode_code(name) end
101
- def mode_code name; if id = MODES.index(name.to_s) then "\e[#{ id }m" end end
102
-
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
+
103
83
  def color_code color, bg=false
104
84
  color = color.to_sym if color.is_a? String
105
85
  case color
106
- when Symbol; #color = color.to_s
86
+ when Symbol;
107
87
  if id = COLORS.index(color); "\e[#{ id + (bg ? 40 : 30) }m"
108
88
  elsif color[/^gr[ae]y\d{,2}$/]
109
89
  "\e[%i;5;%im" % [bg ? 48 : 38, 232 + (color[/\d+/].to_f/100*23).to_i]
110
90
  end
111
91
  when Integer; "\e[%i;5;%im" % [ bg ? 48 : 38, color]
112
92
  when Array; case color.count
113
- 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 ]
114
94
  when 2; color_code( color[0] ) + color_code( color[1], true )
115
95
  end
116
96
  end
117
97
  end
118
-
119
- def get_background; $color[1] end
98
+
99
+ def get_background; $color[1] end
120
100
  def get_foreground; $color[0] end
121
101
  def foreground c=$default[0]; $color[0]=c; show color_code(c) end
122
102
  def background c=$default[1]; $color[1]=c; show color_code(c,true) end
123
- # def color c=$default
124
- # c = [c] unless c.is_a? Array and c.count == 2
125
- # show color_code(c)
126
- # end
127
103
  def color c=$default
128
104
  c = [c] unless c.is_a? Array and c.count == 2
129
- foreground c[0] if c[0]
130
- background c[1] if c[1]
105
+ foreground c[0] if c[0]
106
+ background c[1] if c[1]
131
107
  end
132
108
 
133
109
  def show str; $>.print str end
134
- # def enable attr; mode attr end
135
- # def disable attr=nil; mode :reset end
136
- # def refresh; end
137
- def self.clear mode=:screen
110
+ def self.clear mode=:screen
138
111
  $>.print( { screen: CLEAR_SCREEN, line: DELETE_LINE }[mode] )
139
112
  end
140
113
 
141
114
  def self.read obj, prompt=''
142
115
  case obj
143
- when :key then INPUT.raw{ |tty| tty.sysread 6 } rescue return
144
- 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
145
121
  end
146
122
  end
147
123
 
148
124
  def self.position
125
+ return [0, 0] unless $stdin.tty?
149
126
  result = ''
150
127
  $stdin.raw do |stdin|
151
- $stdout << USER7 #"\e[6n"
128
+ $stdout << USER7
152
129
  $stdout.flush
153
130
  until (char = stdin.getc) == 'R'
154
131
  result << char if char
155
132
  end
156
133
  end
157
134
  result[/[\d;]+/].split(?;).map &:to_i
158
- # m = res.match /(?<row>\d+);(?<column>\d+)/
159
- # { row: Integer(m[:row]), column: Integer(m[:column]) }
160
135
  end
161
136
 
162
- def self.size; IO.console.winsize end
137
+ def self.size; IO.console&.winsize || [24, 80] end
163
138
  def self.width; size.last-1 end
164
- def self.height; size.first end
139
+ def self.height; size.first - 1 end
165
140
  def self.row; position.first end
166
141
  def self.column; position.last end
167
- 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 ]
168
146
  $color = $default = default
169
- # include Typr
170
- # extend self
171
- # Object.undef_method :read
172
- print CURSOR_INVISIBLE
173
- system "tput smkx"
147
+ if $stdin.tty?
148
+ print CURSOR_INVISIBLE
149
+ system "tput smkx"
150
+ end
174
151
  end
175
- def self.exit;
176
- # background
152
+ def self.exit;
177
153
  extend self
178
-
179
- $>.print CURSOR_NORMAL;
180
- $>.print ORIG_COLORS; color; clear
181
-
154
+ if $stdin.tty?
155
+ $>.print CURSOR_NORMAL;
156
+ $>.print ORIG_COLORS; color; clear
157
+ end
182
158
  end
183
159
  end
184
160
 
185
- # include Typr
186
- # extend Typr
187
-
188
161
  if __FILE__ == $0
189
162
  begin
190
163
  include Typr
191
- Typr.init #background: :blue
164
+ Typr.init
192
165
  colors = COLORS + (1..9).map{|i| "grey#{i*10}" }
193
166
  chars = (33..126).map(&:chr)
194
167
  slice = chars.count / colors.count + 1
195
168
  characters = chars.each_slice( slice ).map(&:join)
196
- # key = read :key
197
169
  key,fg,bg = "",150,0
198
170
  Typr.clear
199
171
  loop do
200
- # move 0,0
201
- colors.each_with_index{ |color,y|
202
- characters.each_with_index{ |chars,x|
203
- foreground color.to_sym;
204
- 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;
205
176
  move x*slice,y
206
- show chars
177
+ show chars
207
178
  }
208
179
  }
209
180
  (0...256).each{ |i| background i; show ' ' }
210
-
211
- move 0, Typr.height-1
181
+
182
+ move 0, Typr.height
212
183
  color [:white, :black]
213
- # show "KEY: #{key}"
214
184
  p "KEY: %s / %s" % [key, key]
215
- move 15, Typr.height-1
185
+ move 15, Typr.height
216
186
  color [fg,bg]
217
- print " %s / %s " % [fg,bg] #).center 20
187
+ print " %s / %s " % [fg,bg]
218
188
  key = Typr.read(:key)
219
189
  case key
220
190
  when KEY_UP; fg+=1
221
191
  when KEY_DOWN; fg-=1
222
192
  when KEY_LEFT; bg-=1
223
193
  when KEY_RIGHT; bg+=1
224
- when KEY_ESCAPE; exit
194
+ when KEY_ESCAPE; exit
225
195
  end
226
196
  end
227
197
  ensure
228
198
  Typr.exit
229
199
  end
230
200
  end
231
-
232
-
233
- # KEY_ESC = 27
234
- # KEY_TAB =
235
- # KEY_ESC = 27
236
- # A_STANDOUT = :invert
237
- # BG = :black
238
- # `infocmp -L`.read.join.split(', ').each{ |info| }
239
- # .split('=').to_h
240
-
241
- # KEY_PAGEDOWN = "\e[6~"
242
- # KEY_PAGEUP = "\e[5~"
243
- # KEY_LEFT = "\e[D"
244
- # KEY_RIGHT = "\e[C"
245
- # KEY_UP = "\e[A"
246
- # KEY_DOWN = "\e[B"
247
- # KEY_HOME = "\e[H" #xterm
248
- # KEY_END = "\e[F" #xterm
249
- # INSERT = "\e[2~" #xterm
250
- # DELETE = "\e[3~" #xterm
251
- # KEY_BACKSPACE = "\b" #xterm
252
-
253
- # case ENV["TERM"]
254
- # when
255
- # DELETE = "\e[P" #st
256
- # INSERT = "\e[4h" #st
257
- # BACKSPACE = "\x7F" #st
258
- # KEY_END = "\e[4~" #st
259
-
260
- # KEY_HOME = "\e[7~" #urxvt
261
- # KEY_END = "\e[8~" #urxvt
262
-
263
- # HIDE_CURSOR = "\e[?25l"
264
- # SHOW_CURSOR = "\e[?25h"
265
- # HEIGHT,WIDTH = IO.console.winsize
266
-
267
-
268
- # def mod key,char,extra;
269
- # if key.length == 1; key = char + key.upcase
270
- # elsif key[/~$/]; key[0..-2] + char
271
- # else key[0..-2] + extra + key[-1].downcase end
272
- # end
273
- # def shift key; mod key, "$" end
274
- # def ctrl key; mod key, "^", "O" end
275
- # def alt key; KEYMAP[:esc] + key end
276
- # def clear mode=2; IO.console.erase_screen 1 end
277
- # def mode name; "\e[%im" % [(MODES.index name.to_s)] end
278
- # def ansi arg, type, inc=0
279
- # case arg
280
- # when Integer; show "\e[%i;5;%im" % [ inc + 8, arg]
281
- # else show "\e[%im" % [ ( type.index arg.to_s ) + inc ]
282
- # end
283
- # end
284
-
285
-
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.2"
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.2
4
+ version: 1.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kilian Reitmayr