tty-pager 0.12.1 → 0.13.0

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: f8dcb93333dbebd8cc1f528d51a3c4e28e39a90840d24b0e85bef6ba99dbee65
4
- data.tar.gz: 6b874380df90294f03af9dc7a6c68c078bfcd4a078f31da6a6379fc3b15f8b88
3
+ metadata.gz: adbdf02c80e21f7b2c2fc7723af3a00d268c8a57bffd321e8ed5126e6b7cc120
4
+ data.tar.gz: 4ff28aeef0acff9e54343e498e890bb2ffde576b771b4172326ef3dcdda67fc3
5
5
  SHA512:
6
- metadata.gz: b5e6eae2130ce1d007d86d76c9dac6fa8a023e8d1c9148a5bab0690d65cbcc205d1c6ace4bd4e8053bb25f63875fe24f2c22a926cfeb5fc11571f0ae5ba3e226
7
- data.tar.gz: d89926ee6548e078c7036cdb22f2bd398011e8f88b422433db7835e777ac939111fc6ffcfc14247b4376754f2a84ddcb003878ad1ecddd424e8a54de56264449
6
+ metadata.gz: 5614a278d417950a369489d6480203150da012ea19c1d2e1c564ac989d3f3c32074ce5f7ae61952536ec758f7602512415b63027f891e73b4d96151a6e9b02e4
7
+ data.tar.gz: ec0c2b331343284877e199e1f1672776e967f58f58b1b608ae73653f84905c6214b30990bb928b3f912f1d345dfce42dcfcc5947fd1fdd4f13330705844accaa
@@ -1,5 +1,27 @@
1
1
  # Change log
2
2
 
3
+ ## [v0.13.0] - 2020-05-30
4
+
5
+ ### Added
6
+ * Add support for streaming by Andrew Radev(@AndrewRadev)
7
+ * Add SystemPager integration tests by Andrew Radev(@AndrewRadev)
8
+
9
+ ### Changed
10
+ * Change Pager structure and extract TTY::Pager::Abstract for the null, basic and
11
+ system pagers
12
+ * Change BasicPager paging prompt to return only formatted prompt text and
13
+ account for terminal height
14
+ * Change BasicPager to quit with a single keystroke
15
+ * Change BasicPager internals to increase readability
16
+ * Change SystemPager#command_exist? to search path
17
+ * Change tests structure for ease of maintenance by Andrew Radev(@AndrewRadev)
18
+ * Change gemspec to add metadata, remove test artefacts and dev dependencies
19
+ * Update strings & tty-screen dependencies
20
+ * Remove tty-which dependency
21
+
22
+ ### Fixed
23
+ * Fix SystemPager to run command test silently via Open3 and thus work on JRuby
24
+
3
25
  ## [v0.12.1] - 2019-03-16
4
26
 
5
27
  ### Fixed
@@ -106,6 +128,8 @@
106
128
 
107
129
  * Initial release
108
130
 
131
+ [v0.13.0]: https://github.com/piotrmurach/tty-pager/compare/v0.12.1...v0.13.0
132
+ [v0.12.1]: https://github.com/piotrmurach/tty-pager/compare/v0.12.0...v0.12.1
109
133
  [v0.12.0]: https://github.com/piotrmurach/tty-pager/compare/v0.11.0...v0.12.0
110
134
  [v0.11.0]: https://github.com/piotrmurach/tty-pager/compare/v0.10.0...v0.11.0
111
135
  [v0.10.0]: https://github.com/piotrmurach/tty-pager/compare/v0.9.0...v0.10.0
data/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  <div align="center">
2
- <a href="https://piotrmurach.github.io/tty" target="_blank"><img width="130" src="https://cdn.rawgit.com/piotrmurach/tty/master/images/tty.png" alt="tty logo" /></a>
2
+ <a href="https://piotrmurach.github.io/tty" target="_blank"><img width="130" src="https://github.com/piotrmurach/tty/raw/master/images/tty.png" alt="tty logo" /></a>
3
3
  </div>
4
4
 
5
5
  # TTY::Pager [![Gitter](https://badges.gitter.im/Join%20Chat.svg)][gitter]
@@ -19,9 +19,9 @@
19
19
  [coverage]: https://coveralls.io/github/piotrmurach/tty-pager
20
20
  [inchpages]: http://inch-ci.org/github/piotrmurach/tty-pager
21
21
 
22
- > Terminal output paging in a cross-platform way supporting all major ruby interpreters.
22
+ > A cross-platform terminal pager that works on all major Ruby interpreters.
23
23
 
24
- **TTY::Pager** provides independent terminal output paging component for [TTY](https://github.com/piotrmurach/tty) toolkit.
24
+ **TTY::Pager** provides independent terminal pager component for [TTY](https://github.com/piotrmurach/tty) toolkit.
25
25
 
26
26
  ## Installation
27
27
 
@@ -40,84 +40,286 @@ Or install it yourself as:
40
40
 
41
41
  ## Overview
42
42
 
43
- The **TTY::Pager** on initialization will choose the best available pager out of `SystemPager`, `BasicPager` or `NullPager`. If paging is disabled then a `NullPager` is used, which either returns text as is or simply prints it out to stdout on tty devices. Otherwise a check is performed to find paging command to page text with `SystemPager`. However, if no paging command is found, a `BasicPager` is used which is a pure Ruby implementation that is guaranteed to work with any ruby interpreter and any platform.
43
+ The **TTY::Pager** will automatically choose the best available pager on a user's system. Failing to do so, it will fallback on a pure Ruby version that is guaranteed to work with any Ruby interpreter and on any platform.
44
+
45
+ ## Contents
46
+
47
+ * [1. Usage](#1-usage)
48
+ * [2. API](#2-api)
49
+ * [2.1 new](#21-new)
50
+ * [2.1.1 :enabled](#211-enabled)
51
+ * [2.1.2 :command](#212-command)
52
+ * [2.1.3 :width](#213-width)
53
+ * [2.1.4 :prompt](#214-prompt)
54
+ * [2.2 page](#22-page)
55
+ * [2.3 write](#23-write)
56
+ * [2.4 try_write](#24-try_write)
57
+ * [2.5 puts](#25-puts)
58
+ * [2.6 close](#26-close)
59
+ * [2.7 ENV](#27-env)
44
60
 
45
61
  ## 1. Usage
46
62
 
47
- In order to let **TTY::Pager** pick the best paging mechanism automatically do:
63
+ The **TTY::Pager** will pick the best paging mechanism available on your system when initialized:
48
64
 
49
65
  ```ruby
50
66
  pager = TTY::Pager.new
51
67
  ```
52
68
 
53
- Then to perform actual content pagination invoke `page` method with the content to paginate as the argument:
69
+ Then to start paginating text call the `page` method with the content as the first argument:
54
70
 
55
71
  ```ruby
56
72
  pager.page("Very long text...")
57
73
  ```
58
74
 
59
- If you want to use specific pager you can do so by invoking it directly:
75
+ This will launch a pager in the background and wait until the user is done.
76
+
77
+ Alternatively, you can pass the `:path` keyword to specify a file path:
78
+
79
+ ```ruby
80
+ pager.page(path: "/path/to/filename.txt")
81
+ ```
82
+
83
+ If instead you'd like to paginate a long-running operation, you could use the block form of the pager:
84
+
85
+ ```ruby
86
+ TTY::Pager.page do |pager|
87
+ File.open("file_with_lots_of_lines.txt", "r").each_line do |line|
88
+ # do some work with the line
89
+
90
+ pager.write(line) # send it to the pager
91
+ end
92
+ end
93
+ ```
94
+
95
+ After block finishes, the pager is automatically closed.
96
+
97
+ For more control, you can translate the block form into separate `write` and `close` calls:
98
+
99
+ ```ruby
100
+ begin
101
+ pager = TTY::Pager.new
102
+
103
+ File.open("file_with_lots_of_lines.txt", "r").each_line do |line|
104
+ # do some work with the line
105
+
106
+ pager.write(line) # send it to the pager
107
+ end
108
+ rescue TTY::Pager::PagerClosed
109
+ # the user closed the paginating tool
110
+ ensure
111
+ pager.close
112
+ end
113
+ ```
114
+
115
+ If you want to use a specific pager you can do so by invoking it directly:
60
116
 
61
117
  ```ruby
62
118
  pager = TTY::Pager::BasicPager.new
119
+ # or
120
+ pager = TTY::Pager::SystemPager.new
121
+ # or
122
+ pager = TTY::Pager::NullPager.new
63
123
  ```
64
124
 
65
- ## 2. Interface
125
+ ## 2. API
126
+
127
+ ### 2.1 new
128
+
129
+ The `TTY::Pager` can be configured during initialization for terminal width, type of prompt when basic pager is invoked, and the pagination command to run.
130
+
131
+ For example, to disable a pager in CI you could do:
132
+
133
+ ```ruby
134
+ pager = TTY::Pager.new(enabled: false)
135
+ ````
66
136
 
67
- ### :enabled
137
+ #### 2.1.1 :enabled
68
138
 
69
- If you want to disable the pager pass the `:enabled` option set to `false`:
139
+ If you want to disable the paging use the `:enabled` option set to `false`:
70
140
 
71
141
  ```ruby
72
142
  pager = TTY::Pager.new(enabled: false)
73
143
  ```
74
144
 
75
- ### :width
145
+ This will directly print all the content to the standard output. If the output isn't a tty device, the pager will return the content directly to the caller.
76
146
 
77
- The `BasicPager` allows to wrap content at given width:
147
+ #### 2.1.2 :command
148
+
149
+ To force `TTY::Pager` to always use a specific paging tool(s), use the `:command` option:
150
+
151
+ ```ruby
152
+ TTY::Pager.new(command: "less -R")
153
+ ```
154
+
155
+ The `:command` also accepts an array of pagers to use:
156
+
157
+ ```ruby
158
+ pager = TTY::Pager.new(command: ["less -r", "more -r"])
159
+ ```
160
+
161
+ If the provided pager command or commands don't exist on user's system, the pager will fallback automatically on a basic Ruby implementation.
162
+
163
+ To skip automatic detection of pager and always use a system pager do:
164
+
165
+ ```ruby
166
+ TTY::Pager::SystemPager.new(command: "less -R")
167
+ ```
168
+
169
+ #### 2.1.3 :width
170
+
171
+ Only the `BasicPager` allows you to wrap content at given terminal width:
78
172
 
79
173
  ```ruby
80
174
  pager = TTY::Pager.new(width: 80)
175
+ ```
176
+
177
+ This option doesn't affect the `SystemPager`.
178
+
179
+ To directly use `BasicPager` do:
180
+
181
+ ```ruby
81
182
  pager = TTY::Pager::BasicPager.new(width: 80)
82
183
  ```
83
184
 
84
- ### :prompt
185
+ #### 2.1.4 :prompt
186
+
187
+ To change the `BasicPager` page break prompt display, use the `:prompt` option:
188
+
189
+ ```ruby
190
+ prompt = -> (page) { "Page -#{page_num}- Press enter to continue" }
191
+ pager = TTY::Pager.new(prompt: prompt)
192
+ ```
193
+
194
+ ### 2.2 page
195
+
196
+ To start paging use the `page` method. It can be invoked on an instance or a class.
197
+
198
+ The class-level `page` is a convenient shortcut. To page some text you only need to do:
199
+
200
+ ```ruby
201
+ TTY::Pager.page("Some long text...")
202
+ ````
203
+
204
+ You can also include extra initialization parameters. For example, if you prefer to use a specific command do this:
205
+
206
+ ```ruby
207
+ TTY::Pager.page("Some long text...", command: "less -R")
208
+ ````
209
+
210
+ The instance equivalent would be:
211
+
212
+ ```ruby
213
+ pager = TTY::Pager.new(command: "less -R")
214
+ pager.page("Some long text...")
215
+ ````
216
+
217
+ Apart from text, you can page file content by passing the `:path` option:
218
+
219
+ ```ruby
220
+ TTY::Pager.page(path: "/path/to/filename.txt")
221
+ ````
222
+
223
+ The final way is to use the class-level `page` with a block. After the block is done, the pager is automatically closed. For example, to read a file line by line with additional processing you could do:
224
+
225
+ ```ruby
226
+ TTY::Pager.page do |pager|
227
+ File.foreach("filename.txt") do |line|
228
+ # do some work with the line
229
+
230
+ pager.write(line) # write line to the pager
231
+ end
232
+ end
233
+ ```
234
+
235
+ The instance equivalent of the block version would be:
236
+
237
+ ```ruby
238
+ pager = TTY::Pager.new
239
+ begin
240
+ File.foreach("filename.txt") do |line|
241
+ # do some work with the line
242
+
243
+ pager.write(line) # write line to the pager
244
+ end
245
+ rescue TTY::Pager::PagerClosed
246
+ ensure
247
+ pager.close
248
+ end
249
+ ```
250
+
251
+ ### 2.3 write
252
+
253
+ To stream content to the pager use the `write` method.
254
+
255
+ ```ruby
256
+ pager.write("Some text")
257
+ ```
85
258
 
86
- For the `BasicPager` you can pass a `:prompt` option to change the page break text:
259
+ You can pass in any number of arguments:
87
260
 
88
261
  ```ruby
89
- prompt = -> (page_num) { output.puts "Page -#{page_num}- Press enter to continue" }
90
- pager = TTY::Pager::BasicPager.new(prompt: prompt)
262
+ pager.write("one", "two", "three")
91
263
  ```
92
264
 
93
- ### :command
265
+ ### 2.4 try_write
94
266
 
95
- You can force `SystemPager` to always use a specific paging tool(s) by passing the `:command` option:
267
+ To check if a write has been successful use `try_write`:
96
268
 
97
269
  ```ruby
98
- TTY::Pager.new(command: 'less -R')
99
- TTY::Pager::SystemPager.new(command: 'less -R')
270
+ pager.try_write("Some text")
271
+ # => true
100
272
  ```
101
273
 
102
- You also specify an array of pagers to use:
274
+ ### 2.5 puts
275
+
276
+ To write a line of text and end it with a new line use `puts` call:
103
277
 
104
278
  ```ruby
105
- pager = TTY::Pager.new(command: ['less -r', 'more -r'])
279
+ pager.puts("Single line of content")
106
280
  ```
107
281
 
108
- ### PAGER
282
+ ### 2.6 close
283
+
284
+ When you're done streaming content manually use `close` to finish paging.
109
285
 
110
- By default the `SystemPager` will check the `PAGER` environment variable, if not set it will try one of the `less`, `more`, `cat`, `pager`. Therefore, if you wish to set your preferred pager you can either set up your shell like so:
286
+ All interactions with a pager can raise an exception for various reasons, so wrap your code using the following pattern:
287
+
288
+ ```ruby
289
+ pager = TTY::Pager.new
290
+
291
+ begin
292
+ # ... perform pager writes
293
+ rescue TTY::Pager::PagerClosed
294
+ # the user closed the paginating tool
295
+ ensure
296
+ pager.close
297
+ end
298
+ ```
299
+
300
+ Alternatively use the class-level `page` call with a block to automatically close the pager:
301
+
302
+ ```ruby
303
+ TTY::Pager.page do |pager|
304
+ # ... perform pager writes
305
+ end
306
+ ```
307
+
308
+ ### 2.7 ENV
309
+
310
+ By default the `SystemPager` will check the `PAGER` environment variable. If the `PAGER` isn't set, the pager will try one of the searched commands like `less`, `more` or `pg`.
311
+
312
+ Therefore, if you wish to set your preferred pager you can either set up your shell like so:
111
313
 
112
314
  ```bash
113
- PAGER=less
315
+ PAGER=less -R
114
316
  export PAGER
115
317
  ```
116
318
 
117
- or set `PAGER` in Ruby script:
319
+ Or set `PAGER` in Ruby script:
118
320
 
119
321
  ```ruby
120
- ENV['PAGER']='less'
322
+ ENV["PAGER"]="less -R"
121
323
  ```
122
324
 
123
325
  ## Contributing
@@ -130,6 +332,10 @@ Bug reports and pull requests are welcome on GitHub at https://github.com/piotrm
130
332
  4. Push to the branch (`git push origin my-new-feature`)
131
333
  5. Create a new Pull Request
132
334
 
335
+ ## Code of Conduct
336
+
337
+ Everyone interacting in the TTY::Pager project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/piotrmurach/tty-pager/blob/master/CODE_OF_CONDUCT.md).
338
+
133
339
  ## Copyright
134
340
 
135
341
  Copyright (c) 2015 Piotr Murach. See LICENSE for further details.
@@ -1 +1 @@
1
- require_relative 'tty/pager'
1
+ require_relative "tty/pager"
@@ -1,103 +1,101 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'tty-screen'
4
-
5
- require_relative 'pager/basic'
6
- require_relative 'pager/null'
7
- require_relative 'pager/system'
8
- require_relative 'pager/version'
3
+ require_relative "pager/basic"
4
+ require_relative "pager/null"
5
+ require_relative "pager/system"
6
+ require_relative "pager/version"
9
7
 
10
8
  module TTY
11
- class Pager
9
+ module Pager
12
10
  Error = Class.new(StandardError)
13
11
 
14
- # Select an appriopriate pager
15
- #
16
- # If the user disabled paging then a NullPager is returned,
17
- # otherwise a check is performed to find native system
18
- # command to perform pagination with SystemPager. Finally,
19
- # if no system command is found, a BasicPager is used which
20
- # is a pure Ruby implementation known to work on any platform.
21
- #
22
- # @api private
23
- def self.select_pager(enabled, commands)
24
- if !enabled
25
- NullPager
26
- elsif SystemPager.exec_available?(*commands)
27
- SystemPager
28
- else
29
- BasicPager
30
- end
31
- end
12
+ # Raised when pager is closed
13
+ PagerClosed = Class.new(Error)
32
14
 
33
- # Create a pager
34
- #
35
- # @param [Hash] options
36
- # @option options [Proc] :prompt
37
- # a proc object that accepts page number
38
- # @option options [IO] :input
39
- # the object to send input to
40
- # @option options [IO] :output
41
- # the object to send output to
42
- # @option options [Boolean] :enabled
43
- # disable/enable text paging
44
- #
45
- # @api public
46
- def initialize(**options)
47
- @input = options.fetch(:input) { $stdin }
48
- @output = options.fetch(:output) { $stdout }
49
- @enabled = options.fetch(:enabled) { true }
50
- commands = Array(options[:command])
15
+ # Raised when user provides unnexpected argument
16
+ InvalidArgument = Class.new(Error)
51
17
 
52
- if self.class == TTY::Pager
53
- @pager = self.class.select_pager(@enabled, commands).new(options)
18
+ module ClassMethods
19
+ # Create a pager
20
+ #
21
+ # @param [Boolean] :enabled
22
+ # disable/enable text paging
23
+ # @param [String] :command
24
+ # the paging command
25
+ # @param [IO] :input
26
+ # the object to send input to
27
+ # @param [IO] :output
28
+ # the object to send output to
29
+ # @param [Proc] :prompt
30
+ # a proc object that accepts page number
31
+ # @param [Integer] :width
32
+ # the terminal width
33
+ # @param [Integer] :height
34
+ # the terminal height
35
+ #
36
+ # @api public
37
+ def new(enabled: true, command: nil, **options)
38
+ select_pager(enabled: enabled, command: command).new(
39
+ enabled: enabled, command: command, **options)
54
40
  end
55
- end
56
-
57
- # Check if pager is enabled
58
- #
59
- # @return [Boolean]
60
- #
61
- # @api public
62
- def enabled?
63
- !!@enabled
64
- end
65
41
 
66
- # Page the given text through the available pager
67
- #
68
- # @param [String] text
69
- # the text to run through a pager
70
- #
71
- # @yield [Integer] page number
72
- #
73
- # @return [TTY::Pager]
74
- #
75
- # @api public
76
- def page(text, &callback)
77
- pager.page(text, &callback)
78
- self
79
- end
42
+ # Paginate content through null, basic or system pager.
43
+ #
44
+ # @example
45
+ # TTY::Pager.page do |pager|
46
+ # pager.write "some text"
47
+ # end
48
+ #
49
+ # @param [String] :text
50
+ # an optional blob of content
51
+ # @param [String] :path
52
+ # a path to a file
53
+ # @param [Boolean] :enabled
54
+ # whether or not to use null pager
55
+ # @param [String] :command
56
+ # the paging command
57
+ # @param [IO] :input
58
+ # the object to send input to
59
+ # @param [IO] :output
60
+ # the object to send output to
61
+ #
62
+ # @api public
63
+ def page(text = nil, path: nil, enabled: true, command: nil,
64
+ **options, &block)
65
+ select_pager(enabled: enabled, command: command).
66
+ page(text, path: path, enabled: enabled, command: command,
67
+ **options, &block)
68
+ end
80
69
 
81
- # The terminal height
82
- #
83
- # @api public
84
- def page_height
85
- TTY::Screen.height
86
- end
70
+ # Select an appriopriate pager
71
+ #
72
+ # If the user disabled paging then a NullPager is returned,
73
+ # otherwise a check is performed to find native system
74
+ # command to perform pagination with SystemPager. Finally,
75
+ # if no system command is found, a BasicPager is used which
76
+ # is a pure Ruby implementation known to work on any platform.
77
+ #
78
+ # @param [Boolean] enabled
79
+ # whether or not to allow paging
80
+ # @param [String] command
81
+ # the command to run if available
82
+ #
83
+ # @api private
84
+ def select_pager(enabled: true, command: nil)
85
+ commands = Array(command)
87
86
 
88
- # The terminal width
89
- #
90
- # @api public
91
- def page_width
92
- TTY::Screen.width
87
+ if !enabled
88
+ NullPager
89
+ elsif SystemPager.exec_available?(*commands)
90
+ SystemPager
91
+ else
92
+ BasicPager
93
+ end
94
+ end
93
95
  end
94
96
 
95
- protected
96
-
97
- attr_reader :output
98
-
99
- attr_reader :input
97
+ extend ClassMethods
100
98
 
101
- attr_reader :pager
99
+ private_class_method :select_pager
102
100
  end # Pager
103
101
  end # TTY