squared 0.8.8 → 0.9.0.pre1
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 +34 -78
- data/README.md +156 -124
- data/exe/sqd +224 -0
- data/lib/squared/common/base.rb +7 -5
- data/lib/squared/common/format.rb +9 -4
- data/lib/squared/common/prompt.rb +65 -33
- data/lib/squared/common/shell.rb +3 -1
- data/lib/squared/common/system.rb +2 -9
- data/lib/squared/config.rb +3 -3
- data/lib/squared/version.rb +1 -1
- data/lib/squared/workspace/application.rb +33 -44
- data/lib/squared/workspace/project/base.rb +105 -62
- data/lib/squared/workspace/project/docker.rb +95 -46
- data/lib/squared/workspace/project/git.rb +69 -100
- data/lib/squared/workspace/project/node.rb +52 -73
- data/lib/squared/workspace/project/python.rb +128 -96
- data/lib/squared/workspace/project/ruby.rb +74 -73
- data/lib/squared/workspace/project/support/class.rb +1 -1
- data/lib/squared/workspace/project/support/optionpartition.rb +33 -47
- data/lib/squared/workspace/repo.rb +5 -5
- data/lib/squared/workspace/series.rb +4 -2
- data/squared.gemspec +7 -5
- metadata +21 -5
data/exe/sqd
ADDED
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
$:.unshift(File.expand_path('../lib', __dir__)) if File.exist?(File.expand_path('../squared.gemspec', __dir__))
|
|
5
|
+
|
|
6
|
+
require 'squared'
|
|
7
|
+
require 'rake'
|
|
8
|
+
require 'optparse'
|
|
9
|
+
|
|
10
|
+
class SqdParser < OptionParser
|
|
11
|
+
include Squared::Common::Format
|
|
12
|
+
include Utils
|
|
13
|
+
|
|
14
|
+
attr_reader :options, :global
|
|
15
|
+
|
|
16
|
+
def initialize(*)
|
|
17
|
+
super
|
|
18
|
+
@options = { 'project-args': [], 'project-env': [] }
|
|
19
|
+
@global = []
|
|
20
|
+
@program_name = 'squared'
|
|
21
|
+
@raise_unknown = false
|
|
22
|
+
@require_exact = true
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def parse_global(list, assert:)
|
|
26
|
+
raise ArgumentError, "cannot be used with --#{assert}" if options.key?(assert)
|
|
27
|
+
|
|
28
|
+
ARGV.each_with_index do |val, index|
|
|
29
|
+
if val == '--'
|
|
30
|
+
separator!(index: index)
|
|
31
|
+
break
|
|
32
|
+
end
|
|
33
|
+
next if val.start_with?('-') || val.include?(':') || val.empty?
|
|
34
|
+
|
|
35
|
+
global.concat(list.map { |name| "#{val}:#{name}" })
|
|
36
|
+
ARGV[index] = ''
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def parse_common(list, session:, arg:)
|
|
41
|
+
if list && !list.include?('*')
|
|
42
|
+
session[arg].merge!(list.to_h { |key| [key, 'true'] })
|
|
43
|
+
else
|
|
44
|
+
session[arg] = Hash.new('true')
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def banner_set(val, session:)
|
|
49
|
+
session[:BANNER] = val
|
|
50
|
+
ENV['BANNER'] = val ? 'true' : 'false'
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def color_set(val, session:)
|
|
54
|
+
if (session[:COLOR] = val)
|
|
55
|
+
enable_aixterm
|
|
56
|
+
enable_drawing
|
|
57
|
+
else
|
|
58
|
+
enable_drawing false
|
|
59
|
+
Squared::Common.const_get(:VAR)[:colors].freeze
|
|
60
|
+
end
|
|
61
|
+
ENV['NO_COLOR'] = val ? nil : '1'
|
|
62
|
+
ENV['FORCE_COLOR'] = val ? '2' : '0'
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def run
|
|
66
|
+
parse!(into: options)
|
|
67
|
+
if (project = options[:project])
|
|
68
|
+
pattern, project = project.partition do |val|
|
|
69
|
+
next true if val == '*'
|
|
70
|
+
|
|
71
|
+
val = ".#{val}" if val.start_with?('*')
|
|
72
|
+
val.match?(/[*+\[(]|(?<!\\)\.\.|\{\d+\}/) && Regexp.new(val)
|
|
73
|
+
rescue RegexpError
|
|
74
|
+
false
|
|
75
|
+
end
|
|
76
|
+
pattern.each do |val|
|
|
77
|
+
val = if val == '*'
|
|
78
|
+
'[^:]+'
|
|
79
|
+
else
|
|
80
|
+
val.sub(/^\*/, '.*')
|
|
81
|
+
.sub(/(?<!\.)\*$/, '.*')
|
|
82
|
+
.gsub(/\.([*+])/, '[^:]\1?')
|
|
83
|
+
end
|
|
84
|
+
IO.popen("rake -T \"^#{val}:\"").each { |line| project << $1 if line =~ /\Arake (#{val}):/o }
|
|
85
|
+
end
|
|
86
|
+
exit 1 if project.empty? && !pattern.empty?
|
|
87
|
+
project.uniq!
|
|
88
|
+
options[:'project-env'].each do |val|
|
|
89
|
+
n = val.index('=')
|
|
90
|
+
key = val[...n]
|
|
91
|
+
val = val[n.succ..].stripquote
|
|
92
|
+
project.each { |name| ENV["#{key}_#{env_key(name.split(':').first)}"] = val }
|
|
93
|
+
end
|
|
94
|
+
ARGV.each_with_index do |val, index|
|
|
95
|
+
if val == '--'
|
|
96
|
+
separator!(index: index)
|
|
97
|
+
break
|
|
98
|
+
end
|
|
99
|
+
next unless val.start_with?(':')
|
|
100
|
+
|
|
101
|
+
args = options[:'project-args'].shift
|
|
102
|
+
global.concat(project.map { |name| "#{name}#{val}#{"[#{args}]" if args}" })
|
|
103
|
+
ARGV[index] = ''
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
ARGV.reject!(&:empty?)
|
|
107
|
+
Rake.application.run(global.concat(ARGV))
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def separator!(index:)
|
|
111
|
+
ARGV[index] = '' if ARGV.grep('--').size > 1
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def error_exit(*val, hint)
|
|
115
|
+
raise OptionParser::InvalidArgument, message(*val, hint: hint)
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
SqdParser.new do |sqd|
|
|
120
|
+
session = Squared::Common::ARG
|
|
121
|
+
sqd.banner = 'Usage: sqd [options] [rake options] [global...] [:targets...] -- [rake targets...]'
|
|
122
|
+
sqd.separator ''
|
|
123
|
+
sqd.on('-R', '--ref STR,STR', Array, 'Run global commands by class reference') do |val|
|
|
124
|
+
sqd.parse_global(val, assert: :group)
|
|
125
|
+
session[:APP][:series_ref_min] = 1
|
|
126
|
+
end
|
|
127
|
+
sqd.on('-G', '--group STR,STR', Array, 'Run global commands by project group') do |val|
|
|
128
|
+
sqd.parse_global(val, assert: :ref)
|
|
129
|
+
end
|
|
130
|
+
sqd.separator ''
|
|
131
|
+
sqd.on('-P', '--project STR,PAT', Array, 'Run project commands with common arguments')
|
|
132
|
+
sqd.on('-a', '--project-args STR,STR', 'Provide command arguments for :targets (multiple)') do |val|
|
|
133
|
+
sqd.options[:'project-args'] << val
|
|
134
|
+
end
|
|
135
|
+
sqd.on('-e', '--project-env KEY=STR', 'Provide command ENV variables for :targets (multiple)') do |val|
|
|
136
|
+
sqd.error_exit('missing value', "#{val}=") unless val.include?('=')
|
|
137
|
+
|
|
138
|
+
sqd.options[:'project-env'] << val
|
|
139
|
+
end
|
|
140
|
+
sqd.separator ''
|
|
141
|
+
sqd.on('-s', '--[no-]strict', 'Do not run commands with invalid arguments') do |val|
|
|
142
|
+
session[:STRICT] = val
|
|
143
|
+
ENV['STRICT'] = val ? 'true' : 'false'
|
|
144
|
+
end
|
|
145
|
+
sqd.on('--update', 'Use update strategy for applicable commands') do
|
|
146
|
+
ENV['UPDATE'] = 'true'
|
|
147
|
+
end
|
|
148
|
+
sqd.on('-F', '--force [STR,STR]', Array, 'Enable force through ENV by application') do |val|
|
|
149
|
+
sqd.parse_common(val, session: session, arg: :FORCE)
|
|
150
|
+
end
|
|
151
|
+
sqd.on('-y', '--yes [STR,STR]', Array, 'Enable auto-approve through ENV by application') do |val|
|
|
152
|
+
sqd.parse_common(val, session: session, arg: :YES)
|
|
153
|
+
end
|
|
154
|
+
sqd.on('-d', '--dry-run', 'Run commands without any modifying actions') do
|
|
155
|
+
ENV['DRY_RUN'] = 'true'
|
|
156
|
+
end
|
|
157
|
+
sqd.separator ''
|
|
158
|
+
sqd.on('-S', '--select PAGE:CHOICE', 'Prompt menu selection pagination limits') do |val|
|
|
159
|
+
page, choice = val.split(/\D/, 2).map(&:to_i)
|
|
160
|
+
sqd.error_exit('not an integer', val) if choice.nil? ? page == 0 : choice == 0
|
|
161
|
+
|
|
162
|
+
session[:PAGE] = page if page > 0
|
|
163
|
+
session[:CHOICE] = choice if choice.to_i > 0
|
|
164
|
+
ENV['SELECT'] = "#{page}:#{choice}"
|
|
165
|
+
end
|
|
166
|
+
sqd.separator ''
|
|
167
|
+
sqd.on('-p', '--pipe 0|1|2', Integer, 'Set file descriptor for communication') do |val|
|
|
168
|
+
sqd.error_exit('out of range', val) unless val.between?(0, 2)
|
|
169
|
+
|
|
170
|
+
session[:PIPE] = val
|
|
171
|
+
end
|
|
172
|
+
sqd.on('-o', '--pipe-out FILE', 'Write command data stream to a file') do |val|
|
|
173
|
+
sqd.error_exit("missing an explicit \".#{File::SEPARATOR}\"", val) unless val.include?(File::SEPARATOR)
|
|
174
|
+
|
|
175
|
+
session[:OUT] = val
|
|
176
|
+
end
|
|
177
|
+
sqd.on('--fail 0..4', Integer, 'Set application exception level') do |val|
|
|
178
|
+
sqd.error_exit('out of range', val) unless val.between?(0, 4)
|
|
179
|
+
|
|
180
|
+
session[:FAIL] = val
|
|
181
|
+
end
|
|
182
|
+
%i[debug info warn error fatal].then do |state|
|
|
183
|
+
values = state + (0..4).map(&:to_s)
|
|
184
|
+
sqd.on('--log-level SEVERITY', values, "Set logger and exception state (#{state.join(', ')})") do |val|
|
|
185
|
+
require 'logger'
|
|
186
|
+
severity = case val
|
|
187
|
+
when :debug then Logger::DEBUG
|
|
188
|
+
when :info then Logger::INFO
|
|
189
|
+
when :warn then Logger::WARN
|
|
190
|
+
when :error then Logger::ERROR
|
|
191
|
+
when :fatal then Logger::FATAL
|
|
192
|
+
else
|
|
193
|
+
val.to_i
|
|
194
|
+
end
|
|
195
|
+
session[:LEVEL] = severity
|
|
196
|
+
ENV['LOG_LEVEL'] = severity.to_s
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
sqd.separator ''
|
|
200
|
+
sqd.on('--[no-]banner', 'Display executing command attributes') do |val|
|
|
201
|
+
sqd.banner_set(val, session: session)
|
|
202
|
+
end
|
|
203
|
+
sqd.on('-x', '--[no-]color', 'Use enhanced styling for terminal output') do |val|
|
|
204
|
+
sqd.color_set(val, session: session)
|
|
205
|
+
end
|
|
206
|
+
sqd.on('-X', '--plain', 'Disable banner and styling for all commands') do
|
|
207
|
+
sqd.banner_set(false, session: session)
|
|
208
|
+
sqd.color_set(false, session: session)
|
|
209
|
+
end
|
|
210
|
+
sqd.on('-v', '--verbose', 'Increase output verbosity (multiple)') do
|
|
211
|
+
unless session[:VERBOSE]
|
|
212
|
+
session[:VERBOSE] = $VERBOSE ? 1 : 0
|
|
213
|
+
sqd.global.unshift('--verbose')
|
|
214
|
+
end
|
|
215
|
+
ENV['VERBOSE'] = (session[:VERBOSE] += 1).to_s
|
|
216
|
+
end
|
|
217
|
+
sqd.on('--version', 'Print the current version') do
|
|
218
|
+
puts Squared::VERSION
|
|
219
|
+
exit 0
|
|
220
|
+
end
|
|
221
|
+
sqd.on('-h', '--help', 'Print the command line options') do
|
|
222
|
+
sqd.help_exit
|
|
223
|
+
end
|
|
224
|
+
end.run
|
data/lib/squared/common/base.rb
CHANGED
|
@@ -11,14 +11,17 @@ module Squared
|
|
|
11
11
|
COMMON: true,
|
|
12
12
|
VERBOSE: nil,
|
|
13
13
|
STRICT: false,
|
|
14
|
+
FORCE: {},
|
|
15
|
+
YES: {},
|
|
16
|
+
APP: {},
|
|
14
17
|
BANNER: true,
|
|
15
|
-
|
|
16
|
-
|
|
18
|
+
PAGE: 20,
|
|
19
|
+
CHOICE: 100,
|
|
17
20
|
QUOTE: "'",
|
|
18
21
|
SPACE: ' => ',
|
|
19
22
|
SUCCESS: 'Success',
|
|
20
|
-
GRAPH: %w[| - | \\ -]
|
|
21
|
-
BORDER: %w[| - - - - - | | - -]
|
|
23
|
+
GRAPH: %w[| - | \\ -],
|
|
24
|
+
BORDER: %w[| - - - - - | | - -],
|
|
22
25
|
VIEW: 'view',
|
|
23
26
|
LEVEL: ENV.fetch('LOG_LEVEL', 0).to_i,
|
|
24
27
|
COLOR: ENV.fetch('NO_COLOR', '').empty?
|
|
@@ -102,7 +105,6 @@ module Squared
|
|
|
102
105
|
|
|
103
106
|
def __freeze__
|
|
104
107
|
PATH.freeze
|
|
105
|
-
ARG.each_value { |val| val.freeze if val.is_a?(::Hash) || val.is_a?(::Array) }
|
|
106
108
|
ARG.freeze
|
|
107
109
|
VAR.each_value(&:freeze)
|
|
108
110
|
VAR[:theme].each_value { |val| val.freeze.each_value(&:freeze) }
|
|
@@ -50,9 +50,14 @@ module Squared
|
|
|
50
50
|
self
|
|
51
51
|
end
|
|
52
52
|
|
|
53
|
-
def enable_drawing
|
|
54
|
-
|
|
55
|
-
|
|
53
|
+
def enable_drawing(state = true)
|
|
54
|
+
if state
|
|
55
|
+
ARG[:GRAPH] = BOX_GRAPH unless ARG[:GRAPH].frozen?
|
|
56
|
+
ARG[:BORDER] = BOX_BORDER unless ARG[:BORDER].frozen?
|
|
57
|
+
else
|
|
58
|
+
ARG[:GRAPH].freeze
|
|
59
|
+
ARG[:BORDER].freeze
|
|
60
|
+
end
|
|
56
61
|
self
|
|
57
62
|
end
|
|
58
63
|
|
|
@@ -296,7 +301,7 @@ module Squared
|
|
|
296
301
|
if footer
|
|
297
302
|
unless sub.empty? && !right
|
|
298
303
|
footer.map! do |s|
|
|
299
|
-
s = s.rjust(n +
|
|
304
|
+
s = s.rjust(n + 4) if right
|
|
300
305
|
sub.each { |h| sub_style!(s, **h) }
|
|
301
306
|
s
|
|
302
307
|
end
|
|
@@ -1,27 +1,21 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'timeout'
|
|
4
|
+
|
|
3
5
|
module Squared
|
|
4
6
|
module Common
|
|
5
7
|
module Prompt
|
|
6
8
|
def self.reline
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
require 'reline'
|
|
13
|
-
Reline
|
|
14
|
-
rescue LoadError
|
|
15
|
-
require 'readline'
|
|
16
|
-
Readline
|
|
17
|
-
end
|
|
18
|
-
end
|
|
9
|
+
require 'reline'
|
|
10
|
+
Reline
|
|
11
|
+
rescue LoadError
|
|
12
|
+
require 'readline'
|
|
13
|
+
Readline
|
|
19
14
|
end
|
|
20
15
|
|
|
21
16
|
module_function
|
|
22
17
|
|
|
23
18
|
def confirm(msg, accept = nil, agree: 'Y', cancel: 'N', force: false, attempts: 3, timeout: 60)
|
|
24
|
-
require 'timeout'
|
|
25
19
|
if agree == 'Y' && cancel == 'N' && !msg.match?(%r{\[(Yn|nY|Y/n|y/N)\]})
|
|
26
20
|
case accept
|
|
27
21
|
when 'Y'
|
|
@@ -34,7 +28,7 @@ module Squared
|
|
|
34
28
|
cancel = /^#{Regexp.escape(cancel)}$/i if cancel.is_a?(::String)
|
|
35
29
|
Timeout.timeout(timeout) do
|
|
36
30
|
while (ch = Prompt.reline.readline(msg))
|
|
37
|
-
ch
|
|
31
|
+
ch.chomp!
|
|
38
32
|
case (ch.empty? ? accept : ch)
|
|
39
33
|
when agree
|
|
40
34
|
return true
|
|
@@ -54,9 +48,9 @@ module Squared
|
|
|
54
48
|
false
|
|
55
49
|
end
|
|
56
50
|
|
|
57
|
-
def choice(msg, list = nil, min: 1, max:
|
|
58
|
-
|
|
59
|
-
|
|
51
|
+
def choice(msg, list = nil, min: 1, max: nil, multiple: false, index: false, grep: nil, border: nil, force: true,
|
|
52
|
+
attempts: 3, timeout: 0, pipe: 1, scroll: true, empty: nil, page: 25)
|
|
53
|
+
std = pipe == 2 ? $stderr : $stdout
|
|
60
54
|
multiple = Array(multiple) if multiple.is_a?(::Numeric)
|
|
61
55
|
if list
|
|
62
56
|
grep &&= Array(grep).map { |val| Regexp.new(val) }
|
|
@@ -64,36 +58,71 @@ module Squared
|
|
|
64
58
|
next if grep&.none? { |pat| pat.match?(val) }
|
|
65
59
|
|
|
66
60
|
out << val.to_s.chomp
|
|
67
|
-
puts '%2d. %s' % [out.size, val]
|
|
68
61
|
end
|
|
69
|
-
max = items.size
|
|
62
|
+
max = max ? [max, items.size].min : items.size
|
|
70
63
|
if max == 0
|
|
71
64
|
raise ArgumentError, 'empty selection list' unless empty
|
|
72
65
|
|
|
73
66
|
puts empty
|
|
74
67
|
exit 1
|
|
75
68
|
end
|
|
69
|
+
tmpl = "%#{[items.size.to_s.size, 2].max}d. %s"
|
|
70
|
+
items = items.map.with_index { |item, i| [item, tmpl % [i.succ, item]] }
|
|
76
71
|
min = grep ? 1 : [min, max].min
|
|
77
|
-
|
|
78
|
-
|
|
72
|
+
require 'io/console'
|
|
73
|
+
if min > 1 || max < items.size
|
|
74
|
+
items = items[min.pred...max]
|
|
75
|
+
min = 1
|
|
76
|
+
end
|
|
77
|
+
page = page ? [page, max].min : max
|
|
78
|
+
cur = 0
|
|
79
|
+
line = 0
|
|
80
|
+
last = (max / page.to_f).ceil
|
|
81
|
+
pre = msg
|
|
82
|
+
scroll = true if border
|
|
83
|
+
clear = -> { std.print "\r\e[K" }
|
|
84
|
+
write = lambda do |s, buf = true|
|
|
85
|
+
line += [s.lines.size, 1].max if buf
|
|
86
|
+
clear.call unless scroll && !border
|
|
87
|
+
std.puts s
|
|
88
|
+
end
|
|
89
|
+
render = lambda do |index, init = false|
|
|
90
|
+
fr = index * page
|
|
91
|
+
to = [fr + page, max].min
|
|
92
|
+
unless init
|
|
93
|
+
std.cursor_up((scroll ? 0 : page) + line.succ)
|
|
94
|
+
clear.call
|
|
95
|
+
end
|
|
96
|
+
line = 0
|
|
97
|
+
items[fr...to].each { |item| write.call(item.last, false) }
|
|
79
98
|
if border == true
|
|
80
|
-
|
|
99
|
+
write.call(print_footer)
|
|
81
100
|
elsif border
|
|
82
|
-
|
|
101
|
+
write.call(print_footer(border: border))
|
|
102
|
+
end
|
|
103
|
+
fr = scroll ? 1 : fr.succ
|
|
104
|
+
suf = "|,#{multiple.is_a?(::Array) ? "{#{multiple.join(',')}}" : '*'}" if multiple
|
|
105
|
+
msg = "#{pre + (force ? ':' : '?')} [#{fr}-#{to}#{"/#{max}" if scroll && to < max}#{suf}] "
|
|
106
|
+
if cur == last.pred
|
|
107
|
+
cur = -1
|
|
108
|
+
last = 0 if scroll || (attempts -= 1) == 0
|
|
109
|
+
end
|
|
110
|
+
if init && last > 1 && !scroll
|
|
111
|
+
write.call('', false)
|
|
112
|
+
std.cursor_up(1)
|
|
83
113
|
end
|
|
84
|
-
msg = "#{msg + (force ? ':' : '?')} [#{min}-#{max}#{if (n = multiple)
|
|
85
|
-
"|,#{n.is_a?(::Array) ? "{#{n.join(',')}}" : '*'}"
|
|
86
|
-
end}] "
|
|
87
114
|
end
|
|
115
|
+
render.call(0, true)
|
|
116
|
+
else
|
|
117
|
+
max ||= 1
|
|
118
|
+
last = 0
|
|
88
119
|
end
|
|
89
120
|
between = ->(s) { s.match?(/^\d+$/) && s.to_i.between?(min, max <= min ? Float::INFINITY : max) }
|
|
90
121
|
Timeout.timeout(timeout) do
|
|
91
122
|
while (ch = Prompt.reline.readline(msg))
|
|
92
123
|
ch.strip!
|
|
93
|
-
|
|
94
|
-
if
|
|
95
|
-
break
|
|
96
|
-
elsif multiple
|
|
124
|
+
if !ch.empty?
|
|
125
|
+
if multiple
|
|
97
126
|
k = if ch == '*'
|
|
98
127
|
(min..max).to_a
|
|
99
128
|
else
|
|
@@ -114,12 +143,15 @@ module Squared
|
|
|
114
143
|
k.uniq!
|
|
115
144
|
k.sort!
|
|
116
145
|
unless multiple.is_a?(::Array) && !multiple.include?(k.size)
|
|
117
|
-
return index || !items ? k : k.map { |i| items[i.pred] }
|
|
146
|
+
return index || !items ? k : k.map { |i| items[i.pred].first }
|
|
118
147
|
end
|
|
119
148
|
end
|
|
120
149
|
elsif between.call(ch)
|
|
121
|
-
return index || !items ? ch.to_i : items[ch.to_i.pred]
|
|
150
|
+
return index || !items ? ch.to_i : items[ch.to_i.pred].first
|
|
122
151
|
end
|
|
152
|
+
elsif last > 0
|
|
153
|
+
render.call(cur += 1)
|
|
154
|
+
next
|
|
123
155
|
end
|
|
124
156
|
attempts -= 1
|
|
125
157
|
next if attempts > 0
|
|
@@ -128,7 +160,7 @@ module Squared
|
|
|
128
160
|
break
|
|
129
161
|
end
|
|
130
162
|
rescue Interrupt
|
|
131
|
-
puts
|
|
163
|
+
std.puts
|
|
132
164
|
exit 0
|
|
133
165
|
else
|
|
134
166
|
[] if multiple
|
data/lib/squared/common/shell.rb
CHANGED
|
@@ -167,7 +167,9 @@ module Squared
|
|
|
167
167
|
end
|
|
168
168
|
|
|
169
169
|
def line_width(lines)
|
|
170
|
-
|
|
170
|
+
require 'io/console/size'
|
|
171
|
+
cols = IO.default_console_size.last
|
|
172
|
+
[lines.empty? ? cols : [lines.max_by(&:size).size, cols].max, Rake.application.terminal_width].min
|
|
171
173
|
end
|
|
172
174
|
|
|
173
175
|
def fill_option(val, **kwargs)
|
|
@@ -28,15 +28,8 @@ module Squared
|
|
|
28
28
|
module_function
|
|
29
29
|
|
|
30
30
|
def shell(*args, name: :system, **kwargs)
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
elsif RUBY_VERSION < '2.6'
|
|
34
|
-
ex = kwargs.delete(:exception)
|
|
35
|
-
end
|
|
36
|
-
ret = Kernel.send(name, *args, **kwargs)
|
|
37
|
-
raise $?.to_s if ex && !ret
|
|
38
|
-
|
|
39
|
-
ret
|
|
31
|
+
kwargs.delete(:exception) unless name == :system
|
|
32
|
+
Kernel.send(name, *args, **kwargs)
|
|
40
33
|
end
|
|
41
34
|
|
|
42
35
|
def shell_t(*args, timeout: 0, **kwargs)
|
data/lib/squared/config.rb
CHANGED
|
@@ -65,7 +65,7 @@ module Squared
|
|
|
65
65
|
command = File.basename(@main)
|
|
66
66
|
command = ARG[:VIEW] if command == @name
|
|
67
67
|
end
|
|
68
|
-
ext = @ext[1
|
|
68
|
+
ext = @ext[1..].downcase
|
|
69
69
|
if (data = @@mime_obj[ext])
|
|
70
70
|
add(data[1].first, command: command, opts: opts, ext: data[1])
|
|
71
71
|
else
|
|
@@ -98,7 +98,7 @@ module Squared
|
|
|
98
98
|
namespace task_name(name) do |ns|
|
|
99
99
|
@mime.each do |type, items|
|
|
100
100
|
items.each do |command, file, opts|
|
|
101
|
-
next if Rake::Task.task_defined?(
|
|
101
|
+
next if Rake::Task.task_defined?(task_join(ns.scope.path, command, type))
|
|
102
102
|
|
|
103
103
|
namespace command do
|
|
104
104
|
unless (data = @@mime_obj[type])
|
|
@@ -288,7 +288,7 @@ module Squared
|
|
|
288
288
|
if project
|
|
289
289
|
project.workspace.task_name(val)
|
|
290
290
|
else
|
|
291
|
-
@prefix ?
|
|
291
|
+
@prefix ? task_join(@prefix, val) : val.to_s
|
|
292
292
|
end
|
|
293
293
|
end
|
|
294
294
|
|
data/lib/squared/version.rb
CHANGED