natty-ui 0.31.0 → 0.33.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5b2d8212f4b987cd05c8ce904cdde26e0a0228c9fe360a36dfad04b0e29bd7b6
4
- data.tar.gz: 8a3cd4de41e7ae69e18b6bf4e5437166f0c45fccf329009ebd0ecefd90a72f70
3
+ metadata.gz: 79e64cb2489dcf9efe4066e4f95252284f9227aafa4a77edd0d50f307b255cf2
4
+ data.tar.gz: 7ec6f014b300740062e816fa9c787ff79b3fb7ce68e4b1c2d6967ae6eb58b53d
5
5
  SHA512:
6
- metadata.gz: fe766477cf1ee36fad283300a659ed4bbc5e55a56e4d7b25383359f9e6616bac1179729ddda15a2c95e58a011dd185c3b419595554197a7fae6edf57f1a02b2c
7
- data.tar.gz: 40c4b083965158a22a39f171e897f40d0e2e6ee2d5ff4a601ec0015dfce9a523882e45a68f2b3208aa623effaef7d563287252eca388fb033325fb404064fb3d
6
+ metadata.gz: 86abb66230c52bd8863aec983435b434e7272003a12db631cb0b46af9db938ffc16f3ba1f987dad53a10f9ff4393e5f4bf403d04b813bb68b4b189c5bf0b2860
7
+ data.tar.gz: 34afc008cdec26384f7f20b7be6830a5be511147cfaef831d8e6869f858219ffeaea394ec8718ceb7513cfa3aaee19a852bb70d2b2ef641bc5880ca79d8de38d
data/.yardopts CHANGED
@@ -6,7 +6,6 @@
6
6
  --embed-mixins
7
7
  --tag comment
8
8
  --hide-tag comment
9
- --exclude lib/natty-ui/ansi_wrapper.rb
10
9
  lib/**/*.rb
11
10
  -
12
11
  README.md
data/README.md CHANGED
@@ -4,7 +4,7 @@ This is the beautiful, nice, nifty, fancy, neat, pretty, cool, rich, lovely, nat
4
4
 
5
5
  - Gem: [rubygems.org](https://rubygems.org/gems/natty-ui)
6
6
  - Source: [codeberg.org](https://codeberg.org/mblumtritt/natty-ui)
7
- - Help: [rubydoc.info](https://rubydoc.info/gems/natty-ui/NattyUI)
7
+ - Help: [rubydoc.info](https://rubydoc.info/gems/natty-ui/index)
8
8
 
9
9
  ## Features
10
10
 
@@ -28,7 +28,7 @@ This is the beautiful, nice, nifty, fancy, neat, pretty, cool, rich, lovely, nat
28
28
 
29
29
  ## Help
30
30
 
31
- 📕 See the [online help](https://rubydoc.info/gems/natty-ui/NattyUI) and have a look at the [examples](./examples/) directory to learn from code.
31
+ 📕 See the [online help](https://rubydoc.info/gems/natty-ui/index) and have a look at the [examples](./examples/) directory to learn from code.
32
32
 
33
33
  ### Run Examples
34
34
 
data/examples/hbars.rb CHANGED
@@ -11,7 +11,7 @@ ui.message '[b]​ᓚᕠᗢ NattyUI[/b] [i green]Print Horizontal Bars[/]' do
11
11
 
12
12
  ui.space
13
13
  ui.hbars values, style: :green, normalize: true, width: 0.5, min: 10
14
- ui.puts(
15
- 'These are the same values but [i]normalized[/i] and printed in half width.'
16
- )
14
+ ui.puts <<~INFO, eol: false
15
+ These are the same values but [i]normalized[/i] and printed in half width.
16
+ INFO
17
17
  end
@@ -3,13 +3,15 @@
3
3
  require_relative '../lib/natty-ui'
4
4
 
5
5
  ui.message '[b]​ᓚᕠᗢ NattyUI[/b] [i green]Named Colors Support[/]' do
6
- ui.puts <<~INFO
7
-
8
- NattyUI supports a series of named color values, such as those supported by Kitty.
9
-
6
+ ui.space
7
+ ui.puts <<~INFO, eol: false
8
+ NattyUI supports a series of named color values,
9
+ such as those supported by Kitty.
10
10
  INFO
11
- ui.information('Note') do
12
- ui.puts('Not all terminal emulators support true-colors.')
11
+
12
+ ui.space
13
+ ui.information 'Note' do
14
+ ui.puts 'Not all terminal emulators support true-colors.'
13
15
  end
14
16
 
15
17
  ui.space
data/examples/sh.rb ADDED
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../lib/natty-ui'
4
+
5
+ ui.message '[b]​ᓚᕠᗢ NattyUI[/b] [i green]Call Shell[/]' do
6
+ ui.space
7
+ ui.message 'Pipe this file to [i]cat[/i]; limit to five lines' do
8
+ File.open(__FILE__) do |file|
9
+ ui.run 'cat', input: file, preserve_spaces: true, max_lines: 5
10
+ end
11
+ end
12
+
13
+ ui.space
14
+ ui.message 'Call [i]cat[/i] with invalid option' do
15
+ ui.sh 'cat', '-?'
16
+ end
17
+ end
data/examples/tasks.rb CHANGED
@@ -17,9 +17,9 @@ ui.message '[b]​ᓚᕠᗢ NattyUI[/b] [i green]Tasks[/]' do
17
17
 
18
18
  ui.space
19
19
  ui.task 'Actualize Reading List' do
20
- ui.puts('This is a simple which actualizes the book reading list.')
20
+ ui.puts 'This is a simple which actualizes the book reading list.'
21
21
 
22
- ui.task('Connect to Library') do
22
+ ui.task 'Connect to Library' do
23
23
  do_something
24
24
  ui.mark 'Server Found', mark: :checkmark
25
25
  ui.task('Login...') { do_something_heavy }
@@ -36,14 +36,14 @@ ui.message '[b]​ᓚᕠᗢ NattyUI[/b] [i green]Tasks[/]' do
36
36
 
37
37
  ui.task('Disconnect from Library') { do_something_heavy }
38
38
 
39
- ui.progress('Read Cover Images', max: 11) do |progress|
39
+ ui.progress 'Read Cover Images', max: 11 do |progress|
40
40
  while progress.value < progress.max
41
41
  do_something
42
42
  progress.step
43
43
  end
44
44
  end
45
45
 
46
- ui.pin('New Books Marked', mark: :checkmark)
46
+ ui.pin 'New Books Marked', mark: :checkmark
47
47
 
48
48
  ui.task('Optimize Database') { do_something_heavy }
49
49
 
data/examples/vbars.rb CHANGED
@@ -32,8 +32,8 @@ ui.message '[b]​ᓚᕠᗢ NattyUI[/b] [i green]Print Vertical Bars[/]' do
32
32
 
33
33
  ui.space
34
34
  ui.vbars values, style: :green, normalize: true, bar_width: 2
35
- ui.puts(
36
- 'These are the same values but [i]normalized[/i] and printed with ' \
37
- 'a fixed bar width.'
38
- )
35
+ ui.puts <<~INFO, eol: false
36
+ These are the same values but [i]normalized[/i]
37
+ and printed with a fixed bar width.
38
+ INFO
39
39
  end
@@ -13,10 +13,10 @@ module NattyUI
13
13
  def merge!(**attributes) = attributes.empty? ? self : _assign(attributes)
14
14
  alias assign merge!
15
15
 
16
- # @!visibility private
16
+ # @private
17
17
  def to_hash = _store({})
18
18
 
19
- # @!visibility private
19
+ # @private
20
20
  def to_h(&block) = block ? _store({}).to_h(&block) : _store({})
21
21
 
22
22
  private
@@ -506,7 +506,7 @@ module NattyUI
506
506
  end
507
507
  end
508
508
 
509
- # @!visibility private
509
+ # @private
510
510
  # @return [String, nil]
511
511
  attr_reader :border_chars
512
512
 
@@ -549,11 +549,14 @@ module NattyUI
549
549
  @attributes = @attributes.dup
550
550
  end
551
551
  end
552
+
552
553
  private_constant :WithAttributes
553
554
 
554
555
  module TextWithAttributes
555
556
  include WithAttributes
557
+
556
558
  attr_reader :text
559
+
557
560
  def empty? = @text.empty?
558
561
  alias _to_s to_s
559
562
  private :_to_s
@@ -585,5 +588,6 @@ module NattyUI
585
588
  @text = @text.map(&:dup)
586
589
  end
587
590
  end
591
+
588
592
  private_constant :TextWithAttributes
589
593
  end
@@ -62,5 +62,6 @@ module NattyUI
62
62
  end
63
63
  end
64
64
  end
65
+
65
66
  private_constant :Choice
66
67
  end
@@ -42,5 +42,6 @@ module NattyUI
42
42
  @abortable = abortable
43
43
  end
44
44
  end
45
+
45
46
  private_constant :DumbChoice
46
47
  end
@@ -59,5 +59,6 @@ module NattyUI
59
59
  end
60
60
  end
61
61
  end
62
+
62
63
  private_constant :DumbOptions
63
64
  end
@@ -8,10 +8,10 @@ module NattyUI
8
8
  class Element
9
9
  include Features
10
10
 
11
- # @!visibility private
11
+ # @private
12
12
  def columns = @parent.columns - @prefix_width - @suffix_width
13
13
 
14
- # @!visibility private
14
+ # @private
15
15
  def puts(*objects, **options)
16
16
  if @prefix
17
17
  options[:prefix] = "#{@prefix}#{options[:prefix]}"
@@ -32,7 +32,7 @@ module NattyUI
32
32
  self
33
33
  end
34
34
 
35
- # @!visibility private
35
+ # @private
36
36
  alias to_s inspect
37
37
 
38
38
  alias _to_s to_s
@@ -46,13 +46,32 @@ module NattyUI
46
46
  end
47
47
  end
48
48
 
49
+ # Methods for elements with status like {ProgressHelper}, {Section}, {Task}.
50
+ #
49
51
  module WithStatus
52
+ # @return [Symbol, nil] element's current status
50
53
  attr_reader :status
54
+
55
+ # @attribute [r] active?
56
+ # @return [true, false] whether the element is still active
51
57
  def active? = @status.nil?
58
+
59
+ # @attribute [r] closed?
60
+ # @return [true, false] whether the element is closed
52
61
  def closed? = !active?
62
+
63
+ # @attribute [r] closed?
64
+ # @return [true, false] whether the element is completed
53
65
  def ok? = @state == :ok
66
+
67
+ # @attribute [r] failed?
68
+ # @return [true, false] whether the element is completed with failure
54
69
  def failed? = @state == :failed
55
70
 
71
+ # Close the element.
72
+ #
73
+ # @param [#to_s] text optional message
74
+ # @return [Element] itself
56
75
  def ok(*text)
57
76
  return self if @state
58
77
  text = [@title] if text.empty? && @title
@@ -62,6 +81,12 @@ module NattyUI
62
81
  end
63
82
  alias done ok
64
83
 
84
+ # Close the element with a failure.
85
+ #
86
+ # @param text [#to_s] optional message
87
+ # @yield optionally, when block is given
88
+ # @yieldparam failed [Section] see {Features.failed}
89
+ # @return [Element] itself
65
90
  def failed(*text, &block)
66
91
  return self if @state
67
92
  _failed
@@ -104,11 +104,11 @@ module NattyUI
104
104
  ansi: Terminal.ansi?,
105
105
  ignore_newline: ignore_newline
106
106
  )
107
-
107
+ tail = options[:tail] and lines = lines.to_a.last(tail)
108
108
  @__eol ||= Terminal.ansi? ? "\e[m\n" : "\n"
109
109
 
110
110
  if (align = options[:align]).nil?
111
- lines.each do |line|
111
+ lines.each do |line, _|
112
112
  Terminal.print(prefix, line, suffix, @__eol, bbcode: false)
113
113
  @lines_written += 1
114
114
  prefix, prefix_next = prefix_next, nil if prefix_next
@@ -578,29 +578,65 @@ module NattyUI
578
578
  block ? __with(progress, &block) : progress
579
579
  end
580
580
 
581
- # Run a shell program
582
- #
583
- # @return [Process::Status] when command was executed
584
- # @return [nil] in error case (like command not found)
585
- def sh(*cmd, shell: false, input: nil)
586
- m = (theme = Theme.current).mark(:sh_out)
587
- opts_out = {
588
- bbcode: false,
589
- prefix: "#{m}#{theme.sh_out_style}",
590
- prefix_width: m.width
591
- }
592
- m = theme.mark(:sh_err)
593
- opts_err = {
594
- bbcode: false,
595
- prefix: "#{m}#{theme.sh_err_style}",
596
- prefix_width: m.width
597
- }
598
- ShellCommand.call(*cmd, shell: shell, input: input) do |line, kind|
599
- puts(
600
- line.gsub("\t", '    ').gsub(/[[:space:]]/, ' '),
601
- **(kind == :error ? opts_err : opts_out)
581
+ # Execute a program.
582
+ #
583
+ # @example Execute a simple command
584
+ # ui.sh 'ls'
585
+ #
586
+ # @example Execute a command wih arguments
587
+ # ret = ui.sh('curl', '--version')
588
+ # raise('Curl not found') unless ret&.success?
589
+ #
590
+ # @example Execute shell commands
591
+ # ui.sh "mkdir 'test' && cd 'test'"
592
+ #
593
+ # @example Execute a command with environment variables
594
+ # ui.sh({'ENV' => 'test'}, 'rails')
595
+ #
596
+ # @see run
597
+ #
598
+ # @param cmd (see run)
599
+ # @param preserve_spaces (see run)
600
+ # @param options (see run)
601
+ # @return [Process::Status]
602
+ # when command was executed
603
+ # @return [nil]
604
+ # in error case (like command not found)
605
+ def sh(*cmd, preserve_spaces: false, **options)
606
+ ShellRenderer.sh(self, cmd, options, preserve_spaces)
607
+ end
608
+
609
+ # Execute a shell program and return output. Limit the lines displayed.
610
+ #
611
+ # @example Capture output and error
612
+ # status, out, err = ui.run('ls ./ && ls ./this_does_not_exist')
613
+ # # => #<Process::Status: pid 25562 exit 1>
614
+ # # => [...] # the output of first `ls`
615
+ # # => ["ls: ./this_does_not_exist: No such file or directory"]
616
+ #
617
+ # @see sh
618
+ #
619
+ # @param cmd [String]
620
+ # command and optional arguments
621
+ # @param preserve_spaces [true,false]
622
+ # whether the spaces and tabs of the output should be preserve
623
+ # @param max_lines [Integer]
624
+ # limit of displayed lines
625
+ # @param options [Hash] executions options
626
+ # @return [[Process::Status, Array<String>, Array<String>]]
627
+ # process status, output and error output when command was executed
628
+ # @return [nil]
629
+ # in error case (like command not found)
630
+ def run(*cmd, preserve_spaces: false, max_lines: 10, **options)
631
+ result =
632
+ ShellRenderer.run(
633
+ self,
634
+ cmd,
635
+ options,
636
+ preserve_spaces,
637
+ max_lines.clamp(1, Terminal.rows)
602
638
  )
603
- end
639
+ result if result[0]
604
640
  end
605
641
 
606
642
  #
@@ -749,28 +785,20 @@ module NattyUI
749
785
  # # Italian, Polish, Portuguese, Romanian, Spanish and Swedish.
750
786
  #
751
787
  # @overload await(yes: 'Enter', no: 'Esc')
752
- # @param yes [String, Enumerable<String>]
753
- # key code/s a user can input to return positive result
754
- # @param no [String, Enumerable<String>]
755
- # key code/s a user can input to return negative resault
756
- #
757
- # @return [true, false]
758
- # wheter the user inputs a positive result
759
788
  #
760
789
  # @overload await(yes: 'Enter', no: 'Esc', &block)
761
- # @param yes [String, Enumerable<String>]
762
- # key code/s a user can input to return positive result
763
- # @param no [String, Enumerable<String>]
764
- # key code/s a user can input to return negative resault
765
- #
766
790
  # @yieldparam temp [Temporary]
767
791
  # temporary displayed section (section will be erased after input)
768
792
  #
769
- # @return [true, false]
770
- # wheter the user inputs a positive result
771
- # @return nil
772
- # in error case
793
+ # @param yes [String, Enumerable<String>]
794
+ # key code/s a user can input to return positive result
795
+ # @param no [String, Enumerable<String>]
796
+ # key code/s a user can input to return negative resault
773
797
  #
798
+ # @return [true, false]
799
+ # whether the user inputs a positive result
800
+ # @return [nil]
801
+ # in error case
774
802
  def await(yes: 'Enter', no: 'Esc')
775
803
  return __await(yes, no) unless block_given?
776
804
  temporary do |temp|
@@ -783,9 +811,9 @@ module NattyUI
783
811
  # The selected option is returned.
784
812
  #
785
813
  # @overload choice(*choices, abortable: false)
786
- # @param [#to_s] choices
814
+ # @param choices [#to_s]
787
815
  # one or more alternatives to select from
788
- # @param [true, false] abortable
816
+ # @param abortable [true, false]
789
817
  # whether the user is allowed to abort with 'Esc' or 'Ctrl+c'
790
818
  #
791
819
  # @return [Integer]
@@ -800,9 +828,9 @@ module NattyUI
800
828
  # # => 1, when bananas are user's favorite
801
829
  # # => 2, when user is a oranges lover
802
830
  #
803
- # @param [#to_s] choices
831
+ # @param choices[#to_s]
804
832
  # one or more alternatives to select from
805
- # @param [true, false] abortable
833
+ # @param abortable[true, false]
806
834
  # whether the user is allowed to abort with 'Esc' or 'Ctrl+c'
807
835
  #
808
836
  # @yieldparam temp [Temporary]
@@ -814,11 +842,11 @@ module NattyUI
814
842
  # when user aborted the selection
815
843
  #
816
844
  # @overload choice(**choices, abortable: false)
817
- # @param [#to_s] choices
845
+ # @param choices [#to_s]
818
846
  # one or more alternatives to select from
819
- # @param [true, false] abortable
847
+ # @param abortable [true, false]
820
848
  # whether the user is allowed to abort with 'Esc' or 'Ctrl+c'
821
- # @param [#to_s, nil] selected
849
+ # @param selected [#to_s, nil]
822
850
  # optionally pre-selected option
823
851
  #
824
852
  # @return [Object]
@@ -836,13 +864,13 @@ module NattyUI
836
864
  # r: 'Rio',
837
865
  # abortable: true
838
866
  # ) { ui.puts 'Which terminal emulator do you like?' }
839
- # # => wheter the user selected: :k, :i, :g, :t, :r
867
+ # # => whether the user selected: :k, :i, :g, :t, :r
840
868
  # # => nil, when the user aborted
841
- # @param [#to_s] choices
869
+ # @param choices[#to_s]
842
870
  # one or more alternatives to select from
843
- # @param [true, false] abortable
871
+ # @param abortable[true, false]
844
872
  # whether the user is allowed to abort with 'Esc' or 'Ctrl+c'
845
- # @param [Integer] selected
873
+ # @param selected[Integer]
846
874
  # pre-selected option index
847
875
  #
848
876
  # @yieldparam temp [Temporary]
@@ -867,11 +895,11 @@ module NattyUI
867
895
  # Allows the user to select from several options.
868
896
  # All options are returned with their selection status.
869
897
  #
870
- # @param [{#to_s => [true,false]}] choices
898
+ # @param choices [{#to_s => [true,false]}]
871
899
  # Hash of options and their selection state
872
- # @param [true, false] abortable
900
+ # @param abortable [true, false]
873
901
  # whether the user is allowed to abort with 'Esc' or 'Ctrl+c'
874
- # @param [#to_s, nil] selected
902
+ # @param selected [#to_s, nil]
875
903
  # optionally pre-selected key
876
904
  #
877
905
  # @yieldparam temp [Temporary]
@@ -900,11 +928,11 @@ module NattyUI
900
928
  # ui.puts '[i]Which terminal applications did you already tested?[/i]'
901
929
  # end
902
930
  #
903
- # @param [Array<#to_s>] choices
931
+ # @param choices [Array<#to_s>]
904
932
  # selectable options
905
- # @param [true, false] abortable
933
+ # @param abortable [true, false]
906
934
  # whether the user is allowed to abort with 'Esc' or 'Ctrl+c'
907
- # @param [Integer, :all, nil] selected
935
+ # @param selected [Integer, :all, nil]
908
936
  # optionally pre-selected option index or `:all` to pre-select all items
909
937
  # @yieldparam temp [Temporary]
910
938
  # temporary displayed section (section will be erased after input)
@@ -937,7 +965,7 @@ module NattyUI
937
965
  # @!group Utilities
938
966
  #
939
967
 
940
- # @!visibility private
968
+ # @private
941
969
  def columns = Terminal.columns
942
970
 
943
971
  # Display some temporary content.
@@ -983,15 +1011,16 @@ module NattyUI
983
1011
  end
984
1012
  end
985
1013
 
986
- dir = __dir__
1014
+ dir = __dir__ # call the function once
1015
+
987
1016
  autoload :Framed, "#{dir}/framed.rb"
988
1017
  autoload :Section, "#{dir}/section.rb"
989
- autoload :ShellCommand, "#{dir}/shell_command.rb"
990
1018
  autoload :Table, "#{dir}/table.rb"
991
1019
  autoload :Task, "#{dir}/task.rb"
992
1020
  autoload :Temporary, "#{dir}/temporary.rb"
993
1021
  autoload :Theme, "#{dir}/theme.rb"
994
1022
  autoload :Utils, "#{dir}/utils.rb"
1023
+ private_constant(:Framed, :Utils)
995
1024
 
996
1025
  autoload :Choice, "#{dir}/choice.rb"
997
1026
  autoload :DumbChoice, "#{dir}/dumb_choice.rb"
@@ -999,27 +1028,25 @@ module NattyUI
999
1028
  autoload :DumbOptions, "#{dir}/dumb_options.rb"
1000
1029
  autoload :Progress, "#{dir}/progress.rb"
1001
1030
  autoload :DumbProgress, "#{dir}/progress.rb"
1002
-
1003
- autoload :CompactLSRenderer, "#{dir}/ls_renderer.rb"
1004
- autoload :HBarsRenderer, "#{dir}/hbars_renderer.rb"
1005
- autoload :LSRenderer, "#{dir}/ls_renderer.rb"
1006
- autoload :VBarsRenderer, "#{dir}/vbars_renderer.rb"
1007
-
1008
1031
  private_constant(
1009
- :Framed,
1010
- :ShellCommand,
1011
- :Utils,
1012
- # -
1013
1032
  :Choice,
1014
1033
  :DumbChoice,
1015
1034
  :Options,
1016
1035
  :DumbOptions,
1017
1036
  :Progress,
1018
- :DumbProgress,
1019
- # -
1037
+ :DumbProgress
1038
+ )
1039
+
1040
+ autoload :CompactLSRenderer, "#{dir}/ls_renderer.rb"
1041
+ autoload :HBarsRenderer, "#{dir}/hbars_renderer.rb"
1042
+ autoload :LSRenderer, "#{dir}/ls_renderer.rb"
1043
+ autoload :ShellRenderer, "#{dir}/shell_renderer.rb"
1044
+ autoload :VBarsRenderer, "#{dir}/vbars_renderer.rb"
1045
+ private_constant(
1020
1046
  :CompactLSRenderer,
1021
1047
  :HBarsRenderer,
1022
1048
  :LSRenderer,
1049
+ :ShellRenderer,
1023
1050
  :VBarsRenderer
1024
1051
  )
1025
1052
  end
@@ -6,10 +6,10 @@ module NattyUI
6
6
  # {Element} with a frame around the content used by {Features.framed}.
7
7
  #
8
8
  class Framed < Element
9
- # @!visibility private
9
+ # @private
10
10
  def closed? = @bottom ? false : true
11
11
 
12
- # @!visibility private
12
+ # @private
13
13
  def puts(*objects, **options)
14
14
  return self if closed?
15
15
  options[:align] = @align
@@ -17,14 +17,14 @@ module NattyUI
17
17
  super
18
18
  end
19
19
 
20
- # @!visibility private
20
+ # @private
21
21
  def done
22
22
  return if closed?
23
23
  @parent.puts(@bottom)
24
24
  @bottom = nil
25
25
  end
26
26
 
27
- # @!visibility private
27
+ # @private
28
28
  def inspect = "#{_to_s.chop} align=#{@align.inspect} closed?=#{closed?}>"
29
29
 
30
30
  private
@@ -47,6 +47,7 @@ module NattyUI
47
47
 
48
48
  class Item
49
49
  attr_reader :width
50
+
50
51
  def to_s(in_width) = "#{@str}#{' ' * (in_width - @width)}"
51
52
 
52
53
  def initialize(str)
@@ -54,6 +55,7 @@ module NattyUI
54
55
  @width = Text.width(str)
55
56
  end
56
57
  end
58
+
57
59
  private_constant :Item
58
60
  end
59
61
  end
@@ -73,5 +73,6 @@ module NattyUI
73
73
  end
74
74
  end
75
75
  end
76
+
76
77
  private_constant :Options
77
78
  end
@@ -44,6 +44,11 @@ module NattyUI
44
44
  redraw
45
45
  end
46
46
 
47
+ # Increment {value} and/or change {title}.
48
+ #
49
+ # @param count [Integer] increment
50
+ # @param title [#to_s] new title
51
+ # @return [ProgressHelper] itself
47
52
  def step(count: 1, title: nil)
48
53
  @title = title if title
49
54
  self.value += count
@@ -53,7 +58,7 @@ module NattyUI
53
58
  alias _to_s to_s
54
59
  private :_to_s
55
60
 
56
- # @!visibility private
61
+ # @private
57
62
  def to_s
58
63
  return "#{title}: #{format('%5.2f', @value)}" unless @max
59
64
  "#{@title}: #{
@@ -66,7 +71,7 @@ module NattyUI
66
71
  }"
67
72
  end
68
73
 
69
- # @!visibility private
74
+ # @private
70
75
  def inspect = "#{_to_s.chop} #{self}>"
71
76
  end
72
77
 
@@ -15,7 +15,7 @@ module NattyUI
15
15
  class Section < Element
16
16
  include WithStatus
17
17
 
18
- # @!visibility private
18
+ # @private
19
19
  def puts(*objects, **options) = @state ? self : super
20
20
 
21
21
  private
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'theme'
4
+
5
+ module NattyUI
6
+ module ShellRenderer
7
+ def self.sh(parent, cmd, options, space)
8
+ opts_out, opts_err = opts_fom(Theme.current)
9
+ Terminal.sh(*cmd, **options) do |line, kind|
10
+ parent.puts(
11
+ space ? line.gsub("\t", '    ').gsub(/[[:space:]]/, ' ') : line,
12
+ **(kind == :error ? opts_err : opts_out)
13
+ )
14
+ end
15
+ end
16
+
17
+ if Terminal.ansi?
18
+ def self.opts_fom(theme)
19
+ out = theme.mark(:sh_out)
20
+ err = theme.mark(:sh_err)
21
+ [
22
+ {
23
+ bbcode: false,
24
+ prefix: "#{out}#{theme.sh_out_style}",
25
+ prefix_width: out.width
26
+ },
27
+ {
28
+ bbcode: false,
29
+ prefix: "#{err}#{theme.sh_err_style}",
30
+ prefix_width: err.width
31
+ }
32
+ ]
33
+ end
34
+
35
+ def self.run(parent, cmd, options, space, tail)
36
+ theme = Theme.current
37
+ opref = "#{theme.mark(:sh_out)}#{theme.sh_out_style}"
38
+ epref = "#{theme.mark(:sh_err)}#{theme.sh_err_style}"
39
+ out, err, show = [], [], []
40
+ start = NattyUI.lines_written
41
+ [
42
+ Terminal.sh(*cmd, **options) do |line, kind|
43
+ start = NattyUI.back_to_line(start)
44
+ ol = space ? line.gsub("\t", '    ').gsub(/[[:space:]]/, ' ') : line
45
+ if kind == :error
46
+ err << line
47
+ show << "#{epref}#{ol}"
48
+ else
49
+ out << line
50
+ show << "#{opref}#{ol}"
51
+ end
52
+ parent.puts(*show, bbcode: false, tail: tail)
53
+ end,
54
+ out,
55
+ err
56
+ ]
57
+ end
58
+ else
59
+ def self.opts_fom(theme)
60
+ out = theme.mark(:sh_out)
61
+ err = theme.mark(:sh_err)
62
+ [
63
+ { bbcode: false, prefix: out, prefix_width: out.width },
64
+ { bbcode: false, prefix: err, prefix_width: err.width }
65
+ ]
66
+ end
67
+
68
+ def self.run(parent, cmd, options, _space, _tail)
69
+ theme = Theme.current
70
+ opref, epref = theme.mark(:sh_out), theme.mark(:sh_err)
71
+ out, err = [], []
72
+ [
73
+ Terminal.sh(*cmd, **options) do |line, kind|
74
+ ol = line.gsub("\t", '    ').gsub(/[[:space:]]/, ' ')
75
+ if kind == :error
76
+ err << line
77
+ parent.puts("#{epref}#{ol}", bbcode: false)
78
+ else
79
+ out << line
80
+ parent.puts("#{opref}#{ol}", bbcode: false)
81
+ end
82
+ end,
83
+ out,
84
+ err
85
+ ]
86
+ end
87
+ end
88
+ end
89
+
90
+ private_constant :ShellRenderer
91
+ end
@@ -157,7 +157,9 @@ module NattyUI
157
157
  ["#{@style}#{' ' * @padding[3]}", "#{' ' * @padding[1]}[/]"]
158
158
  end
159
159
  end
160
+
160
161
  private_constant :Cell
161
162
  end
163
+
162
164
  private_constant :TableRenderer
163
165
  end
@@ -3,11 +3,10 @@
3
3
  require_relative 'element'
4
4
 
5
5
  module NattyUI
6
- # Temprary display section used by
7
- # {Features.temporary}.
6
+ # Temporary display section used by {Features.temporary}.
8
7
  #
9
8
  class Temporary < Element
10
- # @!visibility private
9
+ # @private
11
10
  def puts(*objects, **opts)
12
11
  return self if @state
13
12
  if opts.delete(:pin)
@@ -16,7 +15,7 @@ module NattyUI
16
15
  super
17
16
  end
18
17
 
19
- # @!visibility private
18
+ # @private
20
19
  def done
21
20
  return self if @state
22
21
  NattyUI.back_to_line(@start_line) if @start_line
@@ -323,6 +323,7 @@ module NattyUI
323
323
  ]
324
324
  end
325
325
  end
326
+
326
327
  private_constant :SectionBorder
327
328
 
328
329
  @ll = {}
@@ -2,5 +2,5 @@
2
2
 
3
3
  module NattyUI
4
4
  # The version number of the gem.
5
- VERSION = '0.31.0'
5
+ VERSION = '0.33.0'
6
6
  end
@@ -129,7 +129,9 @@ module NattyUI
129
129
  def fix? = min_val == max_val
130
130
  def min_dist = value - min_val
131
131
  end
132
+
132
133
  private_constant :Column
133
134
  end
135
+
134
136
  private_constant :WidthFinder
135
137
  end
data/lib/natty-ui.rb CHANGED
@@ -33,7 +33,7 @@ module NattyUI
33
33
  # @return [:dumb]
34
34
  # when terminal does not support ANSI or interactive input
35
35
  # @return [nil]
36
- # when terminal inoput is not supported
36
+ # when terminal input is not supported
37
37
  def input_mode
38
38
  case Terminal.input_mode
39
39
  when :csi_u, :legacy
@@ -56,23 +56,23 @@ module NattyUI
56
56
  def title=(value)
57
57
  if value
58
58
  title = Ansi.plain(value).gsub(/\s+/, ' ')
59
- _write(Ansi.title(title)) if Terminal.ansi?
59
+ Terminal.raw_write(Ansi.title(title)) if Terminal.ansi?
60
60
  @title_stack << title
61
61
  else
62
62
  @title_stack.pop
63
63
  last = @title_stack[-1]
64
- _write(Ansi.title(last)) if last && Terminal.ansi?
64
+ Terminal.raw_write(Ansi.title(last)) if last && Terminal.ansi?
65
65
  end
66
66
  end
67
67
 
68
- # @!visibility private
68
+ # @private
69
69
  attr_reader :lines_written
70
70
 
71
- # @!visibility private
71
+ # @private
72
72
  def back_to_line(number, erase: true)
73
73
  return @lines_written if (c = @lines_written - number) <= 0
74
74
  if Terminal.ansi?
75
- _write(
75
+ Terminal.raw_write(
76
76
  if erase == :all
77
77
  Ansi.cursor_prev_line(c) + Ansi::SCREEN_ERASE_BELOW
78
78
  elsif erase
@@ -85,21 +85,19 @@ module NattyUI
85
85
  @lines_written = number
86
86
  end
87
87
 
88
- # @!visibility private
88
+ # @private
89
89
  def alternate_screen
90
90
  return yield unless Terminal.ansi?
91
91
  begin
92
- _write(Ansi::SCREEN_ALTERNATE)
92
+ Terminal.raw_write(Ansi::SCREEN_ALTERNATE)
93
93
  yield
94
94
  ensure
95
- _write(Ansi::SCREEN_ALTERNATE_OFF)
95
+ Terminal.raw_write(Ansi::SCREEN_ALTERNATE_OFF)
96
96
  end
97
97
  end
98
98
 
99
99
  private
100
100
 
101
- def _write(str) = Terminal.__send__(:_write, str)
102
-
103
101
  def with(element)
104
102
  Terminal.hide_cursor if @element == self
105
103
  current, @element = @element, element
@@ -118,7 +116,7 @@ end
118
116
  unless defined?(Kernel.ui)
119
117
  module Kernel
120
118
  # @attribute [r] ui
121
- # @return [NattyUI::Features] current used ui element
119
+ # @return [NattyUI::Features] current used UI element
122
120
  # @see NattyUI.element
123
121
  def ui = NattyUI.element
124
122
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: natty-ui
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.31.0
4
+ version: 0.33.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Blumtritt
@@ -15,14 +15,14 @@ dependencies:
15
15
  requirements:
16
16
  - - ">="
17
17
  - !ruby/object:Gem::Version
18
- version: 0.13.0
18
+ version: 0.14.0
19
19
  type: :runtime
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
23
  - - ">="
24
24
  - !ruby/object:Gem::Version
25
- version: 0.13.0
25
+ version: 0.14.0
26
26
  description: |
27
27
  This is the beautiful, nice, nifty, fancy, neat, pretty, cool, rich, lovely,
28
28
  natty user interface tool you like to have for your command line applications.
@@ -52,6 +52,7 @@ files:
52
52
  - examples/named-colors.rb
53
53
  - examples/options.rb
54
54
  - examples/sections.rb
55
+ - examples/sh.rb
55
56
  - examples/tables.rb
56
57
  - examples/tasks.rb
57
58
  - examples/themes.rb
@@ -69,7 +70,7 @@ files:
69
70
  - lib/natty-ui/options.rb
70
71
  - lib/natty-ui/progress.rb
71
72
  - lib/natty-ui/section.rb
72
- - lib/natty-ui/shell_command.rb
73
+ - lib/natty-ui/shell_renderer.rb
73
74
  - lib/natty-ui/table.rb
74
75
  - lib/natty-ui/table_renderer.rb
75
76
  - lib/natty-ui/task.rb
@@ -1,132 +0,0 @@
1
- module NattyUI
2
- module ShellCommand
3
- class << self
4
- def call(*cmd, shell: false, input: nil, **options)
5
- options = options.except(:in, :out, :err)
6
- env = (cmd[0].is_a?(Hash) ? cmd.shift.dup : {}).freeze
7
- if shell
8
- cmd = cmd.map! { _escape(it) }.join(' ')
9
- elsif cmd.size == 1 && cmd[0].include?(' ')
10
- cmd = cmd[0]
11
- end
12
- cmd.freeze
13
- input = Input.for(input)
14
- ret = nil
15
- with_io(options, input) do |cio, out_r, err_r, in_w|
16
- thread = Process.detach(Process.spawn(env, *cmd, options))
17
- begin
18
- cio.each(&:close)
19
- read = [out_r, err_r]
20
- write = [in_w] if in_w
21
- while !read.empty? || write
22
- rr, wr, = IO.select(read, write)
23
- if rr.include?(out_r)
24
- begin
25
- yield(out_r.readline(chomp: true), :output)
26
- rescue SystemCallError, IOError
27
- read.delete(out_r)
28
- end
29
- end
30
- if rr.include?(err_r)
31
- begin
32
- yield(err_r.readline(chomp: true), :error)
33
- rescue SystemCallError, IOError
34
- read.delete(err_r)
35
- end
36
- end
37
- next if wr.empty?
38
- begin
39
- next if input.call(in_w)
40
- rescue SystemCallError, IOError
41
- # nop
42
- end
43
- in_w.close
44
- write = nil
45
- end
46
- ensure
47
- ret = thread.join.value
48
- end
49
- end
50
- ret
51
- rescue SystemCallError, IOError
52
- nil
53
- end
54
-
55
- private
56
-
57
- def with_io(options, input)
58
- IO.pipe do |out_r, out_w|
59
- IO.pipe do |err_r, err_w|
60
- cio = [options[:out] = out_w, options[:err] = err_w]
61
- return yield(cio, out_r, err_r) unless input
62
- IO.pipe do |in_r, in_w|
63
- cio << (options[:in] = in_r)
64
- in_w.sync = true
65
- yield(cio, out_r, err_r, in_w)
66
- end
67
- end
68
- end
69
- end
70
-
71
- def _escape(str)
72
- return +"''" if str.empty?
73
- str = str.dup
74
- str.gsub!(%r{[^A-Za-z0-9_\-.,:+/@\n]}, "\\\\\\&")
75
- str.gsub!("\n", "'\n'")
76
- str
77
- end
78
- end
79
-
80
- module Input
81
- def self.for(obj)
82
- return unless obj
83
- return CopyWriter.new(obj) if obj.respond_to?(:readpartial)
84
- return CopyWriter.new(obj.to_io) if obj.respond_to?(:to_io)
85
- return ArrayWriter.new(obj) if obj.is_a?(Array)
86
- return EnumerableWriter.new(obj) if obj.respond_to?(:each)
87
- return ArrayWriter.new(obj.to_a) if obj.respond_to?(:to_a)
88
- Writer.new(obj)
89
- end
90
-
91
- class Writer
92
- def call(io) = (io.write(_next) if @obj)
93
- def initialize(obj) = (@obj = obj)
94
- def _next = (_, @obj = @obj, nil).first
95
- end
96
-
97
- class CopyWriter < Writer
98
- def call(io) = (IO.copy_stream(_next, io) if @obj)
99
- end
100
-
101
- class ArrayWriter
102
- def call(io) = io.write(@ry[@idx += 1] || return)
103
-
104
- def initialize(ary)
105
- @ry = ary
106
- @idx = -1
107
- end
108
- end
109
-
110
- class EnumerableWriter
111
- def call(io)
112
- io.write(@enum.next)
113
- rescue StopIteration
114
- false
115
- end
116
-
117
- def initialize(enum)
118
- @enum =
119
- if enum.respond_to?(:enum_for)
120
- enum.enum_for(:each)
121
- else
122
- Enumerator.new { |y| enum.each { y << it } }
123
- end
124
- end
125
- end
126
- end
127
-
128
- private_constant :Input
129
- end
130
-
131
- private_constant :ShellCommand
132
- end