kv 0.2.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 07f9b8b9be509c1a29acef17374146c9381713514e19c91a8a2942f9c2ba09e9
4
- data.tar.gz: fb877ac8dbf8b5fac3f9b2c4e6690aa01fc25bca3b11fcf7abf88c52ef41fa23
3
+ metadata.gz: 573415b451a9344ac21da113782892338606925a3dd04c57d3e82805a5e55de2
4
+ data.tar.gz: 7d29a38d796aacb6d769a31c52313fc6e510ff68de5e51615e9ce7357e2f3b1a
5
5
  SHA512:
6
- metadata.gz: c8c646ba69a9a977ea232dedaaff65db9f781d054e76d846913763821678c93c5362e7f4e153574d252505181da0a73a01b7865c38ac2c380c4bc9abaadcd6bc
7
- data.tar.gz: eb9f37454be0ce707fbc02f6caae238541fe1865460e67de6c730a2eb81e2ba90d2fbaefa97f418426f19a8343e651b843f9943c61cd5e49cb2d22d15e5cde32
6
+ metadata.gz: bf24a502a46eead71095315a4d1e7c76872e849c04360e2d740e6521704ce56b75126fa45f7bfceb1b983845f4e0d9bf189fbde870e001a3a580b6b076116139
7
+ data.tar.gz: 720ac127b0e1960712493473d12254ec39b28c84f80cc0b7a99631728038da9e31a85f1970274badc89b36943632b938b3b557ac0633dd815e477259d248cdcf
@@ -0,0 +1,3 @@
1
+ # These are supported funding model platforms
2
+
3
+ github: [ko1]
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
- # kv: A page viewer written by Ruby
1
+ # kv: A page viewer written in Ruby
2
2
 
3
- kv is a page viewer designed for streaming data written by Ruby.
3
+ kv is a page viewer designed for streaming data written in Ruby.
4
4
 
5
5
  ## Installation
6
6
 
@@ -8,9 +8,7 @@ Install it yourself as:
8
8
 
9
9
  $ gem install kv
10
10
 
11
- # Usage
12
-
13
- kv requires Ruby and curses gem.
11
+ kv requires recent Ruby and curses gem.
14
12
 
15
13
  ## Use kv
16
14
 
@@ -18,17 +16,27 @@ kv requires Ruby and curses gem.
18
16
  # View [FILE]
19
17
  $ kv [OPTIONS] [FILE]
20
18
 
19
+ # View [URI] source code
20
+ $ kv [URI]
21
+
21
22
  # View results of [CMD]
22
23
  $ [CMD] | kv [OPTIONS]
23
24
 
24
25
  # View command help
25
26
  $ kv
26
27
 
27
- Options:
28
+ Usage: kv [options]
28
29
  -f following mode like "tail -f"
29
30
  -n, --line-number LINE goto LINE
31
+ -N Show lines
32
+ -T, --time-stamp Enable time stamp
33
+ -e CMD Run CMD as a child process
34
+ -p, --pipe Open named pipe
35
+ -s Separation mode (tsv)
30
36
  ```
31
37
 
38
+ Note that `--pipe` option creates a named pipe (`~/.kv_pipe` or a specified file) if there is not a fifo file.
39
+
32
40
  ## Command on a pager
33
41
 
34
42
  ```
@@ -72,12 +80,21 @@ kv: A pager by Ruby Command list
72
80
 
73
81
  # Output
74
82
  s: Save screen buffer to file
83
+ P: gist -p
84
+
85
+ # Child process
86
+ You can run child process using -e command line option like -e CMD
87
+ and you can send a meesage to the child process with x command.
88
+
89
+ x: send a message to the child process
75
90
 
76
91
  # Modes
77
92
  N: toggle line mode
93
+ T: toggle time stamp mode
78
94
  m: toggle mouse mode
79
95
  t: terminal (REPL) mode
80
96
  v: vi ("vi filename +[LINE]")
97
+ H: show HTTP response header
81
98
  ```
82
99
 
83
100
  `G` is notable feature, `less` doesn't have. This feature jumps to "current" last line even if the pipe source command does not close output (== input for kv). You can refresh the last line by putting any command.
data/lib/kv.rb CHANGED
@@ -4,22 +4,24 @@ require "kv/version"
4
4
  require "curses"
5
5
  require 'stringio'
6
6
  require 'optparse'
7
+ require 'open-uri'
7
8
 
8
9
  module KV
9
- class KV_PushScreen < Exception
10
+ class PushScreen < Exception
10
11
  attr_reader :screen
11
12
  def initialize screen
12
13
  @screen = screen
13
14
  end
14
15
  end
15
16
 
16
- class KV_PopScreen < Exception
17
+ class PopScreen < Exception
17
18
  end
18
19
 
19
- class KV_Screen
20
+ class Screen
20
21
  RenderStatus = Struct.new(
21
- :c_cols, :c_lines, :x, :y,
22
- :search, :goto, :line_mode, :render_full, :last_lineno
22
+ :c_cols, :c_lines, :x, :y, :last_lineno,
23
+ :search, :goto, :wrapping,
24
+ :line_mode, :ts_mode, :separation_mode,
23
25
  )
24
26
  class RenderStatus
25
27
  def to_s
@@ -27,7 +29,10 @@ class KV_Screen
27
29
  end
28
30
  end
29
31
 
30
- def initialize input, lines: [], search: nil, name: nil, following_mode: false, first_line: 0, line_mode: false
32
+ def initialize input, lines: [],
33
+ name: nil, search: nil, first_line: 0,
34
+ following_mode: false, line_mode: false, separation_mode: false,
35
+ time_stamp: nil, ext_input: nil, fifo_file: nil
31
36
  @rs = RenderStatus.new
32
37
  @last_rs = nil
33
38
  @rs.y = first_line
@@ -36,14 +41,22 @@ class KV_Screen
36
41
  @rs.last_lineno = 0
37
42
  @rs.line_mode = line_mode
38
43
  @rs.search = search
44
+ @rs.wrapping = false
45
+ @rs.ts_mode = false
46
+ @rs.separation_mode = separation_mode
39
47
 
40
48
  @name = name
41
49
  @filename = @name if @name && File.exist?(@name)
42
50
 
51
+ @time_stamp = time_stamp
52
+ @ext_input = ext_input
53
+ @fifo_file = fifo_file
54
+
43
55
  @lines = lines
44
56
  @mode = :screen
45
57
 
46
- @following_mode = following_mode
58
+ @following = following_mode
59
+ @apos = 0
47
60
 
48
61
  @mouse = false
49
62
  @search_ignore_case = false
@@ -51,25 +64,35 @@ class KV_Screen
51
64
  @loading = false
52
65
  @buffer_lines = 10_000
53
66
  @yq = Queue.new
54
- @load_unlimited = false
67
+ if @filename
68
+ @load_unlimited = true
69
+ else
70
+ @load_unlimited = false
71
+ end
72
+
55
73
  @prev_render = {}
74
+ @meta = input.respond_to?(:meta) ? input.meta : nil
56
75
 
57
76
  read_async input if input
58
77
  end
59
78
 
60
79
  def setup_line line
61
80
  line = line.chomp
81
+ line.instance_variable_set(:@time_stamp, Time.now.strftime('%H:%M:%S')) if @time_stamp
62
82
  line.instance_variable_set(:@lineno, @rs.last_lineno += 1)
63
83
  line
64
84
  end
65
85
 
66
86
  def read_async input
67
87
  @loading = true
68
- data = input.read_nonblock(4096)
88
+ begin
89
+ data = input.read_nonblock(800_000)
90
+ rescue IO::EAGAINWaitReadable, EOFError
91
+ data = ''
92
+ end
69
93
 
70
- lines = data.each_line.to_a
71
94
  last_line = nil
72
- lines.each{|line|
95
+ data.each_line{|line|
73
96
  if line[-1] != "\n"
74
97
  last_line = line
75
98
  break
@@ -86,6 +109,7 @@ class KV_Screen
86
109
  end
87
110
 
88
111
  @lines << setup_line(line)
112
+
89
113
  while !@load_unlimited && @lines.size > self.y + @buffer_lines
90
114
  @yq.pop; @yq.clear
91
115
  end
@@ -95,6 +119,10 @@ class KV_Screen
95
119
  if @filename
96
120
  @file_mtime = File.mtime(@filename)
97
121
  @file_lastpos = input.tell
122
+ elsif @fifo_file
123
+ input = open(@fifo_file)
124
+ log(input)
125
+ redo
98
126
  end
99
127
  input.close
100
128
  @loading = false
@@ -102,7 +130,8 @@ class KV_Screen
102
130
  end
103
131
 
104
132
  def y_max
105
- @lines.size - Curses.lines + 2
133
+ max = @lines.size - Curses.lines + 2
134
+ max < 0 ? 0 : max
106
135
  end
107
136
 
108
137
  def y
@@ -131,6 +160,11 @@ class KV_Screen
131
160
  @rs.x
132
161
  end
133
162
 
163
+ def set_load_unlimited b
164
+ @load_unlimited = b
165
+ @yq << true
166
+ end
167
+
134
168
  def init_screen
135
169
  Curses.init_screen
136
170
  Curses.stdscr.keypad(true)
@@ -141,6 +175,11 @@ class KV_Screen
141
175
  else
142
176
  Curses.mousemask(0)
143
177
  end
178
+
179
+ if @loading && self.y_max < @rs.y
180
+ log [:going, self.y_max, @rs.y]
181
+ @following = :going
182
+ end
144
183
  self.y = @rs.y
145
184
  end
146
185
 
@@ -169,24 +208,12 @@ class KV_Screen
169
208
  end
170
209
  end
171
210
 
172
- def screen_status status, post = nil
173
- Curses.setpos Curses.lines-1, 0
174
- Curses.addstr ' '.ljust(Curses.cols)
175
-
176
- standout{
177
- Curses.setpos Curses.lines-1, 0
178
- Curses.addstr status
179
- }
180
- Curses.addstr post if post
181
- Curses.standend
182
- end
183
-
184
211
  LINE_ATTR = Curses::A_DIM
185
212
 
186
213
  def render_data
187
214
  # check update
188
- c_lines = Curses.lines
189
- c_cols = Curses.cols
215
+ c_lines = @rs.c_lines = Curses.lines
216
+ c_cols = @rs.c_cols = Curses.cols
190
217
 
191
218
  if @rs != @last_rs
192
219
  @last_rs = @rs.dup
@@ -196,6 +223,15 @@ class KV_Screen
196
223
 
197
224
  Curses.clear
198
225
 
226
+ if @rs.separation_mode && (lines = @lines[self.y ... (self.y + c_lines - 1)])
227
+ max_cols = []
228
+ lines.each.with_index{|line, ln|
229
+ line.split("\t").each_with_index{|w, i|
230
+ max_cols[i] = max_cols[i] ? [max_cols[i], w.size].max : w.size
231
+ }
232
+ }
233
+ end
234
+
199
235
  (c_lines-1).times{|i|
200
236
  lno = i + self.y
201
237
  line = @lines[lno]
@@ -229,8 +265,26 @@ class KV_Screen
229
265
  end
230
266
  end
231
267
 
268
+ if @rs.ts_mode && ts = line.instance_variable_get(:@time_stamp)
269
+ cattr LINE_ATTR do
270
+ ts = line.instance_variable_get(:@time_stamp)
271
+ Curses.addstr("#{ts} |")
272
+ end
273
+ end
274
+
232
275
  line = line[self.x, cols] || ''
233
276
 
277
+ if @rs.separation_mode
278
+ line = line.split(/\t/).tap{|e|
279
+ if (max = max_cols.size) > 0
280
+ # fill empty columns
281
+ e[max - 1] ||= nil
282
+ end
283
+ }.map.with_index{|w, i|
284
+ "%-#{max_cols[i]}s" % w
285
+ }.join(' | ')
286
+ end
287
+
234
288
  if !@rs.search || !(Regexp === @rs.search)
235
289
  Curses.addstr line
236
290
  else
@@ -263,11 +317,49 @@ class KV_Screen
263
317
  name = @name ? "<#{@name}>" : ''
264
318
  mouse = @mouse ? ' [MOUSE]' : ''
265
319
  search = @rs.search ? " search[#{search_str}]" : ''
266
- loading = @loading ? " (loading...#{@load_unlimited ? '!' : nil}#{@following_mode ? ' following' : ''}) " : ''
320
+ loading = @loading ? " (loading...#{@load_unlimited ? '!' : nil}#{@following ? ' following' : ''}) " : ''
267
321
  x = self.x > 0 ? " x:#{self.x}" : ''
268
322
  screen_status "#{name} lines:#{self.y+1}/#{@lines.size}#{x}#{loading}#{search}#{mouse}"
269
323
  end
270
324
 
325
+ ANIMATION = ['[O ]',
326
+ '[o. ]',
327
+ '[... ]',
328
+ '[ ... ]',
329
+ '[ ... ]',
330
+ '[ ...]',
331
+ '[ .o]',
332
+ '[ O]',
333
+ '[ .o]',
334
+ '[ ...]',
335
+ '[ ... ]',
336
+ '[ ... ]',
337
+ '[ ... ]',
338
+ '[... ]',
339
+ '[o. ]',
340
+ ]
341
+
342
+ def screen_status status, post = nil
343
+ cols = Curses.cols
344
+ line = Curses.lines-1
345
+ Curses.setpos line, 0
346
+ Curses.addstr ' '.ljust(cols)
347
+ len = status.size
348
+ len += post.size if post
349
+
350
+ standout{
351
+ Curses.setpos Curses.lines-1, 0
352
+ Curses.addstr status
353
+ }
354
+ Curses.addstr post if post
355
+
356
+ if !post && len < cols - ANIMATION.first.size
357
+ Curses.setpos line, cols - ANIMATION.first.size - 1
358
+ @apos = (@apos + 1) % ANIMATION.size
359
+ Curses.addstr ANIMATION[@apos]
360
+ end
361
+ end
362
+
271
363
  def check_update
272
364
  if @loading == false
273
365
  if @filename && File.exist?(@filename) && File.mtime(@filename) > @file_mtime
@@ -288,7 +380,7 @@ class KV_Screen
288
380
  def render_screen
289
381
  ev = nil
290
382
 
291
- ms = @following_mode ? 100 : 500
383
+ ms = @following ? 100 : 500
292
384
 
293
385
  ctimeout ms do
294
386
  while ev == nil
@@ -296,39 +388,62 @@ class KV_Screen
296
388
  render_status
297
389
  ev = Curses.getch
298
390
  check_update
299
- if @following_mode
300
- if @rs.search && search_next_move(self.y + 1)
301
- break
391
+ y_max = self.y_max
392
+
393
+ if @following
394
+ case @following
395
+ when :searching
396
+ break if search_next_move
397
+ when :going
398
+ if @rs.goto <= y_max
399
+ self.y = @rs.goto
400
+ break
401
+ end
402
+ when true
403
+ # ok
404
+ else
405
+ raise "unknown following mode: #{@following}"
302
406
  end
303
- self.y = self.y_max
407
+
408
+ self.y = y_max
304
409
  end
305
410
  end
306
411
 
307
- if @following_mode
308
- @following_mode = false
309
- @load_unlimited = false
310
- end
412
+ @following = false
413
+ set_load_unlimited false
311
414
 
312
415
  return ev
313
416
  end
314
417
  end
315
418
 
316
- def search_next_move start
317
- (start...@lines.size).each{|i|
419
+ def search_next_move
420
+ last_line = @lines.size
421
+ # log (@searching..last_line)
422
+
423
+ (@searching...last_line).each{|i|
318
424
  if @rs.search === @lines[i]
319
425
  self.y = i
426
+ @searching = false
320
427
  return true
321
428
  end
322
429
  }
430
+ @searching = last_line
323
431
  return false
324
432
  end
325
433
 
326
434
  def search_next start
327
- if search_next_move start
328
- # OK
435
+ @searching = start
436
+ if search_next_move
437
+ # OK. self.y is updated.
329
438
  else
330
- screen_status "not found: [#{self.search_str}]"
331
- pause
439
+ if @loading
440
+ set_load_unlimited true
441
+ @following = :searching
442
+ else
443
+ screen_status "not found: [#{self.search_str}]"
444
+ pause
445
+ @searching = false
446
+ end
332
447
  end
333
448
  end
334
449
 
@@ -350,26 +465,32 @@ class KV_Screen
350
465
  ev
351
466
  end
352
467
 
353
- def input_str pattern, str = ''.dup, other_actions: nil
354
- loop{
355
- ev = Curses.getch
468
+ def input_str pattern, str = ''.dup, other_actions: {}
469
+ update_action = other_actions[:update]
356
470
 
357
- case ev
358
- when 10
359
- return str
360
- when Curses::KEY_BACKSPACE
361
- str.chop!
362
- when pattern
363
- str << ev
364
- else
365
- if other_actions && (action = other_actions[ev])
366
- action.call(ev)
471
+ ctimeout update_action ? 200 : -1 do
472
+ loop do
473
+ ev = Curses.getch
474
+
475
+ case ev
476
+ when 10
477
+ return str
478
+ when Curses::KEY_BACKSPACE
479
+ str.chop!
480
+ when pattern
481
+ str << ev
482
+ when nil # timeout
483
+ update_action[str]
367
484
  else
368
- log "failure: #{key_name ev}"
369
- return nil
485
+ if action = other_actions[ev]
486
+ action.call(ev)
487
+ else
488
+ log "failure: #{key_name ev}"
489
+ return nil
490
+ end
370
491
  end
371
492
  end
372
- }
493
+ end
373
494
  end
374
495
 
375
496
  def pause
@@ -382,7 +503,7 @@ class KV_Screen
382
503
 
383
504
  case ev
384
505
  when 'q'
385
- raise KV_PopScreen
506
+ raise PopScreen
386
507
 
387
508
  when Curses::KEY_UP, 'k'
388
509
  self.y -= 1
@@ -412,13 +533,11 @@ class KV_Screen
412
533
  end
413
534
 
414
535
  when 'F'
415
- @following_mode = true
416
- @load_unlimited = true
417
- @yq << true
536
+ @following = true
537
+ set_load_unlimited true
418
538
 
419
539
  when 'L'
420
- @load_unlimited = !@load_unlimited
421
- @yq << true
540
+ set_load_unlimited !@load_unlimited
422
541
 
423
542
  when '/'
424
543
  search_str = ''.dup
@@ -470,8 +589,8 @@ class KV_Screen
470
589
  filter_mode_title = "*filter mode [#{self.search_str}]*"
471
590
  if @name != filter_mode_title
472
591
  lines = @lines.grep(@rs.search)
473
- fscr = KV_Screen.new nil, lines: lines, search: @rs.search, name: filter_mode_title
474
- raise KV_PushScreen.new(fscr)
592
+ fscr = Screen.new nil, lines: lines, search: @rs.search, name: filter_mode_title
593
+ raise PushScreen.new(fscr)
475
594
  end
476
595
  end
477
596
 
@@ -498,10 +617,34 @@ class KV_Screen
498
617
 
499
618
  when 'v'
500
619
  if @filename
501
- system("vi #{@filename} +#{self.y + 1}")
620
+ syste m("vi #{@filename} +#{self.y + 1}")
502
621
  @last_rs = nil
503
622
  end
504
623
 
624
+ when 'P'
625
+ begin
626
+ if v = `gist -v` and /^gist v\d/ =~ v
627
+ screen_status "gist-ing..."
628
+
629
+ url = IO.popen('gist -p', 'a+'){|rw|
630
+ @lines.each{|line| rw.puts line}
631
+ rw.close_write
632
+ rw.read
633
+ }
634
+ msg = "gist URL: #{url}"
635
+ at_exit{
636
+ puts msg
637
+ }
638
+ screen_status msg
639
+ pause
640
+ else
641
+ raise v.inspect
642
+ end
643
+ rescue Errno::ENOENT
644
+ screen_status 'gist command is not found'
645
+ pause
646
+ end
647
+
505
648
  when 'm'
506
649
  @mouse = !@mouse
507
650
  Curses.close_screen
@@ -514,16 +657,52 @@ class KV_Screen
514
657
 
515
658
  when 'N'
516
659
  @rs.line_mode = !@rs.line_mode
660
+ when 'T'
661
+ @rs.ts_mode = !@rs.ts_mode if @time_stamp
662
+ when 'S'
663
+ @rs.separation_mode = !@rs.separation_mode
517
664
  when 't'
518
665
  Curses.close_screen
519
666
  @mode = :terminal
667
+ when 'x'
668
+ while @ext_input && !@ext_input.closed?
669
+ update_ext_status = -> str do
670
+ screen_status "input for ext:", str
671
+ end
672
+ update_ext_status['']
673
+ actions = {
674
+ update: -> str do
675
+ self.y = self.y_max
676
+ render_data
677
+ update_ext_status[str]
678
+ end
679
+ }
680
+ str = input_str(/./, other_actions: actions)
681
+ if str && !str.empty?
682
+ @ext_input.puts str unless @ext_input.closed?
683
+ else
684
+ break
685
+ end
686
+ end
687
+
688
+ when 'H'
689
+ if @meta
690
+ lines = @meta.map{|k, v| "#{k}: #{v}"}
691
+ raise PushScreen.new(Screen.new nil, lines: lines, name: "Response header [#{@name}]")
692
+ end
693
+
694
+ when Curses::KEY_CTRL_G
695
+ # do nothing
520
696
 
521
697
  when '?'
522
- raise KV_PushScreen.new(KV_Screen.new help_io)
698
+ raise PushScreen.new(Screen.new help_io)
523
699
 
524
700
  when nil
525
701
  # ignore
526
702
 
703
+ when Curses::KEY_RESIZE
704
+ # ignore
705
+
527
706
  else
528
707
  screen_status "unknown: #{key_name(ev)}"
529
708
  pause
@@ -548,6 +727,10 @@ class KV_Screen
548
727
  raise
549
728
  end
550
729
  end
730
+
731
+ def redraw!
732
+ @last_rs = nil
733
+ end
551
734
  end
552
735
 
553
736
  class KV
@@ -559,11 +742,39 @@ class KV
559
742
  }
560
743
 
561
744
  files = parse_option(argv)
745
+ name = files.shift
562
746
 
563
747
  @pipe_in = nil
564
748
 
565
- if files.empty?
566
- if STDIN.isatty
749
+ if @opts[:pipe] || (name && File.pipe?(name))
750
+ @opts.delete(:pipe)
751
+ @opts[:fifo_file] = name || '/tmp/kv_pipe'
752
+
753
+ if name && File.pipe?(name)
754
+ # ok
755
+ else
756
+ begin
757
+ name ||= File.expand_path('~/.kv_pipe')
758
+ unlink_name = name
759
+ File.mkfifo(name)
760
+ at_exit{ puts "$ rm #{unlink_name}"; File.unlink(unlink_name) }
761
+ rescue Errno::EEXIST
762
+ raise "#{name} already exists."
763
+ end
764
+ end
765
+
766
+ puts "waiting for #{name}"
767
+ input = @pipe_in = open(name)
768
+ name = nil
769
+ elsif !name
770
+ case
771
+ when @opts[:e]
772
+ cmd = @opts.delete(:e)
773
+ input = IO.popen(cmd, 'a+')
774
+ name = nil
775
+ @pipe_in = input
776
+ @opts[:ext_input] = input
777
+ when STDIN.isatty
567
778
  input = help_io
568
779
  name = 'HELP'
569
780
  else
@@ -573,16 +784,20 @@ class KV
573
784
  @pipe_in = input
574
785
  end
575
786
  else
576
- name = files.shift
577
787
  begin
578
788
  input = open(name)
579
- rescue
580
- if /(.+):(\d+)/ =~ name
789
+ rescue Errno::ENOENT
790
+ case name
791
+ when /(.+):(\d+)/
581
792
  name = $1
582
- @first_line = $2.to_i - 1
793
+ @opts[:first_line] = $2.to_i - 1
583
794
  retry
795
+ when URI.regexp
796
+ input = URI.open(name)
797
+ else
798
+ STDERR.puts "#{name}: No such file or directory"
799
+ exit 1
584
800
  end
585
- raise
586
801
  end
587
802
  end
588
803
 
@@ -590,7 +805,7 @@ class KV
590
805
  log "SIGINT"
591
806
  }
592
807
 
593
- @screens = [KV_Screen.new(input, name: name, **@opts)]
808
+ @screens = [Screen.new(input, name: name, **@opts)]
594
809
  end
595
810
 
596
811
  def parse_option argv
@@ -604,6 +819,18 @@ class KV
604
819
  opts.on('-N', 'Show lines'){
605
820
  @opts[:line_mode] = true
606
821
  }
822
+ opts.on('-T', '--time-stamp', 'Enable time stamp'){
823
+ @opts[:time_stamp] = true
824
+ }
825
+ opts.on('-e CMD', 'Run CMD as a child process'){|cmd|
826
+ @opts[:e] = cmd
827
+ }
828
+ opts.on('-p', '--pipe', 'Open named pipe'){
829
+ @opts[:pipe] = true
830
+ }
831
+ opts.on('-s', 'Separation mode (tsv)'){
832
+ @opts[:separation_mode] = true
833
+ }
607
834
  opts.parse!(argv)
608
835
  end
609
836
 
@@ -612,10 +839,12 @@ class KV
612
839
  until @screens.empty?
613
840
  begin
614
841
  @screens.last.control
615
- rescue KV_PopScreen
842
+ rescue PopScreen
616
843
  @screens.pop
617
- rescue KV_PushScreen => e
844
+ @screens.last.redraw!
845
+ rescue PushScreen => e
618
846
  @screens.push e.screen
847
+ @screens.last.redraw!
619
848
  end
620
849
  end
621
850
  ensure
@@ -1,3 +1,3 @@
1
- module KV
2
- VERSION = "0.2.0"
3
- end
1
+ module KV
2
+ VERSION = "0.7.0"
3
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kv
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Koichi Sasada
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-02-08 00:00:00.000000000 Z
11
+ date: 2020-08-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: curses
@@ -32,6 +32,7 @@ executables:
32
32
  extensions: []
33
33
  extra_rdoc_files: []
34
34
  files:
35
+ - ".github/FUNDING.yml"
35
36
  - ".gitignore"
36
37
  - LICENSE
37
38
  - README.md
@@ -61,7 +62,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
61
62
  - !ruby/object:Gem::Version
62
63
  version: '0'
63
64
  requirements: []
64
- rubygems_version: 3.2.0.pre1
65
+ rubygems_version: 3.1.2
65
66
  signing_key:
66
67
  specification_version: 4
67
68
  summary: 'kv: A page viewer written by Ruby'