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 +4 -4
- data/CHANGELOG.md +24 -0
- data/README.md +233 -27
- data/lib/tty-pager.rb +1 -1
- data/lib/tty/pager.rb +84 -86
- data/lib/tty/pager/abstract.rb +138 -0
- data/lib/tty/pager/basic.rb +197 -54
- data/lib/tty/pager/null.rb +22 -3
- data/lib/tty/pager/system.rb +154 -67
- data/lib/tty/pager/version.rb +2 -2
- metadata +28 -76
- data/Rakefile +0 -8
- data/examples/basic_pager.rb +0 -5
- data/examples/markdown.rb +0 -7
- data/examples/pager.rb +0 -7
- data/examples/system_pager.rb +0 -7
- data/spec/spec_helper.rb +0 -45
- data/spec/unit/basic/page_spec.rb +0 -141
- data/spec/unit/null/page_spec.rb +0 -23
- data/spec/unit/page_spec.rb +0 -40
- data/spec/unit/system/command_exists_spec.rb +0 -15
- data/spec/unit/system/executables_spec.rb +0 -11
- data/spec/unit/system/find_executable_spec.rb +0 -50
- data/spec/unit/system/new_spec.rb +0 -21
- data/spec/unit/system/page_spec.rb +0 -21
- data/tasks/console.rake +0 -11
- data/tasks/coverage.rake +0 -11
- data/tasks/spec.rake +0 -29
- data/tty-pager.gemspec +0 -31
data/lib/tty/pager/system.rb
CHANGED
@@ -1,18 +1,20 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "open3"
|
4
|
+
|
5
|
+
require_relative "abstract"
|
4
6
|
|
5
7
|
module TTY
|
6
|
-
|
8
|
+
module Pager
|
7
9
|
# A system pager is used on systems where native
|
8
10
|
# pagination exists
|
9
11
|
#
|
10
12
|
# @api public
|
11
|
-
class SystemPager <
|
13
|
+
class SystemPager < Abstract
|
12
14
|
# Check if command exists
|
13
15
|
#
|
14
16
|
# @example
|
15
|
-
#
|
17
|
+
# command_exist?("less") # => true
|
16
18
|
#
|
17
19
|
# @param [String] command
|
18
20
|
# the command to check
|
@@ -20,46 +22,59 @@ module TTY
|
|
20
22
|
# @return [Boolean]
|
21
23
|
#
|
22
24
|
# @api private
|
23
|
-
def self.
|
24
|
-
|
25
|
+
def self.command_exist?(command)
|
26
|
+
exts = ENV.fetch("PATHEXT", "").split(::File::PATH_SEPARATOR)
|
27
|
+
ENV.fetch("PATH", "").split(File::PATH_SEPARATOR).any? do |dir|
|
28
|
+
file = ::File.join(dir, command)
|
29
|
+
::File.exist?(file) || exts.any? { |ext| ::File.exist?("#{file}#{ext}") }
|
30
|
+
end
|
25
31
|
end
|
26
32
|
|
27
33
|
# Run pager command silently with no input and capture output
|
28
34
|
#
|
29
|
-
# @return [
|
30
|
-
#
|
35
|
+
# @return [Boolean]
|
36
|
+
# true if command runs successfully, false otherwise
|
31
37
|
#
|
32
38
|
# @api private
|
33
39
|
def self.run_command(*args)
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
out.rewind
|
39
|
-
out.read
|
40
|
-
ensure
|
41
|
-
out.close
|
42
|
-
out.unlink
|
40
|
+
_, err, status = Open3.capture3(*args)
|
41
|
+
err.empty? && status.success?
|
42
|
+
rescue Errno::ENOENT
|
43
|
+
false
|
43
44
|
end
|
44
45
|
|
45
46
|
# List possible executables for output paging
|
46
47
|
#
|
48
|
+
# The UNIX systems often come with "pg" and "more" but no "less" utility.
|
49
|
+
# The Linux usually provides "less" and "more" pager, but often no "pg".
|
50
|
+
# MacOS comes with "less" and "more" pager and no "pg".
|
51
|
+
# Windows provides "more".
|
52
|
+
# The "more" pager is the oldest utility and thus most compatible
|
53
|
+
# with many systems.
|
54
|
+
#
|
47
55
|
# @return [Array[String]]
|
48
56
|
#
|
49
57
|
# @api private
|
50
58
|
def self.executables
|
51
|
-
[ENV[
|
52
|
-
|
53
|
-
|
59
|
+
[ENV["GIT_PAGER"], ENV["PAGER"], git_pager,
|
60
|
+
"less -r", "more -r", "most", "pg", "cat", "pager"].compact
|
61
|
+
end
|
62
|
+
|
63
|
+
# Finds git pager configuration
|
64
|
+
#
|
65
|
+
# @api private
|
66
|
+
def self.git_pager
|
67
|
+
command_exist?("git") ? `git config --get-all core.pager` : nil
|
54
68
|
end
|
69
|
+
private_class_method :git_pager
|
55
70
|
|
56
71
|
# Find first available termainal pager program executable
|
57
72
|
#
|
58
73
|
# @example Basic usage
|
59
|
-
# find_executable # =>
|
74
|
+
# find_executable # => "less"
|
60
75
|
#
|
61
76
|
# @example Usage with commands
|
62
|
-
# find_executable(
|
77
|
+
# find_executable("less", "cat") # => "less"
|
63
78
|
#
|
64
79
|
# @param [Array[String]] commands
|
65
80
|
#
|
@@ -71,7 +86,7 @@ module TTY
|
|
71
86
|
execs = commands.empty? ? executables : commands
|
72
87
|
execs
|
73
88
|
.compact.map(&:strip).reject(&:empty?).uniq
|
74
|
-
.find { |cmd|
|
89
|
+
.find { |cmd| command_exist?(cmd.split.first) }
|
75
90
|
end
|
76
91
|
|
77
92
|
# Check if command is available
|
@@ -80,7 +95,7 @@ module TTY
|
|
80
95
|
# available? # => true
|
81
96
|
#
|
82
97
|
# @example Usage with command
|
83
|
-
# available?(
|
98
|
+
# available?("less") # => true
|
84
99
|
#
|
85
100
|
# @return [Boolean]
|
86
101
|
#
|
@@ -91,60 +106,73 @@ module TTY
|
|
91
106
|
|
92
107
|
# Create a system pager
|
93
108
|
#
|
94
|
-
# @param [
|
95
|
-
# @option options [String] :command
|
109
|
+
# @param [String] :command
|
96
110
|
# the command to use for paging
|
97
111
|
#
|
98
112
|
# @api public
|
99
|
-
def initialize(**options)
|
100
|
-
super
|
113
|
+
def initialize(command: nil, **options)
|
114
|
+
super(**options)
|
115
|
+
@pager_io = nil
|
101
116
|
@pager_command = nil
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
" try using `BasicPager` instead." \
|
117
|
+
pager_command(*Array(command))
|
118
|
+
|
119
|
+
if pager_command.nil?
|
120
|
+
raise TTY::Pager::Error,
|
121
|
+
"#{self.class.name} cannot be used on your system due to " \
|
122
|
+
"lack of appropriate pager executable. Install `less` like " \
|
123
|
+
"pager or try using `BasicPager` instead."
|
110
124
|
end
|
111
125
|
end
|
112
126
|
|
113
|
-
#
|
127
|
+
# Send text to the pager process. Starts a new process if it hasn't been
|
128
|
+
# started yet.
|
114
129
|
#
|
115
|
-
# @
|
116
|
-
#
|
130
|
+
# @param [Array<String>] *args
|
131
|
+
# strings to send to the pager
|
117
132
|
#
|
118
|
-
# @
|
119
|
-
#
|
120
|
-
#
|
121
|
-
# @return [Boolean]
|
122
|
-
# the success status of launching a process
|
133
|
+
# @raise [PagerClosed]
|
134
|
+
# strings to send to the pager
|
123
135
|
#
|
124
136
|
# @api public
|
125
|
-
def
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
if !out.empty?
|
132
|
-
command = pager_command.split.first
|
133
|
-
end
|
137
|
+
def write(*args)
|
138
|
+
@pager_io ||= spawn_pager
|
139
|
+
@pager_io.write(*args)
|
140
|
+
self
|
141
|
+
end
|
142
|
+
alias << write
|
134
143
|
|
135
|
-
|
136
|
-
|
144
|
+
# Send a line of text, ending in a newline, to the pager process. Starts
|
145
|
+
# a new process if it hasn't been started yet.
|
146
|
+
#
|
147
|
+
# @raise [PagerClosed]
|
148
|
+
# if the pager was closed
|
149
|
+
#
|
150
|
+
# @return [SystemPager]
|
151
|
+
#
|
152
|
+
# @api public
|
153
|
+
def puts(text)
|
154
|
+
@pager_io ||= spawn_pager
|
155
|
+
@pager_io.puts(text)
|
156
|
+
self
|
157
|
+
end
|
137
158
|
|
138
|
-
|
139
|
-
|
159
|
+
# Stop the pager, wait for the process to finish. If no pager has been
|
160
|
+
# started, returns true.
|
161
|
+
#
|
162
|
+
# @return [Boolean]
|
163
|
+
# the exit status of the child process
|
164
|
+
#
|
165
|
+
# @api public
|
166
|
+
def close
|
167
|
+
return true unless @pager_io
|
140
168
|
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
# on jruby 9x waiting on pid raises
|
145
|
-
true
|
169
|
+
success = @pager_io.close
|
170
|
+
@pager_io = nil
|
171
|
+
success
|
146
172
|
end
|
147
173
|
|
174
|
+
private
|
175
|
+
|
148
176
|
# The pager command to run
|
149
177
|
#
|
150
178
|
# @return [String]
|
@@ -152,11 +180,70 @@ module TTY
|
|
152
180
|
#
|
153
181
|
# @api private
|
154
182
|
def pager_command(*commands)
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
183
|
+
if @pager_command && commands.empty?
|
184
|
+
@pager_command
|
185
|
+
else
|
186
|
+
@pager_command = self.class.find_executable(*commands)
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
# Spawn the pager process
|
191
|
+
#
|
192
|
+
# @return [PagerIO]
|
193
|
+
# A wrapper for the external pager
|
194
|
+
#
|
195
|
+
# @api private
|
196
|
+
def spawn_pager
|
197
|
+
# In case there's a previous pager running:
|
198
|
+
close
|
199
|
+
|
200
|
+
command = pager_command
|
201
|
+
status = self.class.run_command(command)
|
202
|
+
# Issue running command, e.g. unsupported flag, fallback to just command
|
203
|
+
unless status
|
204
|
+
command = pager_command.split.first
|
205
|
+
end
|
206
|
+
|
207
|
+
PagerIO.new(command)
|
208
|
+
end
|
209
|
+
|
210
|
+
# A wrapper for an external process.
|
211
|
+
#
|
212
|
+
# @api private
|
213
|
+
class PagerIO
|
214
|
+
def initialize(command)
|
215
|
+
@command = command
|
216
|
+
@io = IO.popen(@command, "w")
|
217
|
+
@pid = @io.pid
|
218
|
+
end
|
219
|
+
|
220
|
+
def write(*args)
|
221
|
+
io_call(:write, *args)
|
222
|
+
end
|
223
|
+
|
224
|
+
def puts(*args)
|
225
|
+
io_call(:puts, *args)
|
226
|
+
end
|
227
|
+
|
228
|
+
def close
|
229
|
+
return true if @io.closed?
|
230
|
+
|
231
|
+
@io.close
|
232
|
+
_, status = Process.waitpid2(@pid, Process::WNOHANG)
|
233
|
+
status.success?
|
234
|
+
rescue Errno::ECHILD, Errno::EPIPE
|
235
|
+
# on jruby 9x waiting on pid raises ECHILD
|
236
|
+
# on ruby 2.5/2.6, closing a closed pipe raises EPIPE
|
237
|
+
true
|
238
|
+
end
|
239
|
+
|
240
|
+
private
|
241
|
+
|
242
|
+
def io_call(method_name, *args)
|
243
|
+
@io.public_send(method_name, *args)
|
244
|
+
rescue Errno::EPIPE
|
245
|
+
raise PagerClosed.new("The pager process (`#{@command}`) was closed")
|
246
|
+
end
|
160
247
|
end
|
161
248
|
end # SystemPager
|
162
249
|
end # Pager
|
data/lib/tty/pager/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tty-pager
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.13.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Piotr Murach
|
8
8
|
autorequire:
|
9
|
-
bindir:
|
9
|
+
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-05-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: tty-screen
|
@@ -16,56 +16,28 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '0.
|
19
|
+
version: '0.8'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '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.4'
|
34
|
-
type: :runtime
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - "~>"
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: '0.4'
|
26
|
+
version: '0.8'
|
41
27
|
- !ruby/object:Gem::Dependency
|
42
28
|
name: strings
|
43
29
|
requirement: !ruby/object:Gem::Requirement
|
44
30
|
requirements:
|
45
31
|
- - "~>"
|
46
32
|
- !ruby/object:Gem::Version
|
47
|
-
version: 0.1.
|
33
|
+
version: 0.1.8
|
48
34
|
type: :runtime
|
49
35
|
prerelease: false
|
50
36
|
version_requirements: !ruby/object:Gem::Requirement
|
51
37
|
requirements:
|
52
38
|
- - "~>"
|
53
39
|
- !ruby/object:Gem::Version
|
54
|
-
version: 0.1.
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: bundler
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
58
|
-
requirements:
|
59
|
-
- - ">="
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: '0'
|
62
|
-
type: :development
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - ">="
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: '0'
|
40
|
+
version: 0.1.8
|
69
41
|
- !ruby/object:Gem::Dependency
|
70
42
|
name: rake
|
71
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -84,55 +56,46 @@ dependencies:
|
|
84
56
|
name: rspec
|
85
57
|
requirement: !ruby/object:Gem::Requirement
|
86
58
|
requirements:
|
87
|
-
- - "
|
59
|
+
- - ">="
|
88
60
|
- !ruby/object:Gem::Version
|
89
|
-
version: '3.
|
61
|
+
version: '3.0'
|
90
62
|
type: :development
|
91
63
|
prerelease: false
|
92
64
|
version_requirements: !ruby/object:Gem::Requirement
|
93
65
|
requirements:
|
94
|
-
- - "
|
66
|
+
- - ">="
|
95
67
|
- !ruby/object:Gem::Version
|
96
|
-
version: '3.
|
97
|
-
description:
|
98
|
-
interpreters.
|
68
|
+
version: '3.0'
|
69
|
+
description: A cross-platform terminal pager that works on all major Ruby interpreters.
|
99
70
|
email:
|
100
|
-
-
|
71
|
+
- piotr@piotrmurach.com
|
101
72
|
executables: []
|
102
73
|
extensions: []
|
103
|
-
extra_rdoc_files:
|
74
|
+
extra_rdoc_files:
|
75
|
+
- README.md
|
76
|
+
- CHANGELOG.md
|
77
|
+
- LICENSE.txt
|
104
78
|
files:
|
105
79
|
- CHANGELOG.md
|
106
80
|
- LICENSE.txt
|
107
81
|
- README.md
|
108
|
-
- Rakefile
|
109
|
-
- examples/basic_pager.rb
|
110
|
-
- examples/markdown.rb
|
111
|
-
- examples/pager.rb
|
112
|
-
- examples/system_pager.rb
|
113
82
|
- lib/tty-pager.rb
|
114
83
|
- lib/tty/pager.rb
|
84
|
+
- lib/tty/pager/abstract.rb
|
115
85
|
- lib/tty/pager/basic.rb
|
116
86
|
- lib/tty/pager/null.rb
|
117
87
|
- lib/tty/pager/system.rb
|
118
88
|
- lib/tty/pager/version.rb
|
119
|
-
- spec/spec_helper.rb
|
120
|
-
- spec/unit/basic/page_spec.rb
|
121
|
-
- spec/unit/null/page_spec.rb
|
122
|
-
- spec/unit/page_spec.rb
|
123
|
-
- spec/unit/system/command_exists_spec.rb
|
124
|
-
- spec/unit/system/executables_spec.rb
|
125
|
-
- spec/unit/system/find_executable_spec.rb
|
126
|
-
- spec/unit/system/new_spec.rb
|
127
|
-
- spec/unit/system/page_spec.rb
|
128
|
-
- tasks/console.rake
|
129
|
-
- tasks/coverage.rake
|
130
|
-
- tasks/spec.rake
|
131
|
-
- tty-pager.gemspec
|
132
89
|
homepage: https://piotrmurach.github.io/tty
|
133
90
|
licenses:
|
134
91
|
- MIT
|
135
|
-
metadata:
|
92
|
+
metadata:
|
93
|
+
allowed_push_host: https://rubygems.org
|
94
|
+
bug_tracker_uri: https://github.com/piotrmurach/tty-pager/issues
|
95
|
+
changelog_uri: https://github.com/piotrmurach/tty-pager/blob/master/CHANGELOG.md
|
96
|
+
documentation_uri: https://www.rubydoc.info/gems/tty-pager
|
97
|
+
homepage_uri: https://piotrmurach.github.io/tty
|
98
|
+
source_code_uri: https://github.com/piotrmurach/tty-pager
|
136
99
|
post_install_message:
|
137
100
|
rdoc_options: []
|
138
101
|
require_paths:
|
@@ -148,19 +111,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
148
111
|
- !ruby/object:Gem::Version
|
149
112
|
version: '0'
|
150
113
|
requirements: []
|
151
|
-
|
152
|
-
rubygems_version: 2.7.3
|
114
|
+
rubygems_version: 3.1.2
|
153
115
|
signing_key:
|
154
116
|
specification_version: 4
|
155
|
-
summary:
|
156
|
-
|
157
|
-
test_files:
|
158
|
-
- spec/spec_helper.rb
|
159
|
-
- spec/unit/basic/page_spec.rb
|
160
|
-
- spec/unit/null/page_spec.rb
|
161
|
-
- spec/unit/page_spec.rb
|
162
|
-
- spec/unit/system/command_exists_spec.rb
|
163
|
-
- spec/unit/system/executables_spec.rb
|
164
|
-
- spec/unit/system/find_executable_spec.rb
|
165
|
-
- spec/unit/system/new_spec.rb
|
166
|
-
- spec/unit/system/page_spec.rb
|
117
|
+
summary: A cross-platform terminal pager that works on all major Ruby interpreters.
|
118
|
+
test_files: []
|