listpager 1.0.2 → 1.0.3

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
  SHA1:
3
- metadata.gz: 0d4f836e524e3a80691d2a2a0212b3e447d683c7
4
- data.tar.gz: 4d68a1eee960c026cfbcbaa24b3b9f7378218e26
3
+ metadata.gz: 1cb09a07756c07b56bc85e800cc44c160c164c0e
4
+ data.tar.gz: ccfa85c999c3b235699461e3ef78dd9e428c9a16
5
5
  SHA512:
6
- metadata.gz: c2942ab1c84e13c509b4958b6002604f81c3ee7ee8708eeb3a6e6dce0e0286ff2df89b5a3d60463535d4c7941b0052c4755519452b394d3bf87095c3ef101d29
7
- data.tar.gz: 8789bc607ee28fdf54d6018144c18df4583e61fd4c250739f46e7209e25cf638371e5ec7cb1f5ffca89f8b79df0aff660d926da9112fb0a8bea78a6b1b088f3f
6
+ metadata.gz: 7d83d8ee3ed4476a2e19e1b11a75a5233d8bd215994481a559a455bc055903355b1baa6b9f83d2d8cfe2d82d48a5e21b0e435b016d50cb7e3148da704ba3acc2
7
+ data.tar.gz: 218bbe3375248ba86926f6a9244e2457acbd93e77c747c2bcf2498ee513a11dbcd686381aa95d006e0eff617dad24876c6096351b04a5d54848d60708123bb65
data/README.md CHANGED
@@ -28,9 +28,7 @@ listpager.sync = true
28
28
  listpager.puts "Item #{i}"
29
29
  end
30
30
 
31
- # Enter command mode.
32
- listpager.puts "%%"
33
- listpager.puts "select 35"
31
+ listpager.puts "%set-selected 35"
34
32
  ```
35
33
 
36
34
  If you want to play with the protocol, it's easiest to use two terminals and
@@ -48,28 +46,20 @@ And a "client", like:
48
46
  socat TCP:localhost:4500 -
49
47
  ```
50
48
 
51
- Add some items on your keyboard, then enter `%%` to enter command mode. Another
52
- `%%` will put you back in command mode. If you need a literal `%%` list item,
53
- escape it with `\%%`. If you need a literal `\\%%`, you're out of luck, because
54
- complete escaping isn't available yet.
49
+ Add some items on your keyboard, then enter some commands, prefixed by `%`. If
50
+ you need an item that starts with a liter `%`, start it with `%%`.
55
51
 
56
52
  There are a lot of obvious things the protocol could do, that it doesn't
57
- currently. It's way low-hanging fruit for any contributors (`clear`, `rename`,
58
- `move`, etc.)
53
+ currently. It's way low-hanging fruit for any contributors.
59
54
 
60
55
  ## Protocol
61
56
  listpager reads each item from stdin, and it becomes a list item. As the user
62
57
  arrows through the list, it outputs messages like:
63
58
 
64
- `select 21 apples` where `21` is the index into the list, and `abacate` is the
65
- caption. Any other keys pressed on an item are written out like
59
+ `is-selected 21 apples` where `21` is the index into the list, and `apples` is
60
+ the caption. Any other keys pressed on an item are written out like
66
61
  `keypress enter apples`.
67
62
 
68
- listpager stops considering input bulk list items once it sees: `%%`, where it
69
- enters command mode. Currently, command mode does nothing, but in the future,
70
- it will allow the calling program to instruct listpager to select certain items,
71
- ask for statuses, manipulate the list, add badges, change captions, etc.
72
-
73
63
 
74
64
  ## Dependencies and Installation
75
65
  Install listpager with `gem install listpager`. It has few dependencies:
@@ -83,7 +73,7 @@ sudo apt install libncursesw5-dev
83
73
 
84
74
  ## Implementation Notes
85
75
  curses is terrible but portable. 'curses' doesn't expose enough to be useful,
86
- 'ncurses-ruby' is about as good as you'll do in Ruby.
76
+ 'ncursesw' is about as good as you'll do in Ruby.
87
77
 
88
78
 
89
79
  ## Upcoming Features
@@ -96,6 +86,7 @@ be more functional, I'd like to add a few features:
96
86
  * Mouse support, with scroll wheels.
97
87
  * Checkboxes
98
88
  * Extend command mode
89
+ * `Listpager::Client`
99
90
 
100
91
 
101
92
  ## Contributing
@@ -11,11 +11,13 @@ module Listpager
11
11
  attr_reader :tty
12
12
  attr_reader :self_pipe
13
13
  attr_reader :list
14
- attr_reader :mode
14
+
15
+ attr_reader :locked
15
16
 
16
17
  def initialize
17
18
  @tty = File.open('/dev/tty', 'r+')
18
19
  @self_pipe = IO.pipe
20
+ @locked = false
19
21
 
20
22
  [@tty, *self_pipe].each do |io|
21
23
  io.sync = true
@@ -24,8 +26,35 @@ module Listpager
24
26
  initialize_curses
25
27
 
26
28
  @list = List.new(Ncurses.stdscr)
27
- @mode = :append
29
+ connect_list
30
+
28
31
  @buffer = ''
32
+ @locked_buffer = []
33
+ end
34
+
35
+ def key_name(v)
36
+ @m ||= {
37
+ 27 => 'esc',
38
+ 10 => 'enter',
39
+ 260 => 'left',
40
+ 261 => 'right',
41
+ 127 => 'backspace',
42
+ 330 => 'delete',
43
+ ' ' => 'space',
44
+ }
45
+ @m[v] || (v < 255 && v.chr.match(/[[:print:]]/) ? v.chr : "\##{v}")
46
+ end
47
+
48
+ def connect_list
49
+ cterm = self
50
+ list.define_singleton_method :on_select_change do
51
+ cterm.cmd!('is-selected', selected, selected_value, observe_lock: true)
52
+ end
53
+
54
+ list.define_singleton_method :on_key_press do |k|
55
+ cterm.cmd!('key-pressed', cterm.key_name(k),
56
+ selected, selected_value, observe_lock: true)
57
+ end
29
58
  end
30
59
 
31
60
  def initialize_curses
@@ -50,45 +79,77 @@ module Listpager
50
79
  @tty.close
51
80
  end
52
81
 
53
- def append_mode?
54
- @mode == :append
82
+ def line!(line, observe_lock: false)
83
+ if observe_lock && @locked
84
+ @locked_buffer.push(line)
85
+ else
86
+ $stdout.puts line
87
+ $stdout.flush
88
+ end
89
+ end
90
+
91
+ def cmd!(*args, observe_lock: false)
92
+ line!('%' + Shellwords.join(args.map(&:to_s)),
93
+ observe_lock: observe_lock)
55
94
  end
56
95
 
57
96
  def process_command(argv)
58
97
  cmd, *args = argv
59
98
  case cmd
60
- when 'append-mode', '%'
61
- @mode = :append
62
- when 'title'
63
- @list.title = args[0]
99
+ # TODO: This to be refactored into CommandProcessor
100
+ when 'quit'
101
+ raise Interrupt
102
+
64
103
  when 'clear'
65
- @list.values = []
66
- @list.selected = 0
104
+ list.values = []
105
+ list.selected = 0
106
+ list.dirty!
107
+
108
+ when 'append'
109
+ list.values.push(args.fetch(0))
67
110
  list.dirty!
111
+
112
+ when 'lock'
113
+ @locked = true
114
+ cmd! 'lock'
115
+
116
+ when 'unlock'
117
+ @locked = false
118
+ cmd! 'unlock'
119
+ @locked_buffer.each do |line|
120
+ line!(line)
121
+ end
122
+ @locked_buffer = []
123
+
124
+ when 'get-title'
125
+ cmd! 'title-is', @list.title
126
+ when 'set-title'
127
+ @list.title = args[0]
128
+ cmd! 'title-is', @list.title
129
+
68
130
  when 'get-selected'
69
- list.selection_changed
70
- when 'select'
131
+ cmd! 'selected-is', list.selected, list.selected_value
132
+ when 'set-selected'
71
133
  list.selected = args.fetch(0).to_i
134
+ cmd! 'seleted-is', list.selected, list.selected_value
135
+
72
136
  when 'get-item'
73
- puts ["item", args.fetch(0), list.values[args.fetch(0).to_i]].join ' '
74
- when 'quit'
75
- raise Interrupt
137
+ cmd! 'item-is', args.fetch(0), list.values[args.fetch(0).to_i]
138
+ when 'set-item'
139
+ cmd! 'item-is'
76
140
  end
77
141
  end
78
142
 
79
143
  def process_line(line)
80
- if append_mode?
81
- if line == '%%'
82
- @mode = :command
83
- elsif line[0] == '%'
84
- cmd = Shellwords.split(line[1..-1])
85
- process_command(cmd)
86
- else
87
- list.values.push(line)
88
- list.dirty!
89
- end
144
+ if line[0] == '%' && line[1] != '%'
145
+ cmd = Shellwords.split(line[1..-1])
146
+ process_command(cmd)
90
147
  else
91
- process_command(Shellwords.split(line))
148
+ if line[0] == '%'
149
+ line = line[1..-1]
150
+ end
151
+ list.values.push(line)
152
+ list.dirty!
92
153
  end
93
154
  end
94
155
 
@@ -14,11 +14,9 @@ module Listpager
14
14
  BLANK_SPACE = ' '
15
15
 
16
16
  def on_select_change
17
- puts "select #{selected} #{values[selected]}"
18
17
  end
19
18
 
20
19
  def on_key_press(k)
21
- puts "keypress #{key_name(k)} #{selected} #{values[selected]}"
22
20
  end
23
21
 
24
22
  attr_reader :window
@@ -72,25 +70,18 @@ module Listpager
72
70
 
73
71
  if v != @selected
74
72
  dirty!
73
+ @selected = v
75
74
  on_select_change
76
75
  end
77
76
 
78
- return (@selected = v)
77
+ return @selected
79
78
  end
80
79
 
81
- def key_name(v)
82
- @m ||= {
83
- 27 => 'esc',
84
- 10 => 'enter',
85
- 260 => 'left',
86
- 261 => 'right',
87
- 127 => 'backspace',
88
- 330 => 'delete',
89
- ' ' => 'space',
90
- }
91
- @m[v] || (v < 255 && v.chr.match(/[[:print:]]/) ? v.chr : "\##{v}")
80
+ def selected_value
81
+ values[selected]
92
82
  end
93
83
 
84
+
94
85
  def key_input(value)
95
86
  maxx, maxy = getmaxxy
96
87
 
@@ -1,3 +1,3 @@
1
1
  module Listpager
2
- VERSION = "1.0.2"
2
+ VERSION = "1.0.3"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: listpager
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.2
4
+ version: 1.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Owens