yarsh 0.1.1 → 0.3.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/AGENTS.md +105 -20
- data/CHANGES.md +101 -12
- data/README.md +66 -2
- data/lib/yarsh/binding.rb +14 -0
- data/lib/yarsh/completion/bash_autocomplete.rb +139 -0
- data/lib/yarsh/completion/engine.rb +17 -0
- data/lib/yarsh/completion/gem_completion.rb +281 -0
- data/lib/yarsh/completion/help_completion.rb +105 -0
- data/lib/yarsh/completion/registry.rb +39 -0
- data/lib/yarsh/completion.rb +16 -0
- data/lib/yarsh/config.rb +3 -1
- data/lib/yarsh/help.rb +72 -0
- data/lib/yarsh/instance_methods.rb +23 -0
- data/lib/yarsh/multiline.rb +147 -0
- data/lib/yarsh/prompt.rb +9 -2
- data/lib/yarsh/shell.rb +243 -50
- data/lib/yarsh/version.rb +1 -1
- data/lib/yarsh.rb +22 -2
- metadata +10 -1
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'engine'
|
|
4
|
+
|
|
5
|
+
module Yarsh
|
|
6
|
+
module Completion
|
|
7
|
+
class GemCompletion < Engine
|
|
8
|
+
SUBCOMMANDS = %w[
|
|
9
|
+
build cert check cleanup contents dependency environment exec fetch
|
|
10
|
+
generate_index help info install list lock mirror open outdated owner
|
|
11
|
+
pristine push rdoc rebuild search server signin signout sources
|
|
12
|
+
specification stale uninstall unpack update which yank
|
|
13
|
+
].freeze
|
|
14
|
+
|
|
15
|
+
OPTIONS = {
|
|
16
|
+
'build' => %w[
|
|
17
|
+
--platform --force --strict -o --output
|
|
18
|
+
-h --help -V --verbose -q --quiet --silent --config-file
|
|
19
|
+
--backtrace --debug --norc
|
|
20
|
+
].freeze,
|
|
21
|
+
'cert' => %w[
|
|
22
|
+
-a --add -l --list -r --remove -b --build -C --certificate
|
|
23
|
+
-K --private-key -A --key-algorithm -s --sign -d --days -R --re-sign
|
|
24
|
+
-h --help -V --verbose -q --quiet --silent --config-file
|
|
25
|
+
--backtrace --debug --norc
|
|
26
|
+
].freeze,
|
|
27
|
+
'check' => %w[
|
|
28
|
+
-a --alien --doctor --dry-run --gems -v --version
|
|
29
|
+
-h --help -V --verbose -q --quiet --silent --config-file
|
|
30
|
+
--backtrace --debug --norc
|
|
31
|
+
].freeze,
|
|
32
|
+
'cleanup' => %w[
|
|
33
|
+
-n -d --dry-run -D --check-development --user-install --dryrun
|
|
34
|
+
-h --help -V --verbose -q --quiet --silent --config-file
|
|
35
|
+
--backtrace --debug --norc
|
|
36
|
+
].freeze,
|
|
37
|
+
'contents' => %w[
|
|
38
|
+
-v --version --all -s --spec-dir -l --lib-only --prefix --show-install-dir
|
|
39
|
+
-h --help -V --verbose -q --quiet --silent --config-file
|
|
40
|
+
--backtrace --debug --norc
|
|
41
|
+
].freeze,
|
|
42
|
+
'dependency' => %w[
|
|
43
|
+
-v --version --platform --prerelease -R --reverse-dependencies --pipe
|
|
44
|
+
-u --update-sources
|
|
45
|
+
-l --local -r --remote -b --both -B --bulk-threshold --clear-sources
|
|
46
|
+
-s --source -p --http-proxy
|
|
47
|
+
-h --help -V --verbose -q --quiet --silent --config-file
|
|
48
|
+
--backtrace --debug --norc
|
|
49
|
+
].freeze,
|
|
50
|
+
'environment' => %w[
|
|
51
|
+
-h --help -V --verbose -q --quiet --silent --config-file
|
|
52
|
+
--backtrace --debug --norc
|
|
53
|
+
].freeze,
|
|
54
|
+
'exec' => %w[
|
|
55
|
+
-v --version --prerelease -g --gem --conservative
|
|
56
|
+
-h --help -V --verbose -q --quiet --silent --config-file
|
|
57
|
+
--backtrace --debug --norc
|
|
58
|
+
].freeze,
|
|
59
|
+
'fetch' => %w[
|
|
60
|
+
-v --version --platform --prerelease --suggestions
|
|
61
|
+
-B --bulk-threshold -p --http-proxy -s --source --clear-sources
|
|
62
|
+
-h --help -V --verbose -q --quiet --silent --config-file
|
|
63
|
+
--backtrace --debug --norc
|
|
64
|
+
].freeze,
|
|
65
|
+
'generate_index' => %w[
|
|
66
|
+
-d --directory --modern --compact --update
|
|
67
|
+
-h --help -V --verbose -q --quiet --silent --config-file
|
|
68
|
+
--backtrace --debug --norc
|
|
69
|
+
].freeze,
|
|
70
|
+
'help' => %w[
|
|
71
|
+
-h --help -V --verbose -q --quiet --silent --config-file
|
|
72
|
+
--backtrace --debug --norc
|
|
73
|
+
].freeze,
|
|
74
|
+
'info' => %w[
|
|
75
|
+
-i --installed -I -v --version --versions -a --all -e --exact --prerelease
|
|
76
|
+
-u --update-sources
|
|
77
|
+
-l --local -r --remote -b --both -B --bulk-threshold --clear-sources
|
|
78
|
+
-s --source -p --http-proxy
|
|
79
|
+
-h --help -V --verbose -q --quiet --silent --config-file
|
|
80
|
+
--backtrace --debug --norc
|
|
81
|
+
].freeze,
|
|
82
|
+
'install' => %w[
|
|
83
|
+
--platform -v --version --prerelease
|
|
84
|
+
--default -u --update-sources
|
|
85
|
+
-i --install-dir -n --bindir -j --build-jobs --document --build-root
|
|
86
|
+
--vendor -N --no-document -E --env-shebang -f --force -w --wrappers
|
|
87
|
+
-P --trust-policy --ignore-dependencies --format-executable --user-install
|
|
88
|
+
--development --development-all --conservative --minimal-deps
|
|
89
|
+
--post-install-message -g --file --without --explain --lock
|
|
90
|
+
--suggestions --target-rbconfig
|
|
91
|
+
-l --local -r --remote -b --both -B --bulk-threshold --clear-sources
|
|
92
|
+
-s --source -p --http-proxy
|
|
93
|
+
-h --help -V --verbose -q --quiet --silent --config-file
|
|
94
|
+
--backtrace --debug --norc
|
|
95
|
+
].freeze,
|
|
96
|
+
'list' => %w[
|
|
97
|
+
-i --installed -I -v --version -d --details --versions -a --all -e --exact --prerelease
|
|
98
|
+
-u --update-sources
|
|
99
|
+
-l --local -r --remote -b --both -B --bulk-threshold --clear-sources
|
|
100
|
+
-s --source -p --http-proxy
|
|
101
|
+
-h --help -V --verbose -q --quiet --silent --config-file
|
|
102
|
+
--backtrace --debug --norc
|
|
103
|
+
].freeze,
|
|
104
|
+
'lock' => %w[
|
|
105
|
+
-s --strict
|
|
106
|
+
-h --help -V --verbose -q --quiet --silent --config-file
|
|
107
|
+
--backtrace --debug --norc
|
|
108
|
+
].freeze,
|
|
109
|
+
'mirror' => %w[
|
|
110
|
+
-h --help -V --verbose -q --quiet --silent --config-file
|
|
111
|
+
--backtrace --debug --norc
|
|
112
|
+
].freeze,
|
|
113
|
+
'open' => %w[
|
|
114
|
+
-e --editor -v --version
|
|
115
|
+
-h --help -V --verbose -q --quiet --silent --config-file
|
|
116
|
+
--backtrace --debug --norc
|
|
117
|
+
].freeze,
|
|
118
|
+
'outdated' => %w[
|
|
119
|
+
--platform
|
|
120
|
+
-u --update-sources
|
|
121
|
+
-l --local -r --remote -b --both -B --bulk-threshold --clear-sources
|
|
122
|
+
-s --source -p --http-proxy
|
|
123
|
+
-h --help -V --verbose -q --quiet --silent --config-file
|
|
124
|
+
--backtrace --debug --norc
|
|
125
|
+
].freeze,
|
|
126
|
+
'owner' => %w[
|
|
127
|
+
-k --key --otp -a --add -r --remove --host
|
|
128
|
+
-p --http-proxy
|
|
129
|
+
-h --help -V --verbose -q --quiet --silent --config-file
|
|
130
|
+
--backtrace --debug --norc
|
|
131
|
+
].freeze,
|
|
132
|
+
'pristine' => %w[
|
|
133
|
+
--all --skip --extensions --only-missing-extensions --only-executables
|
|
134
|
+
--only-plugins -E --env-shebang -i --install-dir -n --bindir -v --version
|
|
135
|
+
-h --help -V --verbose -q --quiet --silent --config-file
|
|
136
|
+
--backtrace --debug --norc
|
|
137
|
+
].freeze,
|
|
138
|
+
'push' => %w[
|
|
139
|
+
-k --key --otp --host --attestation
|
|
140
|
+
-p --http-proxy
|
|
141
|
+
-h --help -V --verbose -q --quiet --silent --config-file
|
|
142
|
+
--backtrace --debug --norc
|
|
143
|
+
].freeze,
|
|
144
|
+
'rdoc' => %w[
|
|
145
|
+
--all --rdoc --ri --overwrite -v --version
|
|
146
|
+
-h --help -V --verbose -q --quiet --silent --config-file
|
|
147
|
+
--backtrace --debug --norc
|
|
148
|
+
].freeze,
|
|
149
|
+
'rebuild' => %w[
|
|
150
|
+
--diff --force --strict --source --original --gemspec -C
|
|
151
|
+
-h --help -V --verbose -q --quiet --silent --config-file
|
|
152
|
+
--backtrace --debug --norc
|
|
153
|
+
].freeze,
|
|
154
|
+
'search' => %w[
|
|
155
|
+
-i --installed -I -v --version -d --details --versions -a --all -e --exact --prerelease
|
|
156
|
+
-u --update-sources
|
|
157
|
+
-l --local -r --remote -b --both -B --bulk-threshold --clear-sources
|
|
158
|
+
-s --source -p --http-proxy
|
|
159
|
+
-h --help -V --verbose -q --quiet --silent --config-file
|
|
160
|
+
--backtrace --debug --norc
|
|
161
|
+
].freeze,
|
|
162
|
+
'server' => %w[
|
|
163
|
+
-h --help -V --verbose -q --quiet --silent --config-file
|
|
164
|
+
--backtrace --debug --norc
|
|
165
|
+
].freeze,
|
|
166
|
+
'signin' => %w[
|
|
167
|
+
--host --otp
|
|
168
|
+
-h --help -V --verbose -q --quiet --silent --config-file
|
|
169
|
+
--backtrace --debug --norc
|
|
170
|
+
].freeze,
|
|
171
|
+
'signout' => %w[
|
|
172
|
+
-h --help -V --verbose -q --quiet --silent --config-file
|
|
173
|
+
--backtrace --debug --norc
|
|
174
|
+
].freeze,
|
|
175
|
+
'sources' => %w[
|
|
176
|
+
-a --add --append --prepend -l --list -r --remove -c --clear-all
|
|
177
|
+
-u --update -f --force
|
|
178
|
+
-p --http-proxy
|
|
179
|
+
-h --help -V --verbose -q --quiet --silent --config-file
|
|
180
|
+
--backtrace --debug --norc
|
|
181
|
+
].freeze,
|
|
182
|
+
'specification' => %w[
|
|
183
|
+
-v --version --platform --prerelease --all --ruby --yaml --marshal
|
|
184
|
+
-u --update-sources
|
|
185
|
+
-l --local -r --remote -b --both -B --bulk-threshold --clear-sources
|
|
186
|
+
-s --source -p --http-proxy
|
|
187
|
+
-h --help -V --verbose -q --quiet --silent --config-file
|
|
188
|
+
--backtrace --debug --norc
|
|
189
|
+
].freeze,
|
|
190
|
+
'stale' => %w[
|
|
191
|
+
-h --help -V --verbose -q --quiet --silent --config-file
|
|
192
|
+
--backtrace --debug --norc
|
|
193
|
+
].freeze,
|
|
194
|
+
'uninstall' => %w[
|
|
195
|
+
-a --all -I --ignore-dependencies -D --check-development -x --executables
|
|
196
|
+
-i --install-dir -n --bindir --user-install --format-executable --force
|
|
197
|
+
--abort-on-dependent -v --version --platform --vendor
|
|
198
|
+
-h --help -V --verbose -q --quiet --silent --config-file
|
|
199
|
+
--backtrace --debug --norc
|
|
200
|
+
].freeze,
|
|
201
|
+
'unpack' => %w[
|
|
202
|
+
--target --spec -v --version
|
|
203
|
+
-P --trust-policy
|
|
204
|
+
-h --help -V --verbose -q --quiet --silent --config-file
|
|
205
|
+
--backtrace --debug --norc
|
|
206
|
+
].freeze,
|
|
207
|
+
'update' => %w[
|
|
208
|
+
--system --platform --prerelease
|
|
209
|
+
--default -u --update-sources
|
|
210
|
+
-i --install-dir -n --bindir -j --build-jobs --document --build-root
|
|
211
|
+
--vendor -N --no-document -E --env-shebang -f --force -w --wrappers
|
|
212
|
+
-P --trust-policy --ignore-dependencies --format-executable --user-install
|
|
213
|
+
--development --development-all --conservative --minimal-deps
|
|
214
|
+
--post-install-message -g --file --without --explain --lock
|
|
215
|
+
--suggestions --target-rbconfig
|
|
216
|
+
-l --local -r --remote -b --both -B --bulk-threshold --clear-sources
|
|
217
|
+
-s --source -p --http-proxy
|
|
218
|
+
-h --help -V --verbose -q --quiet --silent --config-file
|
|
219
|
+
--backtrace --debug --norc
|
|
220
|
+
].freeze,
|
|
221
|
+
'which' => %w[
|
|
222
|
+
-a --all -g --gems-first
|
|
223
|
+
-h --help -V --verbose -q --quiet --silent --config-file
|
|
224
|
+
--backtrace --debug --norc
|
|
225
|
+
].freeze,
|
|
226
|
+
'yank' => %w[
|
|
227
|
+
-v --version --platform --otp --host -k --key
|
|
228
|
+
-h --help -V --verbose -q --quiet --silent --config-file
|
|
229
|
+
--backtrace --debug --norc
|
|
230
|
+
].freeze
|
|
231
|
+
}.freeze
|
|
232
|
+
|
|
233
|
+
GEM_NAME_SUBCOMMANDS = %w[
|
|
234
|
+
info uninstall open contents check cleanup pristine rdoc specification dependency
|
|
235
|
+
].freeze
|
|
236
|
+
|
|
237
|
+
def supports?(command)
|
|
238
|
+
command.to_s.strip.split(/\s+/).first == 'gem'
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
def complete(command, word, args = [])
|
|
242
|
+
return [] unless supports?(command)
|
|
243
|
+
|
|
244
|
+
words = word.strip.split(/\s+/)
|
|
245
|
+
words.shift if words.first == 'gem'
|
|
246
|
+
|
|
247
|
+
has_trailing_space = word.end_with?(' ')
|
|
248
|
+
|
|
249
|
+
if words.empty?
|
|
250
|
+
return SUBCOMMANDS.dup
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
if words.size == 1 && !has_trailing_space
|
|
254
|
+
prefix = words.first
|
|
255
|
+
return SUBCOMMANDS.select { |s| s.start_with?(prefix) }
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
subcommand = words.first
|
|
259
|
+
return [] unless OPTIONS.key?(subcommand)
|
|
260
|
+
|
|
261
|
+
prefix = has_trailing_space ? '' : words.last
|
|
262
|
+
|
|
263
|
+
if prefix.start_with?('-')
|
|
264
|
+
OPTIONS[subcommand].select { |o| o.start_with?(prefix) }
|
|
265
|
+
elsif GEM_NAME_SUBCOMMANDS.include?(subcommand)
|
|
266
|
+
installed_gems.select { |g| g.start_with?(prefix) }
|
|
267
|
+
else
|
|
268
|
+
OPTIONS[subcommand].select { |o| o.start_with?(prefix) }
|
|
269
|
+
end
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
private
|
|
273
|
+
|
|
274
|
+
def installed_gems
|
|
275
|
+
Gem::Specification.map(&:name).uniq.sort
|
|
276
|
+
rescue
|
|
277
|
+
[]
|
|
278
|
+
end
|
|
279
|
+
end
|
|
280
|
+
end
|
|
281
|
+
end
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'shellwords'
|
|
4
|
+
require_relative 'engine'
|
|
5
|
+
|
|
6
|
+
module Yarsh
|
|
7
|
+
module Completion
|
|
8
|
+
class HelpCompletion < Engine
|
|
9
|
+
attr_reader :cache
|
|
10
|
+
|
|
11
|
+
def initialize
|
|
12
|
+
@cache = {}
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def complete(command, word, args = [])
|
|
16
|
+
command = command.strip
|
|
17
|
+
return [] if command.nil? || command.empty?
|
|
18
|
+
cmd = command.split(/\s+/).first
|
|
19
|
+
return [] if cmd.nil? || cmd.empty?
|
|
20
|
+
return [] unless command_exists?(cmd)
|
|
21
|
+
|
|
22
|
+
# Skip privileged commands — running --help would prompt for password
|
|
23
|
+
return [] if PRIVILEGED_COMMANDS.include?(cmd)
|
|
24
|
+
|
|
25
|
+
# Use full word for parse_help only if it starts with the command
|
|
26
|
+
# (e.g., word="docker compose u" starts with command="docker")
|
|
27
|
+
help_cmd = if word.strip.start_with?(cmd)
|
|
28
|
+
word.strip
|
|
29
|
+
else
|
|
30
|
+
command
|
|
31
|
+
end
|
|
32
|
+
options = parse_help(help_cmd)
|
|
33
|
+
return [] if options.nil? || options.empty?
|
|
34
|
+
|
|
35
|
+
prefix = word.strip.split(/\s+/).last
|
|
36
|
+
return options if prefix == help_cmd || prefix == cmd
|
|
37
|
+
|
|
38
|
+
options.select { |opt| opt.start_with?(prefix) }
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def supports?(command)
|
|
42
|
+
return false if command.nil? || command.empty?
|
|
43
|
+
cmd = command.strip.split(/\s+/).first
|
|
44
|
+
command_exists?(cmd)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def parse_help(command)
|
|
48
|
+
return @cache[command][:options] if @cache.key?(command) && !expired?(@cache[command])
|
|
49
|
+
|
|
50
|
+
options = do_parse_help(command)
|
|
51
|
+
@cache[command] = { options: options, fetched_at: Time.now.to_i }
|
|
52
|
+
options
|
|
53
|
+
rescue
|
|
54
|
+
[]
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def cache_info(command)
|
|
58
|
+
@cache[command]
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def clear_cache
|
|
62
|
+
@cache.clear
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
private
|
|
66
|
+
|
|
67
|
+
def command_exists?(command)
|
|
68
|
+
cmd = command.split(/\s+/).first
|
|
69
|
+
!`which #{Shellwords.shellescape(cmd)} 2>/dev/null`.strip.empty?
|
|
70
|
+
rescue
|
|
71
|
+
false
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def expired?(entry)
|
|
75
|
+
return true unless entry[:fetched_at]
|
|
76
|
+
(Time.now.to_i - entry[:fetched_at]) > CACHE_TTL
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def do_parse_help(command)
|
|
80
|
+
escaped = command.split(/\s+/).map { |w| Shellwords.shellescape(w) }.join(' ')
|
|
81
|
+
output = `#{escaped} --help 2>&1`.strip
|
|
82
|
+
return [] if output.empty? || output.include?("command not found") || output.include?("No such file")
|
|
83
|
+
|
|
84
|
+
options = []
|
|
85
|
+
output.each_line do |line|
|
|
86
|
+
cmd_match = line.match(/^\s{2}([a-zA-Z][a-zA-Z0-9-]*)/)
|
|
87
|
+
options << cmd_match[1] if cmd_match && !options.include?(cmd_match[1])
|
|
88
|
+
|
|
89
|
+
line.strip!
|
|
90
|
+
next if line.empty?
|
|
91
|
+
|
|
92
|
+
matches = line.scan(/(?:^|[\s|\]\[])(-{1,2}[a-zA-Z][a-zA-Z0-9-]*)/)
|
|
93
|
+
matches.each do |m|
|
|
94
|
+
opt = m.first
|
|
95
|
+
next if opt.empty?
|
|
96
|
+
options << opt unless options.include?(opt)
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
options.uniq.sort
|
|
100
|
+
rescue
|
|
101
|
+
[]
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'engine'
|
|
4
|
+
|
|
5
|
+
module Yarsh
|
|
6
|
+
module Completion
|
|
7
|
+
class Registry
|
|
8
|
+
def initialize
|
|
9
|
+
@engines = []
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def register(engine)
|
|
13
|
+
@engines << engine
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def complete(command, word, args = [])
|
|
17
|
+
return [] if command.nil? || command.empty?
|
|
18
|
+
return [] if word.nil?
|
|
19
|
+
|
|
20
|
+
@engines.each do |engine|
|
|
21
|
+
next unless engine.supports?(command)
|
|
22
|
+
result = engine.complete(command, word, args)
|
|
23
|
+
return result unless result.nil? || result.empty?
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
[]
|
|
27
|
+
rescue
|
|
28
|
+
[]
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def find_engine(command)
|
|
32
|
+
@engines.each do |engine|
|
|
33
|
+
return engine if engine.supports?(command)
|
|
34
|
+
end
|
|
35
|
+
nil
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'fileutils'
|
|
4
|
+
|
|
5
|
+
module Yarsh
|
|
6
|
+
module Completion
|
|
7
|
+
BASE_DIR = '/usr/share/bash-completion/completions'
|
|
8
|
+
CACHE_DIR = File.expand_path('~/.yarsh/completion_cache')
|
|
9
|
+
CACHE_TTL = 3600
|
|
10
|
+
|
|
11
|
+
def self.cache_dir
|
|
12
|
+
FileUtils.mkdir_p(CACHE_DIR) unless File.exist?(CACHE_DIR)
|
|
13
|
+
CACHE_DIR
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
data/lib/yarsh/config.rb
CHANGED
|
@@ -13,12 +13,14 @@ module Yarsh
|
|
|
13
13
|
include Singleton
|
|
14
14
|
|
|
15
15
|
attr_reader :aliases, :log_level
|
|
16
|
-
attr_accessor :logger
|
|
16
|
+
attr_accessor :logger, :autocompletion, :ruby_completion
|
|
17
17
|
|
|
18
18
|
def initialize
|
|
19
19
|
@aliases = {}
|
|
20
20
|
@prompt = nil
|
|
21
21
|
@logger = Logger.new($stdout, level: Logger::UNKNOWN)
|
|
22
|
+
@autocompletion = true
|
|
23
|
+
@ruby_completion = true
|
|
22
24
|
end
|
|
23
25
|
|
|
24
26
|
def log_level=(level)
|
data/lib/yarsh/help.rb
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
module Yarsh
|
|
2
|
+
module Help
|
|
3
|
+
class Command
|
|
4
|
+
MINIMAL_WIDTH = 5
|
|
5
|
+
|
|
6
|
+
def initialize(screen_width, cursor_pos_to_render, autocomplete_dialog)
|
|
7
|
+
@x = cursor_pos_to_render.x + autocomplete_dialog.width + 1
|
|
8
|
+
@y = cursor_pos_to_render.y
|
|
9
|
+
@width = screen_width - @x
|
|
10
|
+
@whatis = nil
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def info(command)
|
|
14
|
+
@info = `whatis #{command} 2>&1`
|
|
15
|
+
return false unless $?.success?
|
|
16
|
+
|
|
17
|
+
@info = @info.split('- ', 2).last.strip
|
|
18
|
+
rescue StandardError => e
|
|
19
|
+
debug("Error during whatis: #{e.message}")
|
|
20
|
+
false
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def render_dialog
|
|
24
|
+
return nil unless info_and_width?
|
|
25
|
+
|
|
26
|
+
Reline::DialogRenderInfo.new(
|
|
27
|
+
contents: format_output,
|
|
28
|
+
pos: Reline::CursorPos.new(@x, @y - 1),
|
|
29
|
+
width: @width,
|
|
30
|
+
height: height + 1,
|
|
31
|
+
face: :completion_dialog
|
|
32
|
+
)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
private
|
|
36
|
+
|
|
37
|
+
def format_output
|
|
38
|
+
return nil unless info_and_width?
|
|
39
|
+
|
|
40
|
+
dialog_line = []
|
|
41
|
+
line_size = 0
|
|
42
|
+
dialog_content = []
|
|
43
|
+
words = @info.split(' ')
|
|
44
|
+
words.each_with_index do |word, i|
|
|
45
|
+
dialog_line << word
|
|
46
|
+
line_size += word.size + 1
|
|
47
|
+
if i + 1 == words.size
|
|
48
|
+
if line_size >= @width
|
|
49
|
+
dialog_content << dialog_line[0..-2].join(' ').strip << dialog_line.last
|
|
50
|
+
next
|
|
51
|
+
end
|
|
52
|
+
dialog_content << dialog_line.join(' ').strip && next
|
|
53
|
+
end
|
|
54
|
+
next unless line_size >= @width
|
|
55
|
+
|
|
56
|
+
dialog_content << dialog_line[0..-2].join(' ').strip
|
|
57
|
+
line_size = dialog_line.last.size
|
|
58
|
+
dialog_line = [dialog_line.last]
|
|
59
|
+
end
|
|
60
|
+
dialog_content
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def height
|
|
64
|
+
@height ||= !info_and_width? ? nil : @info.size / @width
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def info_and_width?
|
|
68
|
+
@info && @width && @width > MINIMAL_WIDTH
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
@@ -8,6 +8,29 @@ module Yarsh
|
|
|
8
8
|
Config.instance.add_alias(new_name, command)
|
|
9
9
|
end
|
|
10
10
|
|
|
11
|
+
# Executes a shell line from inside a multiline Ruby buffer. Shell lines
|
|
12
|
+
# are rewritten to __sh__(...) by Yarsh::Multiline.transform.
|
|
13
|
+
def __sh__(command)
|
|
14
|
+
shell = Yarsh.current_shell
|
|
15
|
+
raise Error, 'No active Yarsh shell' if shell.nil?
|
|
16
|
+
|
|
17
|
+
shell.send(:__sh_exec, command)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def __yarsh__(exp, binding = nil)
|
|
21
|
+
shell = Yarsh.current_shell
|
|
22
|
+
raise Error, 'No active Yarsh shell' if shell.nil?
|
|
23
|
+
|
|
24
|
+
current_bind = nil
|
|
25
|
+
if binding
|
|
26
|
+
current_bind = shell.bind
|
|
27
|
+
shell.bind = binding
|
|
28
|
+
end
|
|
29
|
+
result = shell.send(:yarsh_eval, exp)
|
|
30
|
+
shell.bind = current_bind if binding
|
|
31
|
+
result
|
|
32
|
+
end
|
|
33
|
+
|
|
11
34
|
def source(filename)
|
|
12
35
|
load(filename, Yarsh::InstanceMethods)
|
|
13
36
|
end
|