tty-pager 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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 Version](https://badge.fury.io/rb/tty-pager.svg)][gem]
|
3
|
+
[![Build Status](https://secure.travis-ci.org/peter-murach/tty-pager.svg?branch=master)][travis]
|
4
|
+
[![Code Climate](https://codeclimate.com/github/peter-murach/tty-pager/badges/gpa.svg)][codeclimate]
|
5
|
+
[![Coverage Status](https://coveralls.io/repos/peter-murach/tty-pager/badge.svg)][coverage]
|
6
|
+
[![Inline docs](http://inch-ci.org/github/peter-murach/tty-pager.svg?branch=master)][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:
|