natty-ui 0.12.1 → 0.25.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.
Files changed (77) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +1 -1
  3. data/README.md +22 -26
  4. data/examples/24bit-colors.rb +4 -7
  5. data/examples/3bit-colors.rb +28 -6
  6. data/examples/8bit-colors.rb +18 -21
  7. data/examples/attributes.rb +30 -22
  8. data/examples/cols.rb +40 -0
  9. data/examples/elements.rb +31 -0
  10. data/examples/examples.rb +45 -0
  11. data/examples/illustration.rb +56 -54
  12. data/examples/ls.rb +16 -16
  13. data/examples/named-colors.rb +23 -0
  14. data/examples/sections.rb +29 -0
  15. data/examples/tables.rb +62 -0
  16. data/examples/tasks.rb +52 -0
  17. data/lib/natty-ui/attributes.rb +604 -0
  18. data/lib/natty-ui/choice.rb +56 -0
  19. data/lib/natty-ui/dumb_choice.rb +45 -0
  20. data/lib/natty-ui/element.rb +78 -0
  21. data/lib/natty-ui/features.rb +798 -0
  22. data/lib/natty-ui/framed.rb +51 -0
  23. data/lib/natty-ui/ls_renderer.rb +93 -0
  24. data/lib/natty-ui/progress.rb +187 -0
  25. data/lib/natty-ui/section.rb +69 -0
  26. data/lib/natty-ui/table.rb +241 -0
  27. data/lib/natty-ui/table_renderer.rb +147 -0
  28. data/lib/natty-ui/task.rb +44 -0
  29. data/lib/natty-ui/temporary.rb +38 -0
  30. data/lib/natty-ui/theme.rb +303 -0
  31. data/lib/natty-ui/utils.rb +79 -0
  32. data/lib/natty-ui/version.rb +1 -1
  33. data/lib/natty-ui/width_finder.rb +125 -0
  34. data/lib/natty-ui.rb +89 -147
  35. metadata +44 -53
  36. data/examples/animate.rb +0 -42
  37. data/examples/attributes_list.rb +0 -12
  38. data/examples/demo.rb +0 -51
  39. data/examples/message.rb +0 -30
  40. data/examples/progress.rb +0 -66
  41. data/examples/query.rb +0 -39
  42. data/examples/read_key.rb +0 -13
  43. data/examples/table.rb +0 -39
  44. data/lib/natty-ui/animation/binary.rb +0 -36
  45. data/lib/natty-ui/animation/default.rb +0 -38
  46. data/lib/natty-ui/animation/matrix.rb +0 -51
  47. data/lib/natty-ui/animation/rainbow.rb +0 -28
  48. data/lib/natty-ui/animation/type_writer.rb +0 -44
  49. data/lib/natty-ui/animation.rb +0 -69
  50. data/lib/natty-ui/ansi/constants.rb +0 -75
  51. data/lib/natty-ui/ansi.rb +0 -530
  52. data/lib/natty-ui/ansi_wrapper.rb +0 -232
  53. data/lib/natty-ui/frame.rb +0 -53
  54. data/lib/natty-ui/glyph.rb +0 -64
  55. data/lib/natty-ui/key_map.rb +0 -142
  56. data/lib/natty-ui/preload.rb +0 -12
  57. data/lib/natty-ui/spinner.rb +0 -120
  58. data/lib/natty-ui/text/east_asian_width.rb +0 -2529
  59. data/lib/natty-ui/text.rb +0 -203
  60. data/lib/natty-ui/wrapper/animate.rb +0 -17
  61. data/lib/natty-ui/wrapper/ask.rb +0 -78
  62. data/lib/natty-ui/wrapper/element.rb +0 -79
  63. data/lib/natty-ui/wrapper/features.rb +0 -21
  64. data/lib/natty-ui/wrapper/framed.rb +0 -45
  65. data/lib/natty-ui/wrapper/heading.rb +0 -64
  66. data/lib/natty-ui/wrapper/horizontal_rule.rb +0 -37
  67. data/lib/natty-ui/wrapper/list_in_columns.rb +0 -138
  68. data/lib/natty-ui/wrapper/message.rb +0 -109
  69. data/lib/natty-ui/wrapper/mixins.rb +0 -75
  70. data/lib/natty-ui/wrapper/progress.rb +0 -63
  71. data/lib/natty-ui/wrapper/query.rb +0 -89
  72. data/lib/natty-ui/wrapper/quote.rb +0 -25
  73. data/lib/natty-ui/wrapper/request.rb +0 -54
  74. data/lib/natty-ui/wrapper/section.rb +0 -118
  75. data/lib/natty-ui/wrapper/table.rb +0 -550
  76. data/lib/natty-ui/wrapper/task.rb +0 -55
  77. data/lib/natty-ui/wrapper.rb +0 -239
@@ -1,109 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'section'
4
-
5
- module NattyUI
6
- module Features
7
- # Creates a section with a highlighted `title` and prints given additional
8
- # arguments as lines into the section.
9
- #
10
- # @param [#to_s] title object to print as section title
11
- # @param [Array<#to_s>] args more objects to print
12
- # @param [Symbol, #to_s] glyph used for the title; see {NattyUI::Glyph}
13
- # @yieldparam [Wrapper::Message] message the created section
14
- # @return [Object] the result of the code block
15
- # @return [Wrapper::Message] itself, when no code block is given
16
- def message(title, *args, glyph: :default, &block)
17
- _section(:Message, args, title: title, glyph: glyph, &block)
18
- end
19
- alias msg message
20
-
21
- # Creates a informational message section with a highlighted `title` and
22
- # prints given additional arguments as lines into the section.
23
- #
24
- # @param [#to_s] title object to print as section title
25
- # @param [Array<#to_s>] args more objects to print
26
- # @yieldparam (see #message)
27
- # @return (see #message)
28
- def information(title, *args, &block)
29
- _section(:Message, args, title: title, glyph: :information, &block)
30
- end
31
- alias info information
32
-
33
- # Creates a warning message section with a highlighted `title` and
34
- # prints given additional arguments as lines into the section.
35
- #
36
- # @param (see #information)
37
- # @yieldparam (see #message)
38
- # @return (see #message)
39
- def warning(title, *args, &block)
40
- _section(:Message, args, title: title, glyph: :warning, &block)
41
- end
42
- alias warn warning
43
-
44
- # Creates a error message section with a highlighted `title` and
45
- # prints given additional arguments as lines into the section.
46
- #
47
- # @param (see #information)
48
- # @yieldparam (see #message)
49
- # @return (see #message)
50
- def error(title, *args, &block)
51
- _section(:Message, args, title: title, glyph: :error, &block)
52
- end
53
- alias err error
54
-
55
- # Creates a completion message section with a highlighted `title` and
56
- # prints given additional arguments as lines into the section.
57
- #
58
- # When used for a {#task} section it closes this section with status `:ok`.
59
- #
60
- # @param (see #information)
61
- # @yieldparam (see #message)
62
- # @return (see #message)
63
- def completed(title, *args, &block)
64
- _section(:Message, args, title: title, glyph: :completed, &block)
65
- end
66
- alias done completed
67
- alias ok completed
68
-
69
- # Creates a failure message section with a highlighted `title` and
70
- # prints given additional arguments as lines into the section.
71
- #
72
- # When used for a {#task} section it closes this section with status
73
- # `:failed`.
74
- #
75
- # @param (see #information)
76
- # @yieldparam (see #message)
77
- # @return (see #message)
78
- def failed(title, *args, &block)
79
- _section(:Message, args, title: title, glyph: :failed, &block)
80
- end
81
- end
82
-
83
- class Wrapper
84
- #
85
- # A {Section} with a highlighted title.
86
- #
87
- # @see Features#message
88
- # @see Features#information
89
- # @see Features#warning
90
- # @see Features#error
91
- # @see Features#completed
92
- # @see Features#failed
93
- class Message < Section
94
- protected
95
-
96
- def initialize(parent, title:, glyph:)
97
- glyph = NattyUI::Glyph[glyph]
98
- prefix_width = Text.width(glyph) + 1
99
- super(
100
- parent,
101
- prefix: ' ' * prefix_width,
102
- prefix_width: prefix_width,
103
- suffix_width: 0
104
- )
105
- parent.puts(title, prefix: "#{glyph} ", prefix_width: prefix_width)
106
- end
107
- end
108
- end
109
- end
@@ -1,75 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module NattyUI
4
- #
5
- # Additional attributes for progression elements.
6
- #
7
- # Progression elements have additional states ({#completed?}, {#failed?}) and
8
- # can be closed with calling {Features#completed} or {Features#failed}.
9
- #
10
- # @see Wrapper::Progress
11
- # @see Wrapper::Task
12
- #
13
- module ProgressAttributes
14
- # @attribute [r] completed?
15
- # @return [Boolean] whether the task completed successfully
16
- def completed? = (@status == :completed)
17
-
18
- # @attribute [r] failed?
19
- # @return [Boolean] whether the task failed
20
- def failed? = (@status == :failed)
21
-
22
- # @!visibility private
23
- def completed(*args)
24
- @final_text = args unless args.empty?
25
- _close(:completed)
26
- end
27
- alias done completed
28
- alias ok completed
29
-
30
- # @!visibility private
31
- def failed(*args)
32
- @final_text = args unless args.empty?
33
- _close(:failed)
34
- end
35
- end
36
-
37
- #
38
- # Additional attributes for progression elements.
39
- #
40
- # @see Wrapper::Progress
41
- #
42
- module ValueAttributes
43
- # @return [Float] current value
44
- attr_reader :value
45
-
46
- def value=(value)
47
- @value = [0, value.to_f].max
48
- @max_value = @value if @max_value&.< @value
49
- redraw
50
- end
51
-
52
- # @return [String, nil] current information
53
- attr_reader :info
54
-
55
- def info=(value)
56
- @info = value
57
- redraw
58
- end
59
-
60
- # Maximum value.
61
- #
62
- # @return [Float] maximum value
63
- # @return [nil] when no max_value was configured
64
- attr_reader :max_value
65
-
66
- # Increase the value by given amount.
67
- #
68
- # @param increment [#to_f] value increment
69
- # @return [Wrapper::Element] itself
70
- def step(increment = 1)
71
- self.value = @value + increment.to_f
72
- self
73
- end
74
- end
75
- end
@@ -1,63 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'element'
4
- require_relative 'mixins'
5
-
6
- module NattyUI
7
- module Features
8
- # Creates progress element implementing additional {ProgressAttributes}.
9
- #
10
- # When a `max_value` is given, the progress will by displayed as a bar.
11
- # Otherwise the `spinner` is used for a little animation.
12
- #
13
- # When no pre-defined spinner is specified then spinner will be
14
- # used char-wise as a string for the progress animation.
15
- #
16
- # A progress element has additional states and can be closed with
17
- # {#completed} or {#failed}.
18
- #
19
- # @param [#to_s] title object to print as progress title
20
- # @param [#to_f] max_value maximum value of the progress
21
- # @param [Symbol, #to_a, #to_s] spinner spinner type; see {NattyUI::Spinner}
22
- # @return [Wrapper::Progress] the created progress element
23
- def progress(title, max_value: nil, spinner: :default)
24
- _element(:Progress, title, max_value, spinner)
25
- end
26
- end
27
-
28
- class Wrapper
29
- #
30
- # An {Element} displaying a progression.
31
- #
32
- # @see Features#progress
33
- class Progress < Element
34
- include ProgressAttributes
35
- include ValueAttributes
36
-
37
- protected
38
-
39
- def call(title, max_value, _spinner)
40
- @final_text = [title]
41
- @max_value = [0, max_value.to_f].max if max_value
42
- @value = @progress = 0
43
- (wrapper.stream << @parent.prefix << "➔ #{title} ").flush
44
- self
45
- end
46
-
47
- def redraw
48
- return if @status
49
- return (wrapper.stream << '.').flush unless @max_value
50
- cn = (20 * @value / @max_value).to_i
51
- return if @progress == cn
52
- (wrapper.stream << ('.' * (cn - @progress))).flush
53
- @progress = cn
54
- end
55
-
56
- def finish
57
- wrapper.stream << "\n"
58
- return @parent.failed(*@final_text) if failed?
59
- @parent.message(*@final_text, glyph: @status = :completed)
60
- end
61
- end
62
- end
63
- end
@@ -1,89 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'element'
4
-
5
- module NattyUI
6
- module Features
7
- # Request a choice from user.
8
- #
9
- # @example Select by Index
10
- # choice = ui.query(
11
- # 'Which fruits do you prefer?',
12
- # 'Apples',
13
- # 'Bananas',
14
- # 'Cherries'
15
- # )
16
- # # => '1' or '2' or '3' or nil if user aborted
17
- #
18
- # @example Select by given char
19
- # choice = ui.query(
20
- # 'Which fruits do you prefer?',
21
- # a: 'Apples',
22
- # b: 'Bananas',
23
- # c: 'Cherries'
24
- # )
25
- # # => 'a' or 'b' or 'c' or nil if user aborted
26
- #
27
- # @see NattyUI.in_stream
28
- #
29
- # @param question [#to_s] Question to display
30
- # @param choices [#to_s] choices selectable via index (0..9)
31
- # @param result [Symbol] defines how the result will be returned
32
- # @param display [Symbol] display choices as `:list` or `:compact`
33
- # @param kw_choices [{Char => #to_s}] choices selectable with given char
34
- # @return [Char] when `result` is configured as `:char`
35
- # @return [#to_s] when `result` is configured as `:choice`
36
- # @return [[Char, #to_s]] when `result` is configured as `:both`
37
- # @return [nil] when input was aborted with `^C` or `^D`
38
- def query(question, *choices, result: :char, display: :list, **kw_choices)
39
- _element(:Query, question, choices, kw_choices, result, display)
40
- end
41
- end
42
-
43
- class Wrapper
44
- #
45
- # An {Element} to request a user choice.
46
- #
47
- # @see Features#query
48
- class Query < Element
49
- protected
50
-
51
- def call(question, choices, kw_choices, result, display)
52
- return if choices.empty? && kw_choices.empty?
53
- choices = as_choices(choices, kw_choices)
54
- text = choices.map { |k, v| "⦗#{CHOICE_MARK}#{k}#{Ansi::RESET}⦘ #{v}" }
55
- @parent.wrapper.temporary do
56
- if display == :compact
57
- @parent.msg(question, glyph: :query).ls(text)
58
- else
59
- @parent.msg(question, *text, glyph: :query)
60
- end
61
- read(choices, result)
62
- end
63
- end
64
-
65
- def as_choices(choices, kw_choices)
66
- choices
67
- .take(9)
68
- .each_with_index
69
- .to_h { |str, i| [i + 1, str] }
70
- .merge!(kw_choices)
71
- .transform_keys!(&:to_s)
72
- end
73
-
74
- def read(choices, result)
75
- while true
76
- char = NattyUI.read_key
77
- return if char == 'Ctrl+C'
78
- next unless choices.key?(char)
79
- return char if result == :char
80
- return choices[char] if result == :title
81
- return char, choices[char]
82
- end
83
- end
84
-
85
- CHOICE_MARK = Ansi[:bold, 34]
86
- private_constant :CHOICE_MARK
87
- end
88
- end
89
- end
@@ -1,25 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'element'
4
-
5
- module NattyUI
6
- module Features
7
- # Creates a quotation section and prints given arguments as lines
8
- # into the section.
9
- #
10
- # @param (see #section)
11
- # @yieldparam (see #section)
12
- # @return [Object] the result of the code block
13
- # @return [Wrapper::Quote] itself, when no code block is given
14
- def quote(*args, &block) = _section(:Quote, args, prefix: '▍ ', &block)
15
- end
16
-
17
- class Wrapper
18
- #
19
- # A quotation {Section}.
20
- #
21
- # @see Features#quote
22
- class Quote < Section
23
- end
24
- end
25
- end
@@ -1,54 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'element'
4
-
5
- module NattyUI
6
- module Features
7
- # Request user input.
8
- #
9
- # @param question [#to_s] Question to display
10
- # @param password [Boolean] whether to hide the input
11
- # @return [String] the user input
12
- # @return [nil] when input was aborted with `^C` or `^D`
13
- def request(question, password: false)
14
- _element(:Request, question, password)
15
- end
16
- end
17
-
18
- class Wrapper
19
- #
20
- # An {Element} to request user input.
21
- #
22
- # @see Features#request
23
- class Request < Element
24
- protected
25
-
26
- def call(question, password)
27
- draw(question)
28
- return NattyUI.in_stream.getpass if password
29
- NattyUI.in_stream.gets(chomp: true)
30
- rescue Interrupt, SystemCallError
31
- nil
32
- ensure
33
- (wrapper = @parent.wrapper).ansi? and
34
- (wrapper.stream << ANSI_FINISH).flush
35
- end
36
-
37
- def draw(question)
38
- wrapper = @parent.wrapper
39
- glyph = NattyUI :Glyph[:query]
40
- @parent.print(
41
- question,
42
- prefix: "#{glyph} #{Ansi[255]}",
43
- prefix_width: Text.width(glyph) + 1,
44
- suffix_width: 0
45
- )
46
- (wrapper.stream << ANSI_PREFIX).flush if wrapper.ansi?
47
- end
48
-
49
- ANSI_PREFIX = Ansi::RESET + Ansi::ITALIC
50
- ANSI_FINISH = Ansi::RESET + Ansi::LINE_PREVIOUS + Ansi::LINE_ERASE
51
- private_constant :ANSI_PREFIX, :ANSI_FINISH
52
- end
53
- end
54
- end
@@ -1,118 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'element'
4
-
5
- module NattyUI
6
- module Features
7
- # Creates a default section and prints given arguments as lines
8
- # into the section.
9
- #
10
- # @param [Array<#to_s>] args optional objects to print
11
- # @param [String] prefix used for each printed line
12
- # @param [String] suffix used for each printed line
13
- # @yieldparam [Wrapper::Section] section the created section
14
- # @return [Object] the result of the code block
15
- # @return [Wrapper::Section] itself, when no code block is given
16
- def section(*args, prefix: ' ', suffix: ' ', &block)
17
- _section(:Section, args, prefix: prefix, suffix: suffix, &block)
18
- end
19
- alias sec section
20
- end
21
-
22
- class Wrapper
23
- #
24
- # Visual {Element} to keep text lines together.
25
- #
26
- # A section can contain other elements and sections.
27
- #
28
- # @see Features#section
29
- class Section < Element
30
- # @return [Integer] available columns count within the section
31
- def available_width
32
- @available_width ||=
33
- @parent.available_width - @prefix_width - @suffix_width
34
- end
35
-
36
- # Print given arguments line-wise into the section.
37
- #
38
- # @param [#to_s] args objects to print
39
- # @option options [:left, :right, :center] :align text alignment
40
- # @return [Section] itself
41
- def puts(*args, **options)
42
- return self if @status
43
- @parent.puts(
44
- *args,
45
- **options.merge!(
46
- prefix: "#{@prefix}#{options[:prefix]}",
47
- prefix_width: @prefix_width + options[:prefix_width].to_i,
48
- suffix: "#{options[:suffix]}#{@suffix}",
49
- suffix_width: @suffix_width + options[:suffix_width].to_i
50
- )
51
- )
52
- self
53
- end
54
-
55
- # Print given arguments into the section.
56
- #
57
- # @param [#to_s] args objects to print
58
- # @option options [:left, :right, :center] :align text alignment
59
- # @return [Section] itself
60
- def print(*args, **options)
61
- return self if @status
62
- @parent.print(
63
- *args,
64
- **options.merge!(
65
- prefix: "#{@prefix}#{options[:prefix]}",
66
- prefix_width: @prefix_width + options[:prefix_width].to_i,
67
- suffix: "#{options[:suffix]}#{@suffix}",
68
- suffix_width: @suffix_width + options[:suffix_width].to_i
69
- )
70
- )
71
- self
72
- end
73
-
74
- # Add at least one empty line
75
- #
76
- # @param [#to_i] lines count of lines
77
- # @return [Section] itself
78
- def space(lines = 1) = puts("\n" * [1, lines.to_i].max)
79
-
80
- # @note The screen manipulation is only available in ANSI mode see {#ansi?}
81
- #
82
- # Resets the part of the screen written below the current output line when
83
- # the given block ended.
84
- #
85
- # @example
86
- # section.temporary do |temp|
87
- # temp.info('This message will disappear in 5 seconds!')
88
- # sleep 5
89
- # end
90
- #
91
- # @yield [Section] itself
92
- # @return [Object] block result
93
- def temporary = block_given? ? yield(self) : self
94
-
95
- # @!visibility private
96
- def inspect = @status ? "#{_to_s[..-2]} status=#{@status}>" : _to_s
97
-
98
- # @!visibility private
99
- def rcol = @parent.rcol - @suffix_width
100
-
101
- protected
102
-
103
- def initialize(
104
- parent,
105
- prefix:,
106
- prefix_width: Text.width(prefix),
107
- suffix: nil,
108
- suffix_width: Text.width(suffix)
109
- )
110
- super(parent)
111
- @prefix = prefix
112
- @suffix = suffix
113
- @prefix_width = prefix_width
114
- @suffix_width = suffix_width
115
- end
116
- end
117
- end
118
- end