kv 0.6.0 → 0.9.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: 70b1f3af205a0cc4e0654de74a8d9e31e023719c8cf04cd6fbb9e43d96b14be4
4
- data.tar.gz: 5265f5930278a1f39f5d00f6a6f3265e436bcdce233b7350f8f791d7f0752fee
3
+ metadata.gz: 510d5e2565cf1d662da48e3c4af89799375377b594469132319f5475ff53b8ce
4
+ data.tar.gz: '09136cab7d1f49371444949e563d5ec58225881b6ab7f781711314ea176f4401'
5
5
  SHA512:
6
- metadata.gz: 935613e6eb8be95f504d75b777b83a864bab18a34ccbdc4694df5e82c8b2312d270e9f4f4f5da7ef07ed360cc083281705b61ff62a329aa7004da289e989909f
7
- data.tar.gz: 7fb6b11b84f0c014c956cf0f0e223a74ce88426860f65919ef2e351028b957876c72a255fba10c2ed2e65dac0dbf701691cf10817745f7ec231a42de76ff7ed4
6
+ metadata.gz: e3e76a17edc990f59d1a999cb16d75619852503beafd05c9009c3efb697ccd2712203eeec6e6627614e71cce676f516972e17384588ecc9a24bd0f4acb8c2ae5
7
+ data.tar.gz: ad6c7de4f61931c05a867554ae47998d0f19f72548fbf76cfb3336fdebca7b06f111e828b17ac21011dd95defa5adb588d70c157b9043b3b897ad612fda7f4b3
@@ -0,0 +1,3 @@
1
+ # These are supported funding model platforms
2
+
3
+ github: [ko1]
data/exe/kv CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  begin
4
4
  require 'kv'
5
- rescue LoadError
5
+ rescue
6
6
  $:.unshift File.join(__dir__, '../lib')
7
7
  require 'kv'
8
8
  end
data/lib/kv/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module KV
2
- VERSION = "0.6.0"
2
+ VERSION = "0.9.0"
3
3
  end
data/lib/kv.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "kv/version"
3
+ require_relative "kv/version"
4
4
  require "curses"
5
5
  require 'stringio'
6
6
  require 'optparse'
@@ -20,7 +20,8 @@ end
20
20
  class Screen
21
21
  RenderStatus = Struct.new(
22
22
  :c_cols, :c_lines, :x, :y, :last_lineno,
23
- :search, :goto, :line_mode, :ts_mode, :wrapping,
23
+ :search, :goto, :wrapping,
24
+ :line_mode, :ts_mode, :separation_mode,
24
25
  )
25
26
  class RenderStatus
26
27
  def to_s
@@ -29,9 +30,18 @@ class Screen
29
30
  end
30
31
 
31
32
  def initialize input, lines: [],
32
- name: nil, search: nil, first_line: 0,
33
- following_mode: false, line_mode: false, separation_mode: false,
34
- time_stamp: nil, ext_input: nil, fifo_file: nil
33
+ name: nil,
34
+ search: nil,
35
+ first_line: 0,
36
+ following_mode: false,
37
+ line_mode: false,
38
+ separation_mode: false,
39
+ time_stamp: nil,
40
+ ext_input: nil,
41
+ fifo_file: nil,
42
+ watch: false,
43
+ filter_command: nil
44
+
35
45
  @rs = RenderStatus.new
36
46
  @last_rs = nil
37
47
  @rs.y = first_line
@@ -42,18 +52,21 @@ class Screen
42
52
  @rs.search = search
43
53
  @rs.wrapping = false
44
54
  @rs.ts_mode = false
55
+ @rs.separation_mode = separation_mode
45
56
 
46
57
  @name = name
47
58
  @filename = @name if @name && File.exist?(@name)
59
+ @filter_command = @filename && filter_command
48
60
 
49
61
  @time_stamp = time_stamp
50
62
  @ext_input = ext_input
51
63
  @fifo_file = fifo_file
52
- @separation_mode = separation_mode
53
64
 
54
65
  @lines = lines
55
66
  @mode = :screen
56
67
 
68
+ @watch_mode = watch
69
+
57
70
  @following = following_mode
58
71
  @apos = 0
59
72
 
@@ -70,11 +83,23 @@ class Screen
70
83
  end
71
84
 
72
85
  @prev_render = {}
86
+ input = open_file if @filename
73
87
  @meta = input.respond_to?(:meta) ? input.meta : nil
74
-
75
88
  read_async input if input
76
89
  end
77
90
 
91
+ def open_file
92
+ input = open(@filename)
93
+ @rs.last_lineno = 0
94
+
95
+ if @filter_command
96
+ io = IO.popen("#{@filter_command} #{@filename}", err: '/dev/null')
97
+ # io.close_write
98
+ input = io
99
+ end
100
+ input
101
+ end
102
+
78
103
  def setup_line line
79
104
  line = line.chomp
80
105
  line.instance_variable_set(:@time_stamp, Time.now.strftime('%H:%M:%S')) if @time_stamp
@@ -117,7 +142,7 @@ class Screen
117
142
  ensure
118
143
  if @filename
119
144
  @file_mtime = File.mtime(@filename)
120
- @file_lastpos = input.tell
145
+ @file_lastpos = input.tell unless @filter_command
121
146
  elsif @fifo_file
122
147
  input = open(@fifo_file)
123
148
  log(input)
@@ -184,9 +209,9 @@ class Screen
184
209
 
185
210
 
186
211
  def standout
187
- Curses.standout
188
- yield
189
- Curses.standend
212
+ cattr Curses::A_STANDOUT do
213
+ yield
214
+ end
190
215
  end
191
216
 
192
217
  def cattr attr
@@ -222,11 +247,11 @@ class Screen
222
247
 
223
248
  Curses.clear
224
249
 
225
- if @separation_mode && (lines = @lines[self.y ... (self.y + c_lines - 1)])
226
- max_cols = []
250
+ if @rs.separation_mode && (lines = @lines[self.y ... (self.y + c_lines - 1)])
251
+ @max_cols = [] unless defined? @max_cols
227
252
  lines.each.with_index{|line, ln|
228
253
  line.split("\t").each_with_index{|w, i|
229
- max_cols[i] = max_cols[i] ? [max_cols[i], w.size].max : w.size
254
+ @max_cols[i] = @max_cols[i] ? [@max_cols[i], w.size].max : w.size
230
255
  }
231
256
  }
232
257
  end
@@ -273,29 +298,32 @@ class Screen
273
298
 
274
299
  line = line[self.x, cols] || ''
275
300
 
276
- if @separation_mode
301
+ if @rs.separation_mode
277
302
  line = line.split(/\t/).tap{|e|
278
- if (max = max_cols.size) > 0
303
+ if (max = @max_cols.size) > 0
279
304
  # fill empty columns
280
305
  e[max - 1] ||= nil
281
306
  end
282
307
  }.map.with_index{|w, i|
283
- "%-#{max_cols[i]}s" % w
308
+ "%-#{@max_cols[i]}s" % w
284
309
  }.join(' | ')
285
310
  end
286
311
 
287
- if !@rs.search || !(Regexp === @rs.search)
312
+ if !@rs.search || !(Regexp === @rs.search) ||
313
+ (parts = search_partition(line, @rs.search)).is_a?(String)
288
314
  Curses.addstr line
289
315
  else
290
- partition(line, @rs.search).each{|(matched, str)|
291
- if matched == :match
292
- standout{
316
+ cattr Curses::A_UNDERLINE do
317
+ parts.each{|(matched, str)|
318
+ if matched == :match
319
+ standout{
320
+ Curses.addstr str
321
+ }
322
+ else
293
323
  Curses.addstr str
294
- }
295
- else
296
- Curses.addstr str
297
- end
298
- }
324
+ end
325
+ }
326
+ end
299
327
  end
300
328
  }
301
329
  end
@@ -361,17 +389,25 @@ class Screen
361
389
 
362
390
  def check_update
363
391
  if @loading == false
364
- if @filename && File.exist?(@filename) && File.mtime(@filename) > @file_mtime
365
- input = open(@filename)
392
+ if @filename && File.mtime(@filename) > @file_mtime
393
+ screen_status "#{@filename} is updated."
366
394
 
367
- if input.size < @file_lastpos
368
- screen_status "#{@filename} is truncated. Rewinded."
369
- pause
370
- @lineno = 0
395
+ if @watch_mode
396
+ @lines = []
397
+ input = open_file
398
+ read_async input
371
399
  else
372
- input.seek @file_lastpos
400
+ input = open(@filename)
401
+
402
+ if input.size < @file_lastpos
403
+ screen_status "#{@filename} is truncated. Rewinded."
404
+ pause
405
+ @lineno = 0
406
+ else
407
+ input.seek @file_lastpos
408
+ end
409
+ read_async input
373
410
  end
374
- read_async input
375
411
  end
376
412
  end
377
413
  end
@@ -658,6 +694,9 @@ class Screen
658
694
  @rs.line_mode = !@rs.line_mode
659
695
  when 'T'
660
696
  @rs.ts_mode = !@rs.ts_mode if @time_stamp
697
+ when 'S'
698
+ @rs.separation_mode = !@rs.separation_mode
699
+ @max_cols = []
661
700
  when 't'
662
701
  Curses.close_screen
663
702
  @mode = :terminal
@@ -828,6 +867,12 @@ class KV
828
867
  opts.on('-s', 'Separation mode (tsv)'){
829
868
  @opts[:separation_mode] = true
830
869
  }
870
+ opts.on('-w', 'Watch mode: Reload on file changed'){
871
+ @opts[:watch] = true
872
+ }
873
+ opts.on('--filter-command=FILTER_COMMAND', 'Apply filter command'){|cmd|
874
+ @opts[:filter_command] = cmd
875
+ }
831
876
  opts.parse!(argv)
832
877
  end
833
878
 
@@ -838,7 +883,7 @@ class KV
838
883
  @screens.last.control
839
884
  rescue PopScreen
840
885
  @screens.pop
841
- @screens.last.redraw!
886
+ @screens.last.redraw! unless @screens.empty?
842
887
  rescue PushScreen => e
843
888
  @screens.push e.screen
844
889
  @screens.last.redraw!
@@ -861,18 +906,23 @@ def log obj, prefix = ''
861
906
  end
862
907
  end
863
908
 
864
- def partition str, search
909
+ def search_partition str, search
865
910
  results = []
866
911
  loop{
867
912
  r = str.match(search){|m|
868
913
  break if m.post_match == str
869
- results << [:unmatch, m.pre_match]
914
+ results << [:unmatch, m.pre_match] unless m.pre_match.empty?
870
915
  results << [:match, m.to_s]
871
916
  str = m.post_match
872
917
  }
873
918
  break unless r
874
919
  }
875
- results << [:unmatch, str]
920
+ if results.empty?
921
+ str
922
+ else
923
+ results << [:unmatch, str] unless str.empty?
924
+ results
925
+ end
876
926
  end
877
927
 
878
928
  def help_io
@@ -888,5 +938,5 @@ def help_io
888
938
  end
889
939
  }
890
940
 
891
- help_io = StringIO.new(help.join)
941
+ StringIO.new(help.join)
892
942
  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.6.0
4
+ version: 0.9.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-06-19 00:00:00.000000000 Z
11
+ date: 2022-05-26 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,8 +62,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
61
62
  - !ruby/object:Gem::Version
62
63
  version: '0'
63
64
  requirements: []
64
- rubyforge_project:
65
- rubygems_version: 2.7.6
65
+ rubygems_version: 3.1.6
66
66
  signing_key:
67
67
  specification_version: 4
68
68
  summary: 'kv: A page viewer written by Ruby'