squared 0.5.10 → 0.5.12

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.
@@ -65,11 +65,13 @@ module Squared
65
65
 
66
66
  @@tasks = {}
67
67
  @@graph = { _: [] }
68
- @@asdf = if File.exist?("#{Dir.home}/.asdf/asdf.sh")
69
- [Pathname.new("#{Dir.home}/.asdf"), 15]
70
- elsif ENV['ASDF_DATA_DIR']
71
- [Pathname.new(ENV['ASDF_DATA_DIR']), 16]
72
- end
68
+ @@asdf = Pathname.new("#{Dir.home}/.asdf").yield_self do |path|
69
+ if path.join('asdf.sh').exist?
70
+ [path, 15]
71
+ elsif ENV['ASDF_DATA_DIR']
72
+ [Pathname.new(ENV['ASDF_DATA_DIR']), 16]
73
+ end
74
+ end
73
75
  @@print_order = 0
74
76
 
75
77
  subtasks({
@@ -80,6 +82,7 @@ module Squared
80
82
 
81
83
  attr_reader :name, :project, :workspace, :path, :theme, :group, :parent, :dependfile,
82
84
  :exception, :pipe, :verbose
85
+ attr_accessor :global
83
86
 
84
87
  def initialize(workspace, path, name, *, group: nil, first: {}, last: {}, error: {}, common: ARG[:COMMON],
85
88
  **kwargs)
@@ -97,9 +100,14 @@ module Squared
97
100
  @clean = kwargs[:clean]
98
101
  @release = kwargs[:release]
99
102
  self.version = kwargs[:version]
100
- self.exception = kwargs[:exception]
101
- self.pipe = kwargs[:pipe]
102
- self.verbose = kwargs[:verbose]
103
+ self.exception = env_bool(kwargs[:exception], workspace.exception, strict: true)
104
+ self.pipe = env_pipe(kwargs[:pipe], workspace.pipe, strict: true)
105
+ self.verbose = case (val = env('VERBOSE', kwargs[:verbose]))
106
+ when String
107
+ env_bool(val, workspace.verbose, strict: true, index: true)
108
+ else
109
+ val.nil? ? workspace.verbose : val
110
+ end
103
111
  @output = []
104
112
  @ref = []
105
113
  @children = []
@@ -150,8 +158,10 @@ module Squared
150
158
  data = @workspace.script_find(*@ref, @group)
151
159
  if @output[0].nil?
152
160
  if (scr = data[:script])
153
- @global = true
154
- script_set(scr, args: data.fetch(:args, kwargs[:args]), prod: kwargs[:prod])
161
+ unless kwargs[:script] == false
162
+ @global = true
163
+ script_set(scr, args: data.fetch(:args, kwargs[:args]), prod: kwargs[:prod])
164
+ end
155
165
  elsif (run = data[:run])
156
166
  @global = true
157
167
  run_set run
@@ -174,7 +184,6 @@ module Squared
174
184
  @global = true
175
185
  run_set data[:run]
176
186
  end
177
- @global = true
178
187
  end
179
188
 
180
189
  def initialize_events(ref, **)
@@ -291,21 +300,29 @@ module Squared
291
300
  end
292
301
 
293
302
  def exception=(val)
294
- @exception = env_bool(val, workspace.exception, strict: true)
303
+ @exception = case val
304
+ when Numeric, TrueClass, FalseClass
305
+ val
306
+ else
307
+ workspace.exception
308
+ end
295
309
  end
296
310
 
297
311
  def pipe=(val)
298
- @pipe = env_pipe(val, workspace.pipe, strict: true)
312
+ @pipe = case val
313
+ when Numeric, Pathname
314
+ val
315
+ else
316
+ workspace.pipe
317
+ end
299
318
  end
300
319
 
301
320
  def verbose=(val)
302
- @verbose = case (val = env('VERBOSE', val))
303
- when NilClass
304
- workspace.verbose
305
- when String
306
- env_bool(val, workspace.verbose, strict: true, index: true)
307
- else
321
+ @verbose = case val
322
+ when Numeric, TrueClass, FalseClass
308
323
  val
324
+ else
325
+ workspace.verbose
309
326
  end
310
327
  end
311
328
 
@@ -335,13 +352,8 @@ module Squared
335
352
  else
336
353
  out, done = graph(args, out: [])
337
354
  out.map! do |val|
338
- done.each_with_index do |proj, i|
339
- next unless val.match?(/ #{Regexp.escape(proj.name)}(?:@\d|\z)/)
340
-
341
- val += " (#{i.succ})"
342
- break
343
- end
344
- val
355
+ n = done.index { |proj| val.match?(/ #{Regexp.escape(proj.name)}(?:@\d|\z)/) }
356
+ n ? "#{val} (#{n.succ})" : val
345
357
  end
346
358
  emphasize(out, title: path, right: true, border: borderstyle, sub: [
347
359
  { pat: /\A(#{Regexp.escape(path.to_s)})(.*)\z/, styles: theme[:header] },
@@ -389,6 +401,7 @@ module Squared
389
401
  version, opts = choice_index('Select a version',
390
402
  @asdf[1].children
391
403
  .map(&:basename)
404
+ .sort { |a, b| b <=> a }
392
405
  .append('latest', 'system'),
393
406
  force: true, accept: [['Confirm?', false, true]],
394
407
  values: ['Options'])
@@ -425,32 +438,32 @@ module Squared
425
438
  end
426
439
 
427
440
  def add(path, name = nil, **kwargs, &blk)
428
- if path.is_a?(String) && (seg = path[%r{\A(.+)[\\/]\*+\z}, 1])
429
- return self unless checkdir?(path = basepath(seg))
441
+ if path.is_a?(String) && path =~ %r{\A(.+)[\\/]\*+\z}
442
+ return self unless checkdir?(path = basepath($1))
430
443
 
431
444
  path = path.children.select { |val| checkdir?(val) }
432
445
  end
433
446
  if path.is_a?(Array)
434
- name = @name if name == true
447
+ name = self.name if name == true
435
448
  path.each { |val| add(val, name && task_join(name, File.basename(val)), **kwargs, &blk) }
436
- return self
437
- end
438
- return self unless projectpath?(path = basepath(path)) && checkdir?(path)
439
-
440
- kwargs = @withargs.yield_self { |data| data.dup.update(kwargs) } if @withargs
441
- kwargs[:group] = group unless kwargs.key?(:group)
442
- kwargs[:ref] = ref unless kwargs.key?(:ref)
443
- parent = self
444
- name = case name
445
- when String, Symbol
446
- name.to_s
447
- else
448
- path.basename
449
- end
450
- workspace.add(path, name, **kwargs) do
451
- __send__ :parent_set, parent
452
- @children << self
453
- instance_eval(&blk) if block_given?
449
+ elsif projectpath?(path = basepath(path)) && checkdir?(path)
450
+ kwargs = hashdup(@withargs).update(kwargs) if @withargs
451
+ kwargs[:group] = group if group && !kwargs.key?(:group)
452
+ kwargs[:ref] = ref unless kwargs.key?(:ref)
453
+ parent = self
454
+ proj = nil
455
+ name = case name
456
+ when String, Symbol
457
+ name.to_s
458
+ else
459
+ path.basename
460
+ end
461
+ workspace.add(path, name, **kwargs) do
462
+ __send__ :parent_set, parent
463
+ proj = self
464
+ instance_eval(&blk) if block_given?
465
+ end
466
+ @children << proj
454
467
  end
455
468
  self
456
469
  end
@@ -461,13 +474,13 @@ module Squared
461
474
  end
462
475
 
463
476
  def inject(obj, *args, **kwargs, &blk)
464
- return self unless enabled?
465
-
466
- out = obj.link(self, *args, **kwargs, &blk) if obj.respond_to?(:link)
467
- if !out
468
- print_error('link not compatible', subject: obj, hint: name)
469
- elsif out.respond_to?(:build)
470
- out.build
477
+ if enabled?
478
+ out = obj.link(self, *args, **kwargs, &blk) if obj.respond_to?(:link)
479
+ if !out
480
+ print_error('link not compatible', subject: obj, hint: name)
481
+ elsif out.respond_to?(:build)
482
+ out.build
483
+ end
471
484
  end
472
485
  self
473
486
  end
@@ -477,9 +490,9 @@ module Squared
477
490
  if args.empty?
478
491
  return unless from == :run
479
492
 
480
- run_b(@run, sync: sync, from: from) if series?(@run)
481
- args = @output
482
493
  banner = verbosetype > 1 if from_base?('build')
494
+ run_b(@run, sync: sync, from: from, banner: banner) if series?(@run)
495
+ args = @output
483
496
  end
484
497
  if args.first.is_a?(Struct)
485
498
  f, blk = args.first.to_a
@@ -513,11 +526,9 @@ module Squared
513
526
  else
514
527
  cmd, opts, var, flags, extra = args
515
528
  end
516
- if cmd.is_a?(Proc) || cmd.is_a?(Method)
517
- run_b(cmd, sync: sync, from: from)
518
- return
519
- end
520
529
  if cmd
530
+ return run_b(cmd, sync: sync, from: from) if cmd.is_a?(Proc) || cmd.is_a?(Method)
531
+
521
532
  cmd = as_get(cmd, from)
522
533
  opts = compose(opts, script: false) if opts && respond_to?(:compose)
523
534
  flags = append_hash(flags, target: []).join(' ') if flags.is_a?(Hash)
@@ -553,13 +564,13 @@ module Squared
553
564
  next if @@graph[:_].include?(proj)
554
565
 
555
566
  if (val = ENV["PREREQS_#{proj.instance_variable_get(:@envname)}"] || ENV["PREREQS_#{proj.ref.upcase}"])
556
- val.split(/\s*,\s*/).each do |meth|
567
+ split_escape(val).each do |meth|
557
568
  if proj.respond_to?(meth.to_sym)
558
569
  begin
559
570
  proj.__send__(meth, sync: sync)
560
571
  next
561
572
  rescue StandardError => e
562
- on_error(:prereqs, e, exception: true)
573
+ on_error(e, :prereqs, exception: true)
563
574
  end
564
575
  end
565
576
  print_error(name, 'method not found', subject: 'prereqs', hint: meth)
@@ -579,7 +590,7 @@ module Squared
579
590
  end
580
591
 
581
592
  def doc(*, sync: invoked_sync?('doc'), **)
582
- run_b(@doc, sync: sync, from: :doc, banner: from_base?('doc') ? verbosetype > 1 : verbose)
593
+ run_b(@doc, sync: sync, banner: from_base?('doc') ? verbose? : verbosetype > 0, from: :doc)
583
594
  end
584
595
 
585
596
  def lint(*, sync: invoked_sync?('lint'), **)
@@ -600,9 +611,9 @@ module Squared
600
611
  on :first, :clean unless pass
601
612
  case @clean
602
613
  when Struct
603
- if (any = instance_eval(&@clean.block) || @clean.run)
614
+ if (val = instance_eval(&@clean.block) || @clean.run)
604
615
  temp = @clean
605
- @clean = any
616
+ @clean = val
606
617
  clean(*args, sync: sync, pass: true, **kwargs)
607
618
  @clean = temp
608
619
  end
@@ -612,7 +623,7 @@ module Squared
612
623
  begin
613
624
  @clean.each { |cmd, opts| build(cmd.to_s, opts, sync: sync) }
614
625
  rescue StandardError => e
615
- on_error e, from
626
+ on_error e, :clean
616
627
  end
617
628
  else
618
629
  if @clean.is_a?(Enumerable) && !series?(@clean)
@@ -620,7 +631,7 @@ module Squared
620
631
  entry = basepath(val = val.to_s)
621
632
  if entry.directory? && val.match?(%r{[\\/]\z})
622
633
  log&.warn "rm -rf #{entry}"
623
- rm_rf(entry, verbose: verbose)
634
+ rm_rf(entry, verbose: verbosetype > 0)
624
635
  else
625
636
  log&.warn "rm #{entry}"
626
637
  (val.include?('*') ? Dir[entry] : [entry]).each do |file|
@@ -659,7 +670,7 @@ module Squared
659
670
  end
660
671
  ret = graph_branch(self, data, tasks, out, sync: sync, pass: pass)
661
672
  rescue StandardError => e
662
- on_error(:graph, e, exception: true)
673
+ on_error(e, :graph, exception: true)
663
674
  else
664
675
  if out
665
676
  [out, ret]
@@ -718,10 +729,12 @@ module Squared
718
729
  case f.content_type
719
730
  when 'application/zip'
720
731
  ext = 'zip'
721
- when 'application/x-gzip'
732
+ when %r{application/(?:x-)?gzip}
722
733
  ext = 'tgz'
723
734
  when 'application/x-xz'
724
735
  ext = 'txz'
736
+ when 'application/x-7z-compressed'
737
+ ext = '7z'
725
738
  end
726
739
  end
727
740
  break uri = url if data
@@ -756,7 +769,7 @@ module Squared
756
769
  case ext
757
770
  when 'zip', 'aar'
758
771
  session 'unzip', shell_quote(file), quote_option('d', target)
759
- when 'tar', 'tgz', 'tar.gz', 'tar.xz', 'gz', 'xz'
772
+ when 'tar', 'tgz', 'txz', 'tar.gz', 'tar.xz', 'gz', 'xz'
760
773
  flags = +(verbose ? 'v' : '')
761
774
  if ext.end_with?('gz')
762
775
  flags += 'z'
@@ -780,9 +793,7 @@ module Squared
780
793
  break unless entry.directory?
781
794
 
782
795
  i = 0
783
- while (dest = target + "#{File.basename(file)}-#{i}").exist?
784
- i += 1
785
- end
796
+ i += 1 while (dest = target + "#{File.basename(file)}-#{i}").exist?
786
797
  FileUtils.mv(entry, dest)
787
798
  dest.each_child { |child| FileUtils.mv(child, target) }
788
799
  dest.rmdir
@@ -822,7 +833,7 @@ module Squared
822
833
  cmd << '--no-header' unless legacy
823
834
  cmd << name
824
835
  end
825
- print_success if success?(run(from: :"asdf:#{flag}")) && flag == :set
836
+ print_success if success?(run(from: :"asdf:#{flag}"), flag == :set)
826
837
  end
827
838
 
828
839
  def first(key, *args, **kwargs, &blk)
@@ -868,9 +879,9 @@ module Squared
868
879
  end
869
880
 
870
881
  def run(cmd = @session, var = nil, exception: self.exception, sync: true, from: nil, banner: true, chdir: path,
871
- interactive: nil, hint: nil, **)
882
+ interactive: nil, hint: nil, series: true, **)
872
883
  unless cmd
873
- print_error('no command given', subject: project, hint: from || 'unknown', pass: true)
884
+ print_error('no command session started', subject: project, hint: from, pass: true)
874
885
  return
875
886
  end
876
887
  cmd = cmd.target if cmd.is_a?(OptionPartition)
@@ -893,7 +904,7 @@ module Squared
893
904
  log&.warn "ENV discarded: #{var}" if var
894
905
  task_invoke(cmd, exception: exception, warning: warning?)
895
906
  else
896
- print_item format_banner(hint ? "#{cmd} (#{hint})" : cmd, banner: banner) if sync
907
+ print_item(format_banner(hint ? "#{cmd} (#{hint})" : cmd, banner: banner), series: series) if sync
897
908
  if var != false && (pre = runenv)
898
909
  case pre
899
910
  when Hash
@@ -908,7 +919,7 @@ module Squared
908
919
  ret = shell(*args, chdir: chdir, exception: exception)
909
920
  end
910
921
  rescue StandardError => e
911
- on_error(from, e, exception: true)
922
+ on_error(e, from, exception: true)
912
923
  false
913
924
  else
914
925
  on :last, from
@@ -1120,8 +1131,8 @@ module Squared
1120
1131
  def run_b(obj, **kwargs)
1121
1132
  case obj
1122
1133
  when Struct
1123
- if (any = instance_eval(&obj.block) || obj.run)
1124
- run_b(any, **kwargs)
1134
+ if (val = instance_eval(&obj.block) || obj.run)
1135
+ run_b(val, **kwargs)
1125
1136
  end
1126
1137
  when Proc
1127
1138
  instance_eval(&obj)
@@ -1141,6 +1152,7 @@ module Squared
1141
1152
  def graph_branch(target, data, tasks = nil, out = nil, sync: true, pass: [], done: [], depth: 0,
1142
1153
  single: false, last: false, context: nil)
1143
1154
  tag = ->(proj) { "#{proj.name}#{SEM_VER.match?(proj.version) ? "@#{proj.version}" : ''}" }
1155
+ script = ->(proj) { workspace.script_get(:graph, group: proj.group, ref: proj.allref)&.fetch(:graph, nil) }
1144
1156
  check = ->(deps) { deps.reject { |val| done.include?(val) } }
1145
1157
  dedupe = lambda do |name|
1146
1158
  next [] unless (ret = data[name])
@@ -1191,10 +1203,7 @@ module Squared
1191
1203
  single: single, last: j == true, context: target)
1192
1204
  end
1193
1205
  if !out
1194
- if !tasks && (script = workspace.script_get(:graph, group: proj.group, ref: proj.allref))
1195
- tasks = script[:graph]
1196
- end
1197
- (tasks || (dev? ? ['build', 'copy'] : ['depend', 'build'])).each do |meth|
1206
+ (tasks || (subtasks = script.call(proj)) || (dev? ? %w[build copy] : %w[depend build])).each do |meth|
1198
1207
  next if pass.include?(meth)
1199
1208
 
1200
1209
  if workspace.task_defined?(cmd = task_join(proj.name, meth))
@@ -1205,7 +1214,7 @@ module Squared
1205
1214
  end
1206
1215
  run(cmd, sync: false, banner: false)
1207
1216
  ENV.delete(key) if key
1208
- elsif proj.has?(meth, tasks ? nil : workspace.baseref)
1217
+ elsif proj.has?(meth, tasks || subtasks ? nil : workspace.baseref)
1209
1218
  proj.__send__(meth.to_sym, sync: sync)
1210
1219
  end
1211
1220
  end
@@ -1350,9 +1359,9 @@ module Squared
1350
1359
  warn log_message(loglevel, *args, **kwargs) if warning?
1351
1360
  end
1352
1361
 
1353
- def print_item(*val)
1362
+ def print_item(*val, series: true)
1354
1363
  puts unless printfirst?
1355
- printsucc
1364
+ printsucc if series
1356
1365
  puts val unless val.empty? || (val.size == 1 && val.first.nil?)
1357
1366
  end
1358
1367
 
@@ -1387,7 +1396,7 @@ module Squared
1387
1396
  sub&.each { |h| s = sub_style(s, **h) }
1388
1397
  s
1389
1398
  end
1390
- ret = [sub_style(ARG[:BORDER][1] * n, styles: border), *lines]
1399
+ ret = [sub_style(ARG[:BORDER][1] * n, styles: border)].concat(lines)
1391
1400
  ret.reverse! if reverse
1392
1401
  ret.join("\n")
1393
1402
  end
@@ -1488,7 +1497,7 @@ module Squared
1488
1497
  else
1489
1498
  pat = /\A(\s*\d+\.)(.+)\z/
1490
1499
  unless grep.empty?
1491
- footer = "#{out.size} found"
1500
+ footer = "#{out.size} found "
1492
1501
  sub << { pat: /\A(\d+)( .+)\z/, styles: theme[:inline] }
1493
1502
  end
1494
1503
  end
@@ -1687,8 +1696,8 @@ module Squared
1687
1696
  confirm "#{a}: #{b}#{c} #{sub_style(ver.rjust(col1 > 0 ? 10 : 0), styles: theme[:inline])} ", d
1688
1697
  end
1689
1698
 
1690
- def choice_index(msg, list, values: nil, accept: nil, series: false, trim: nil, column: nil,
1691
- multiple: false, force: true, **kwargs)
1699
+ def choice_index(msg, list, values: nil, accept: nil, series: false, trim: nil, column: nil, multiple: false,
1700
+ force: true, **kwargs)
1692
1701
  puts if !series && !printfirst?
1693
1702
  msg = "#{msg} (optional)" unless force
1694
1703
  unless (ret = choice(msg, list, multiple: multiple, force: force, **kwargs)) && !ret.empty?
@@ -1704,13 +1713,10 @@ module Squared
1704
1713
  if accept
1705
1714
  hint = Array(ret).map { |val| sub_style(val, styles: theme[:inline]) }.join(', ')
1706
1715
  accept = Array(accept).map { |val| Array(val) }
1707
- if accept.any? { |val| val[1] == true }
1708
- ret = [ret]
1709
- multiple = -1
1710
- end
1716
+ ret = Array(ret) if accept.any? { |val| val[1] == true }
1711
1717
  loop do
1712
1718
  item = accept.first
1713
- c = confirm("#{item[0]}#{a ? " [#{hint}]" : ''}", item[2] ? 'Y' : 'N', timeout: 60)
1719
+ c = confirm("#{item[0]}#{hint ? " [#{hint}]" : ''}", item[2] ? 'Y' : 'N', timeout: 60)
1714
1720
  if item[1] == true
1715
1721
  ret << c
1716
1722
  elsif !c
@@ -1723,8 +1729,8 @@ module Squared
1723
1729
  exit 1 unless accept.empty?
1724
1730
  end
1725
1731
  if values
1726
- ret = [ret] unless accept && multiple == -1
1727
- values.each do |val|
1732
+ ret = Array(ret)
1733
+ Array(values).each do |val|
1728
1734
  if val.is_a?(Array)
1729
1735
  val, force = val
1730
1736
  else
@@ -1757,21 +1763,17 @@ module Squared
1757
1763
  end
1758
1764
 
1759
1765
  def command(*args)
1760
- if workspace.powershell?
1761
- "powershell.exe -Command \"& {#{args.join(' ; ')}}\""
1762
- else
1763
- args.join(' && ')
1764
- end
1766
+ return args.join(' && ') unless workspace.powershell?
1767
+
1768
+ "powershell.exe -Command #{shell_quote("& {#{args.join(' ; ')}}", option: false, double: true)}"
1765
1769
  end
1766
1770
 
1767
1771
  def relativepath(*list, all: false)
1768
1772
  return [] if list.empty?
1769
1773
 
1770
1774
  list.flatten.map! { |val| Pathname.new(val) }.select { |val| projectpath?(val) }.map! do |val|
1771
- val = val.absolute? ? val.relative_path_from(path).to_s : val.to_s
1772
- val = val[2..-1] if val.start_with?('./')
1773
- val = "#{val}*" if all && val.end_with?('/')
1774
- val
1775
+ ret = (val.absolute? ? val.relative_path_from(path) : val.cleanpath).to_s
1776
+ all && val.to_s.end_with?('/') ? "#{ret}/*" : ret
1775
1777
  end
1776
1778
  end
1777
1779
 
@@ -1813,16 +1815,14 @@ module Squared
1813
1815
 
1814
1816
  def semcmp(val, other)
1815
1817
  return 0 if val == other
1816
-
1817
- a, b = [val, other].map! { |ver| ver.scan(SEM_VER) }
1818
- return -1 if b.empty?
1819
- return 1 if a.empty?
1818
+ return -1 if (b = other.scan(SEM_VER)).empty?
1819
+ return 1 if (a = val.scan(SEM_VER)).empty?
1820
1820
 
1821
1821
  a, b = [a.first, b.first].map! do |c|
1822
- begin
1823
- d = Integer(c[5]).to_s
1822
+ d = begin
1823
+ Integer(c[5]).to_s
1824
1824
  rescue StandardError
1825
- d = c[5] ? '-1' : '0'
1825
+ c[5] ? '-1' : '0'
1826
1826
  end
1827
1827
  [c[0], c[2], c[4] || '0', d]
1828
1828
  end
@@ -1855,8 +1855,7 @@ module Squared
1855
1855
  end
1856
1856
 
1857
1857
  def color(val)
1858
- ret = theme[val]
1859
- ret && !ret.empty? ? ret : [val]
1858
+ (ret = theme[val]) && !ret.empty? ? ret : [val]
1860
1859
  end
1861
1860
 
1862
1861
  def colormap(val)
@@ -2074,16 +2073,15 @@ module Squared
2074
2073
  end
2075
2074
 
2076
2075
  def projectpath?(val)
2077
- Pathname.new(val).cleanpath.yield_self do |file|
2078
- file.absolute? ? file.to_s.start_with?(File.join(path, '')) : !file.to_s.start_with?(File.join('..', ''))
2079
- end
2076
+ ret = Pathname.new(val).cleanpath
2077
+ ret.absolute? ? ret.to_s.start_with?(File.join(path, '')) : !ret.to_s.start_with?(File.join('..', ''))
2080
2078
  end
2081
2079
 
2082
2080
  def checkdir?(val)
2083
2081
  if val.directory? && !val.empty?
2084
2082
  true
2085
2083
  else
2086
- log&.warn "directory \"#{val}\" (#{val.empty? ? 'empty' : 'not found'})"
2084
+ log&.warn "directory \"#{val}\" (#{val.directory? ? 'empty' : 'not found'})"
2087
2085
  false
2088
2086
  end
2089
2087
  end
@@ -2151,6 +2149,10 @@ module Squared
2151
2149
  !!verbose && !stdin?
2152
2150
  end
2153
2151
 
2152
+ def verbose?
2153
+ verbosetype > 1
2154
+ end
2155
+
2154
2156
  def warning?
2155
2157
  workspace.warning
2156
2158
  end
@@ -2182,6 +2184,10 @@ module Squared
2182
2184
  Workspace::Support.hashlist
2183
2185
  end
2184
2186
 
2187
+ def hashdup
2188
+ Workspace::Support.hashdup
2189
+ end
2190
+
2185
2191
  def borderstyle
2186
2192
  workspace.banner_get(*@ref, group: group)&.border || theme[:border]
2187
2193
  end