tty-pager 0.1.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 +7 -0
- data/.gitignore +22 -0
- data/.rspec +3 -0
- data/.ruby-version +1 -0
- data/.travis.yml +24 -0
- data/Gemfile +15 -0
- data/LICENSE.txt +22 -0
- data/README.md +75 -0
- data/Rakefile +8 -0
- data/lib/tty/pager/basic.rb +60 -0
- data/lib/tty/pager/null.rb +14 -0
- data/lib/tty/pager/system.rb +124 -0
- data/lib/tty/pager/version.rb +7 -0
- data/lib/tty/pager.rb +129 -0
- data/lib/tty-pager.rb +6 -0
- data/spec/spec_helper.rb +45 -0
- data/spec/unit/basic/page_spec.rb +135 -0
- data/spec/unit/null/page_spec.rb +12 -0
- data/spec/unit/page_spec.rb +41 -0
- data/spec/unit/system/available_spec.rb +25 -0
- data/spec/unit/system/page_spec.rb +23 -0
- data/tasks/console.rake +10 -0
- data/tasks/coverage.rake +11 -0
- data/tasks/spec.rake +29 -0
- data/tty-pager.gemspec +26 -0
- metadata +133 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 762884b7e1c8aed7cb329a22577247b1d13e3dec
|
4
|
+
data.tar.gz: 3a0e5d127f2348ab58a7e95402b4a76c8cf1aea9
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 9fbcf3ac3cbbbe53591bc2ced88aa28af51825e6d094f2fe22d7aa47940293f8b0fb8abca0861d98664de6b3bb7397b12477973a5599fd36aade65b8918e7d2e
|
7
|
+
data.tar.gz: a7632fc1596b11cd0e9a4aa9d2bde295020b856eca9e5e2f6b28aca8252d4db5228a4a7e177920851d68e8db5b1aae6f47800c3ff25af8f9ca3a3b5cc3b27594
|
data/.gitignore
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
.yardoc
|
6
|
+
Gemfile.lock
|
7
|
+
InstalledFiles
|
8
|
+
_yardoc
|
9
|
+
coverage
|
10
|
+
doc/
|
11
|
+
lib/bundler/man
|
12
|
+
pkg
|
13
|
+
rdoc
|
14
|
+
spec/reports
|
15
|
+
test/tmp
|
16
|
+
test/version_tmp
|
17
|
+
tmp
|
18
|
+
*.bundle
|
19
|
+
*.so
|
20
|
+
*.o
|
21
|
+
*.a
|
22
|
+
mkmf.log
|
data/.rspec
ADDED
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.0.0
|
data/.travis.yml
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
language: ruby
|
2
|
+
bundler_args: --without yard benchmarks
|
3
|
+
script: "bundle exec rake ci"
|
4
|
+
rvm:
|
5
|
+
- 1.9.3
|
6
|
+
- 2.0
|
7
|
+
- 2.1
|
8
|
+
- 2.2
|
9
|
+
- ruby-head
|
10
|
+
matrix:
|
11
|
+
include:
|
12
|
+
- rvm: jruby-19mode
|
13
|
+
- rvm: jruby-20mode
|
14
|
+
- rvm: jruby-21mode
|
15
|
+
- rvm: jruby-head
|
16
|
+
- rvm: rbx-2
|
17
|
+
allow_failures:
|
18
|
+
- rvm: ruby-head
|
19
|
+
- rvm: jruby-head
|
20
|
+
- rvm: jruby-20mode
|
21
|
+
- rvm: jruby-21mode
|
22
|
+
fast_finish: true
|
23
|
+
branches:
|
24
|
+
only: master
|
data/Gemfile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
gemspec
|
4
|
+
|
5
|
+
group :development do
|
6
|
+
gem 'rake', '~> 10.4.2'
|
7
|
+
gem 'rspec', '~> 3.2.0'
|
8
|
+
gem 'yard', '~> 0.8.7'
|
9
|
+
end
|
10
|
+
|
11
|
+
group :metrics do
|
12
|
+
gem 'coveralls', '~> 0.8.1'
|
13
|
+
gem 'simplecov', '~> 0.10.0'
|
14
|
+
gem 'yardstick', '~> 0.9.9'
|
15
|
+
end
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2015 Piotr Murach
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
# TTY::Pager
|
2
|
+
[][gem]
|
3
|
+
[][travis]
|
4
|
+
[][codeclimate]
|
5
|
+
[][coverage]
|
6
|
+
[][inchpages]
|
7
|
+
|
8
|
+
[gem]: http://badge.fury.io/rb/tty-pager
|
9
|
+
[travis]: http://travis-ci.org/peter-murach/tty-pager
|
10
|
+
[codeclimate]: https://codeclimate.com/github/peter-murach/tty-pager
|
11
|
+
[coverage]: https://coveralls.io/r/peter-murach/tty-pager
|
12
|
+
[inchpages]: http://inch-ci.org/github/peter-murach/tty-pager
|
13
|
+
|
14
|
+
> Terminal output paging in a cross-platform way supporting all major ruby interpreters.
|
15
|
+
|
16
|
+
**TTY::Pager** provides independent terminal output paging component for [TTY](https://github.com/peter-murach/tty) toolkit.
|
17
|
+
|
18
|
+
## Installation
|
19
|
+
|
20
|
+
Add this line to your application's Gemfile:
|
21
|
+
|
22
|
+
gem 'tty-pager'
|
23
|
+
|
24
|
+
And then execute:
|
25
|
+
|
26
|
+
$ bundle
|
27
|
+
|
28
|
+
Or install it yourself as:
|
29
|
+
|
30
|
+
$ gem install tty-pager
|
31
|
+
|
32
|
+
## 1. Usage
|
33
|
+
|
34
|
+
The **TTY::Pager** upon initialization will choose the best available pager out of `SystemPager`, `BasicPager` or `NullPager`. If paging is disabled then a `NullPager` is used that simply prints content out to stdout, otherwise a check is performed to find native system executable to perform pagination natively with `SystemPager`. If no system executable is found, a `BasicPager` is used which is a pure Ruby implementation that will work with any ruby interpreter.
|
35
|
+
|
36
|
+
```ruby
|
37
|
+
pager = TTY::Pager.new
|
38
|
+
```
|
39
|
+
|
40
|
+
Then to perform actual content pagination invoke `page` like so:
|
41
|
+
|
42
|
+
```ruby
|
43
|
+
pager.page("Very long text...")
|
44
|
+
```
|
45
|
+
|
46
|
+
If you want to use specific pager you can do so by invoking it directly
|
47
|
+
|
48
|
+
```ruby
|
49
|
+
pager = TTY::Pager::BasicPager.new
|
50
|
+
```
|
51
|
+
|
52
|
+
If you want to disable the pager pass the `:enabled` option:
|
53
|
+
|
54
|
+
```ruby
|
55
|
+
pager = TTY::Pager.new enabled: false
|
56
|
+
```
|
57
|
+
|
58
|
+
For the `BasicPager` you can also pass a `:prompt` option to change the page break content:
|
59
|
+
|
60
|
+
```ruby
|
61
|
+
prompt = -> (page_num) { output.puts "Page -#{page_num}- Press enter to continue" }
|
62
|
+
pager = TTY::Pager::BasicPager.new prompt: prompt
|
63
|
+
```
|
64
|
+
|
65
|
+
## Contributing
|
66
|
+
|
67
|
+
1. Fork it ( https://github.com/peter-murach/tty-pager/fork )
|
68
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
69
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
70
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
71
|
+
5. Create a new Pull Request
|
72
|
+
|
73
|
+
## Copyright
|
74
|
+
|
75
|
+
Copyright (c) 2015 Piotr Murach. See LICENSE for further details.
|
data/Rakefile
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
module TTY
|
4
|
+
class Pager
|
5
|
+
# A basic pager is used to work on systems where
|
6
|
+
# system pager is not supported.
|
7
|
+
#
|
8
|
+
# @api public
|
9
|
+
class BasicPager < Pager
|
10
|
+
# Page text
|
11
|
+
#
|
12
|
+
# @api public
|
13
|
+
def page(text, &callback)
|
14
|
+
page_num = 1
|
15
|
+
leftover = []
|
16
|
+
lines_left = @height
|
17
|
+
|
18
|
+
text.lines.each do |line|
|
19
|
+
chunk = []
|
20
|
+
if !leftover.empty?
|
21
|
+
chunk = leftover
|
22
|
+
leftover = []
|
23
|
+
end
|
24
|
+
wrapped_line = Verse.wrap(line, @width)
|
25
|
+
wrapped_line.lines.each do |line_part|
|
26
|
+
if lines_left > 0
|
27
|
+
chunk << line_part
|
28
|
+
lines_left -= 1
|
29
|
+
else
|
30
|
+
leftover << line_part
|
31
|
+
end
|
32
|
+
end
|
33
|
+
output.print(chunk.join)
|
34
|
+
|
35
|
+
if lines_left == 0
|
36
|
+
break unless continue_paging?(page_num)
|
37
|
+
lines_left = @height
|
38
|
+
if leftover.size > 0
|
39
|
+
lines_left -= leftover.size
|
40
|
+
end
|
41
|
+
page_num += 1
|
42
|
+
return !callback.call(page_num) unless callback.nil?
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
if leftover.size > 0
|
47
|
+
output.print(leftover.join)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
# @api private
|
54
|
+
def continue_paging?(page_num)
|
55
|
+
instance_exec(page_num, &@prompt)
|
56
|
+
!@input.gets.chomp[/q/i]
|
57
|
+
end
|
58
|
+
end # BasicPager
|
59
|
+
end # Pager
|
60
|
+
end # TTY
|
@@ -0,0 +1,124 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
module TTY
|
4
|
+
class Pager
|
5
|
+
# A system pager is used on systems where native
|
6
|
+
# pagination exists
|
7
|
+
#
|
8
|
+
# @api public
|
9
|
+
class SystemPager < Pager
|
10
|
+
# Find first available system command for paging
|
11
|
+
#
|
12
|
+
# @example Basic usage
|
13
|
+
# available # => 'less'
|
14
|
+
#
|
15
|
+
# @example Usage with commands
|
16
|
+
# available('less', 'cat') # => 'less'
|
17
|
+
#
|
18
|
+
# @param [Array[String]] commands
|
19
|
+
#
|
20
|
+
# @return [String]
|
21
|
+
#
|
22
|
+
# @api public
|
23
|
+
def self.available(*commands)
|
24
|
+
commands = commands.empty? ? executables : commands
|
25
|
+
commands.compact.uniq.find { |cmd| command_exists?(cmd) }
|
26
|
+
end
|
27
|
+
|
28
|
+
# Check if command is available
|
29
|
+
#
|
30
|
+
# @example Basic usage
|
31
|
+
# available? # => true
|
32
|
+
#
|
33
|
+
# @example Usage with command
|
34
|
+
# available?('less') # => true
|
35
|
+
#
|
36
|
+
# @return [Boolean]
|
37
|
+
#
|
38
|
+
# @api public
|
39
|
+
def self.available?(*commands)
|
40
|
+
!available(*commands).nil?
|
41
|
+
end
|
42
|
+
|
43
|
+
# Use system command to page output text
|
44
|
+
#
|
45
|
+
# @example
|
46
|
+
# page('some long text...')
|
47
|
+
#
|
48
|
+
# @param [String] text
|
49
|
+
# the text to paginate
|
50
|
+
#
|
51
|
+
# @return [nil]
|
52
|
+
#
|
53
|
+
# @api public
|
54
|
+
def page(text, &callback)
|
55
|
+
read_io, write_io = IO.pipe
|
56
|
+
|
57
|
+
if Kernel.fork
|
58
|
+
# parent process
|
59
|
+
write_io.close
|
60
|
+
input.reopen(read_io)
|
61
|
+
read_io.close
|
62
|
+
|
63
|
+
# Wait until we have input before we start the pager
|
64
|
+
IO.select [input]
|
65
|
+
|
66
|
+
begin
|
67
|
+
exec(pager_command)
|
68
|
+
rescue SystemCallError
|
69
|
+
exit 1
|
70
|
+
end
|
71
|
+
else
|
72
|
+
# child process
|
73
|
+
read_io.close
|
74
|
+
write_io.write(text)
|
75
|
+
write_io.close
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
# List possible executables for output paging
|
82
|
+
#
|
83
|
+
# @return [Array[String]]
|
84
|
+
#
|
85
|
+
# @api private
|
86
|
+
def self.executables
|
87
|
+
[ENV['GIT_PAGER'], ENV['PAGER'],
|
88
|
+
`git config --get-all core.pager`.split.first,
|
89
|
+
'less', 'more', 'cat', 'pager']
|
90
|
+
end
|
91
|
+
private_class_method :executables
|
92
|
+
|
93
|
+
# Check if command exists
|
94
|
+
#
|
95
|
+
# @example
|
96
|
+
# command_exists?('less) # => true
|
97
|
+
#
|
98
|
+
# @param [String] command
|
99
|
+
# the command to check
|
100
|
+
#
|
101
|
+
# @return [Boolean]
|
102
|
+
#
|
103
|
+
# @api private
|
104
|
+
def self.command_exists?(command)
|
105
|
+
!TTY::Which.which(command).nil?
|
106
|
+
end
|
107
|
+
private_class_method :command_exists?
|
108
|
+
|
109
|
+
# The pager command to run
|
110
|
+
#
|
111
|
+
# @return [String]
|
112
|
+
# the name of executable to run
|
113
|
+
#
|
114
|
+
# @api private
|
115
|
+
def pager_command(*commands)
|
116
|
+
@pager_command = if @pager_command && commands.empty?
|
117
|
+
@pager_command
|
118
|
+
else
|
119
|
+
self.class.available(*commands)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end # SystemPager
|
123
|
+
end # Pager
|
124
|
+
end # TTY
|
data/lib/tty/pager.rb
ADDED
@@ -0,0 +1,129 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require "tty/pager/basic"
|
4
|
+
require "tty/pager/null"
|
5
|
+
require "tty/pager/system"
|
6
|
+
require "tty/pager/version"
|
7
|
+
|
8
|
+
module TTY
|
9
|
+
class Pager
|
10
|
+
PROMPT_HEIGHT = 2
|
11
|
+
|
12
|
+
PAGE_BREAK = "\n--- Page -%s- " \
|
13
|
+
"Press enter/return to continue " \
|
14
|
+
"(or q to quit) ---".freeze
|
15
|
+
|
16
|
+
# Create a pager
|
17
|
+
#
|
18
|
+
# @param [Hash] options
|
19
|
+
# @option options [Proc] :prompt
|
20
|
+
# a proc object that accepts page number
|
21
|
+
# @option options [IO] :input
|
22
|
+
# the object to send input to
|
23
|
+
# @option options [IO] :output
|
24
|
+
# the object to send output to
|
25
|
+
# @option options [Integer] :height
|
26
|
+
# the terminal height
|
27
|
+
# @option options [Integer] :width
|
28
|
+
# the terminal width
|
29
|
+
# @option options [Boolean] :enabled
|
30
|
+
# disable/enable text paging
|
31
|
+
#
|
32
|
+
# @api public
|
33
|
+
def initialize(options = {})
|
34
|
+
@height = options.fetch(:height) { page_height }
|
35
|
+
@width = options.fetch(:width) { page_width }
|
36
|
+
@input = options.fetch(:input) { $stdin }
|
37
|
+
@output = options.fetch(:output) { $stdout }
|
38
|
+
@enabled = options.fetch(:enabled) { true }
|
39
|
+
@prompt = options.fetch(:prompt) { default_prompt }
|
40
|
+
@height -= PROMPT_HEIGHT
|
41
|
+
@output = output
|
42
|
+
|
43
|
+
if self.class == TTY::Pager
|
44
|
+
@pager = find_available
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Default prompt for paging
|
49
|
+
#
|
50
|
+
# @return [Proc]
|
51
|
+
#
|
52
|
+
# @api private
|
53
|
+
def default_prompt
|
54
|
+
proc { |page_num| output.puts PAGE_BREAK % page_num }
|
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
|
+
|
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
|
80
|
+
|
81
|
+
# The terminal height
|
82
|
+
#
|
83
|
+
# @api public
|
84
|
+
def page_height
|
85
|
+
TTY::Screen.height
|
86
|
+
end
|
87
|
+
|
88
|
+
# The terminal width
|
89
|
+
#
|
90
|
+
# @api public
|
91
|
+
def page_width
|
92
|
+
TTY::Screen.width
|
93
|
+
end
|
94
|
+
|
95
|
+
protected
|
96
|
+
|
97
|
+
attr_reader :output
|
98
|
+
|
99
|
+
attr_reader :input
|
100
|
+
|
101
|
+
attr_reader :pager
|
102
|
+
|
103
|
+
# Find available pager
|
104
|
+
#
|
105
|
+
# If the user disabled paging then a NullPager is returned,
|
106
|
+
# otherwise a check is performed to find native system
|
107
|
+
# utility to perform pagination with SystemPager. Finally,
|
108
|
+
# if no system utility exists a BasicPager is used which
|
109
|
+
# is pure Ruby implementation.
|
110
|
+
#
|
111
|
+
# @api private
|
112
|
+
def find_available
|
113
|
+
if !enabled?
|
114
|
+
NullPager.new
|
115
|
+
elsif SystemPager.available? && !Pager.jruby?
|
116
|
+
SystemPager.new
|
117
|
+
else
|
118
|
+
BasicPager.new
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
# Check if running on jruby
|
123
|
+
#
|
124
|
+
# @api private
|
125
|
+
def self.jruby?
|
126
|
+
RbConfig::CONFIG['ruby_install_name'] == 'jruby'
|
127
|
+
end
|
128
|
+
end # Pager
|
129
|
+
end # TTY
|
data/lib/tty-pager.rb
ADDED
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
if RUBY_VERSION > '1.9' and (ENV['COVERAGE'] || ENV['TRAVIS'])
|
4
|
+
require 'simplecov'
|
5
|
+
require 'coveralls'
|
6
|
+
|
7
|
+
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
|
8
|
+
SimpleCov::Formatter::HTMLFormatter,
|
9
|
+
Coveralls::SimpleCov::Formatter
|
10
|
+
]
|
11
|
+
|
12
|
+
SimpleCov.start do
|
13
|
+
command_name 'spec'
|
14
|
+
add_filter 'spec'
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
require 'tty-pager'
|
19
|
+
|
20
|
+
RSpec.configure do |config|
|
21
|
+
config.expect_with :rspec do |expectations|
|
22
|
+
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
|
23
|
+
end
|
24
|
+
|
25
|
+
config.mock_with :rspec do |mocks|
|
26
|
+
mocks.verify_partial_doubles = true
|
27
|
+
end
|
28
|
+
|
29
|
+
# Limits the available syntax to the non-monkey patched syntax that is recommended.
|
30
|
+
config.disable_monkey_patching!
|
31
|
+
|
32
|
+
# This setting enables warnings. It's recommended, but in some cases may
|
33
|
+
# be too noisy due to issues in dependencies.
|
34
|
+
config.warnings = true
|
35
|
+
|
36
|
+
if config.files_to_run.one?
|
37
|
+
config.default_formatter = 'doc'
|
38
|
+
end
|
39
|
+
|
40
|
+
config.profile_examples = 2
|
41
|
+
|
42
|
+
config.order = :random
|
43
|
+
|
44
|
+
Kernel.srand config.seed
|
45
|
+
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
RSpec.describe TTY::Pager::BasicPager, '.page' do
|
4
|
+
let(:input) { StringIO.new }
|
5
|
+
let(:output) { StringIO.new }
|
6
|
+
|
7
|
+
it "doesn't paginate empty string" do
|
8
|
+
pager = described_class.new(output: output, input: input)
|
9
|
+
pager.page("")
|
10
|
+
expect(output.string).to eq("")
|
11
|
+
end
|
12
|
+
|
13
|
+
it "doesn't paginate text that fits on screen" do
|
14
|
+
text = "I try all things, I achieve what I can.\n"
|
15
|
+
pager = described_class.new(output: output, width: 100, height: 10)
|
16
|
+
pager.page(text)
|
17
|
+
expect(output.string).to eq(text)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "breaks text exceeding terminal width" do
|
21
|
+
text = ""
|
22
|
+
text << "It is not down on any map; true places never are.\n"
|
23
|
+
input << "\n"
|
24
|
+
input.rewind
|
25
|
+
pager = described_class.new(output: output, input: input,
|
26
|
+
width: 10, height: 6)
|
27
|
+
pager.page(text)
|
28
|
+
expect(output.string).to eq([
|
29
|
+
"It is not ",
|
30
|
+
"down on ",
|
31
|
+
"any map; ",
|
32
|
+
"true ",
|
33
|
+
"",
|
34
|
+
"--- Page -1- Press enter/return to continue (or q to quit) ---",
|
35
|
+
"places ",
|
36
|
+
"never are.\n"
|
37
|
+
].join("\n"))
|
38
|
+
end
|
39
|
+
|
40
|
+
it "continues paging when enter is pressed" do
|
41
|
+
text = ""
|
42
|
+
10.times { text << "I try all things, I achieve what I can.\n"}
|
43
|
+
input << "\n\n\n"
|
44
|
+
input.rewind
|
45
|
+
pager = described_class.new(output: output, input: input,
|
46
|
+
width: 100, height: 5)
|
47
|
+
pager.page(text)
|
48
|
+
expect(output.string).to eq([
|
49
|
+
"I try all things, I achieve what I can.",
|
50
|
+
"I try all things, I achieve what I can.",
|
51
|
+
"I try all things, I achieve what I can.",
|
52
|
+
"",
|
53
|
+
"--- Page -1- Press enter/return to continue (or q to quit) ---",
|
54
|
+
"I try all things, I achieve what I can.",
|
55
|
+
"I try all things, I achieve what I can.",
|
56
|
+
"I try all things, I achieve what I can.",
|
57
|
+
"",
|
58
|
+
"--- Page -2- Press enter/return to continue (or q to quit) ---",
|
59
|
+
"I try all things, I achieve what I can.",
|
60
|
+
"I try all things, I achieve what I can.",
|
61
|
+
"I try all things, I achieve what I can.",
|
62
|
+
"",
|
63
|
+
"--- Page -3- Press enter/return to continue (or q to quit) ---",
|
64
|
+
"I try all things, I achieve what I can.\n"
|
65
|
+
].join("\n"))
|
66
|
+
end
|
67
|
+
|
68
|
+
it "stops paging when q is pressed" do
|
69
|
+
text = ""
|
70
|
+
10.times { text << "I try all things, I achieve what I can.\n"}
|
71
|
+
input << "\nq\n"
|
72
|
+
input.rewind
|
73
|
+
pager = described_class.new(output: output, input: input,
|
74
|
+
width: 100, height: 5)
|
75
|
+
pager.page(text)
|
76
|
+
expect(output.string).to eq([
|
77
|
+
"I try all things, I achieve what I can.",
|
78
|
+
"I try all things, I achieve what I can.",
|
79
|
+
"I try all things, I achieve what I can.",
|
80
|
+
"",
|
81
|
+
"--- Page -1- Press enter/return to continue (or q to quit) ---",
|
82
|
+
"I try all things, I achieve what I can.",
|
83
|
+
"I try all things, I achieve what I can.",
|
84
|
+
"I try all things, I achieve what I can.",
|
85
|
+
"",
|
86
|
+
"--- Page -2- Press enter/return to continue (or q to quit) ---\n",
|
87
|
+
].join("\n"))
|
88
|
+
end
|
89
|
+
|
90
|
+
it "allows to change paging prompt" do
|
91
|
+
text = ""
|
92
|
+
5.times { text << "I try all things, I achieve what I can.\n"}
|
93
|
+
input << "\nq\n"
|
94
|
+
input.rewind
|
95
|
+
prompt = proc { |num| output.puts "Page -#{num}-" }
|
96
|
+
pager = described_class.new(output: output, input: input,
|
97
|
+
width: 100, height: 5, prompt: prompt)
|
98
|
+
pager.page(text)
|
99
|
+
expect(output.string).to eq([
|
100
|
+
"I try all things, I achieve what I can.",
|
101
|
+
"I try all things, I achieve what I can.",
|
102
|
+
"I try all things, I achieve what I can.",
|
103
|
+
"Page -1-",
|
104
|
+
"I try all things, I achieve what I can.",
|
105
|
+
"I try all things, I achieve what I can.\n",
|
106
|
+
].join("\n"))
|
107
|
+
end
|
108
|
+
|
109
|
+
it "preserves new lines when breaking" do
|
110
|
+
text = "a\na\na\na\na\na\na\na\na\na"
|
111
|
+
input << "\n\n\n"
|
112
|
+
input.rewind
|
113
|
+
pager = described_class.new(output: output, input: input,
|
114
|
+
width: 1, height: 5)
|
115
|
+
pager.page(text)
|
116
|
+
expect(output.string).to eq([
|
117
|
+
"a",
|
118
|
+
"a",
|
119
|
+
"a",
|
120
|
+
"",
|
121
|
+
"--- Page -1- Press enter/return to continue (or q to quit) ---",
|
122
|
+
"a",
|
123
|
+
"a",
|
124
|
+
"a",
|
125
|
+
"",
|
126
|
+
"--- Page -2- Press enter/return to continue (or q to quit) ---",
|
127
|
+
"a",
|
128
|
+
"a",
|
129
|
+
"a",
|
130
|
+
"",
|
131
|
+
"--- Page -3- Press enter/return to continue (or q to quit) ---",
|
132
|
+
"a"
|
133
|
+
].join("\n"))
|
134
|
+
end
|
135
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
RSpec.describe TTY::Pager::NullPager, '.page' do
|
4
|
+
let(:output) { StringIO.new }
|
5
|
+
|
6
|
+
it "doesn't paginate empty string" do
|
7
|
+
pager = described_class.new(output: output)
|
8
|
+
text = "I try all things, I achieve what I can.\n"
|
9
|
+
pager.page(text)
|
10
|
+
expect(output.string).to eq(text)
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
RSpec.describe TTY::Pager, '.page' do
|
4
|
+
let(:output) { StringIO.new }
|
5
|
+
|
6
|
+
it "selects null pager when disabled" do
|
7
|
+
null_pager = spy(:null_pager)
|
8
|
+
allow(TTY::Pager::NullPager).to receive(:new) { null_pager }
|
9
|
+
|
10
|
+
pager = described_class.new(enabled: false)
|
11
|
+
text = "I try all things, I achieve what I can.\n"
|
12
|
+
pager.page(text)
|
13
|
+
|
14
|
+
expect(TTY::Pager::NullPager).to have_received(:new)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "selects basic pager on non tty systems" do
|
18
|
+
basic_pager = spy(:basic_pager)
|
19
|
+
allow(TTY::Pager::SystemPager).to receive(:available?) { false }
|
20
|
+
allow(TTY::Pager::BasicPager).to receive(:new) { basic_pager }
|
21
|
+
|
22
|
+
pager = described_class.new
|
23
|
+
text = "I try all things, I achieve what I can.\n"
|
24
|
+
pager.page(text)
|
25
|
+
|
26
|
+
expect(basic_pager).to have_received(:page).with(text)
|
27
|
+
end
|
28
|
+
|
29
|
+
it "selects system pager on systems with tty" do
|
30
|
+
system_pager = spy(:system_pager)
|
31
|
+
allow(TTY::Pager::SystemPager).to receive(:available?) { true }
|
32
|
+
allow(described_class).to receive(:jruby?) { false }
|
33
|
+
allow(TTY::Pager::SystemPager).to receive(:new) { system_pager }
|
34
|
+
|
35
|
+
pager = described_class.new
|
36
|
+
text = "I try all things, I achieve what I can.\n"
|
37
|
+
pager.page(text)
|
38
|
+
|
39
|
+
expect(system_pager).to have_received(:page).with(text)
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
RSpec.describe TTY::Pager::SystemPager, '#available' do
|
4
|
+
let(:execs) { ['less', 'more'] }
|
5
|
+
|
6
|
+
subject(:pager) { described_class }
|
7
|
+
|
8
|
+
it 'finds available command' do
|
9
|
+
allow(pager).to receive(:executables).and_return(execs)
|
10
|
+
allow(pager).to receive(:command_exists?).with('less') { true }
|
11
|
+
allow(pager).to receive(:command_exists?).with('more') { false }
|
12
|
+
expect(pager.available).to eql('less')
|
13
|
+
end
|
14
|
+
|
15
|
+
it "doesn't find command" do
|
16
|
+
allow(pager).to receive(:executables).and_return(execs)
|
17
|
+
allow(pager).to receive(:command_exists?) { false }
|
18
|
+
expect(pager.available).to be_nil
|
19
|
+
end
|
20
|
+
|
21
|
+
it "takes precedence over other commands" do
|
22
|
+
allow(pager).to receive(:command_exists?).with('more') { true }
|
23
|
+
expect(pager.available('more')).to eql('more')
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
RSpec.describe TTY::Pager::SystemPager, '.page' do
|
4
|
+
let(:input) { StringIO.new }
|
5
|
+
let(:output) { StringIO.new }
|
6
|
+
|
7
|
+
it "executes the pager command in a subprocess" do
|
8
|
+
text = "I try all things, I achieve what I can.\n"
|
9
|
+
pager = described_class.new(output: output, input: input)
|
10
|
+
|
11
|
+
allow(pager).to receive(:exec)
|
12
|
+
allow(Kernel).to receive(:fork).and_return(true)
|
13
|
+
allow(pager).to receive(:pager_command).and_return('less')
|
14
|
+
allow(IO).to receive(:select)
|
15
|
+
allow(input).to receive(:reopen)
|
16
|
+
|
17
|
+
pager.page(text)
|
18
|
+
|
19
|
+
expect(IO).to have_received(:select).with([input])
|
20
|
+
expect(pager).to have_received(:exec).with('less')
|
21
|
+
expect(output.read).to eq('')
|
22
|
+
end
|
23
|
+
end
|
data/tasks/console.rake
ADDED
data/tasks/coverage.rake
ADDED
data/tasks/spec.rake
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'rspec/core/rake_task'
|
5
|
+
|
6
|
+
desc 'Run all specs'
|
7
|
+
RSpec::Core::RakeTask.new(:spec) do |task|
|
8
|
+
task.pattern = 'spec/{unit,integration}{,/*/**}/*_spec.rb'
|
9
|
+
end
|
10
|
+
|
11
|
+
namespace :spec do
|
12
|
+
desc 'Run unit specs'
|
13
|
+
RSpec::Core::RakeTask.new(:unit) do |task|
|
14
|
+
task.pattern = 'spec/unit{,/*/**}/*_spec.rb'
|
15
|
+
end
|
16
|
+
|
17
|
+
desc 'Run integration specs'
|
18
|
+
RSpec::Core::RakeTask.new(:integration) do |task|
|
19
|
+
task.pattern = 'spec/integration{,/*/**}/*_spec.rb'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
rescue LoadError
|
24
|
+
%w[spec spec:unit spec:integration].each do |name|
|
25
|
+
task name do
|
26
|
+
$stderr.puts "In order to run #{name}, do `gem install rspec`"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/tty-pager.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'tty/pager/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "tty-pager"
|
8
|
+
spec.version = TTY::Pager::VERSION
|
9
|
+
spec.authors = ["Piotr Murach"]
|
10
|
+
spec.email = [""]
|
11
|
+
spec.summary = %q{Terminal output paging in a cross-platform way supporting all major ruby interpreters.}
|
12
|
+
spec.description = %q{Terminal output paging in a cross-platform way supporting all major ruby interpreters.}
|
13
|
+
spec.homepage = "https://github.com/peter-murach/tty-pager"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_dependency 'tty-screen', '~> 0.2.0'
|
22
|
+
spec.add_dependency 'tty-which', '~> 0.1.0'
|
23
|
+
spec.add_dependency 'verse', '~> 0.4.0'
|
24
|
+
|
25
|
+
spec.add_development_dependency 'bundler', '~> 1.6'
|
26
|
+
end
|
metadata
ADDED
@@ -0,0 +1,133 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: tty-pager
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Piotr Murach
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-05-31 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: tty-screen
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.2.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.2.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: tty-which
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.1.0
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 0.1.0
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: verse
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ~>
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 0.4.0
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 0.4.0
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: bundler
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.6'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ~>
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.6'
|
69
|
+
description: Terminal output paging in a cross-platform way supporting all major ruby
|
70
|
+
interpreters.
|
71
|
+
email:
|
72
|
+
- ''
|
73
|
+
executables: []
|
74
|
+
extensions: []
|
75
|
+
extra_rdoc_files: []
|
76
|
+
files:
|
77
|
+
- .gitignore
|
78
|
+
- .rspec
|
79
|
+
- .ruby-version
|
80
|
+
- .travis.yml
|
81
|
+
- Gemfile
|
82
|
+
- LICENSE.txt
|
83
|
+
- README.md
|
84
|
+
- Rakefile
|
85
|
+
- lib/tty-pager.rb
|
86
|
+
- lib/tty/pager.rb
|
87
|
+
- lib/tty/pager/basic.rb
|
88
|
+
- lib/tty/pager/null.rb
|
89
|
+
- lib/tty/pager/system.rb
|
90
|
+
- lib/tty/pager/version.rb
|
91
|
+
- spec/spec_helper.rb
|
92
|
+
- spec/unit/basic/page_spec.rb
|
93
|
+
- spec/unit/null/page_spec.rb
|
94
|
+
- spec/unit/page_spec.rb
|
95
|
+
- spec/unit/system/available_spec.rb
|
96
|
+
- spec/unit/system/page_spec.rb
|
97
|
+
- tasks/console.rake
|
98
|
+
- tasks/coverage.rake
|
99
|
+
- tasks/spec.rake
|
100
|
+
- tty-pager.gemspec
|
101
|
+
homepage: https://github.com/peter-murach/tty-pager
|
102
|
+
licenses:
|
103
|
+
- MIT
|
104
|
+
metadata: {}
|
105
|
+
post_install_message:
|
106
|
+
rdoc_options: []
|
107
|
+
require_paths:
|
108
|
+
- lib
|
109
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
110
|
+
requirements:
|
111
|
+
- - '>='
|
112
|
+
- !ruby/object:Gem::Version
|
113
|
+
version: '0'
|
114
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
115
|
+
requirements:
|
116
|
+
- - '>='
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: '0'
|
119
|
+
requirements: []
|
120
|
+
rubyforge_project:
|
121
|
+
rubygems_version: 2.0.3
|
122
|
+
signing_key:
|
123
|
+
specification_version: 4
|
124
|
+
summary: Terminal output paging in a cross-platform way supporting all major ruby
|
125
|
+
interpreters.
|
126
|
+
test_files:
|
127
|
+
- spec/spec_helper.rb
|
128
|
+
- spec/unit/basic/page_spec.rb
|
129
|
+
- spec/unit/null/page_spec.rb
|
130
|
+
- spec/unit/page_spec.rb
|
131
|
+
- spec/unit/system/available_spec.rb
|
132
|
+
- spec/unit/system/page_spec.rb
|
133
|
+
has_rdoc:
|