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
data/examples/progress.rb DELETED
@@ -1,66 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative '../lib/natty-ui'
4
-
5
- ui.h1 'NattyUI: Progress Indication', space: 2
6
-
7
- # just simulate some work
8
- if ENV.key?('NO_WAIT')
9
- def something = nil
10
- def some = nil
11
- else
12
- def something = sleep(0.5)
13
- def some = sleep(0.15)
14
- end
15
-
16
- ui.info 'Tasks are sections to visualize step by step processing.' do
17
- ui.task 'Assemble assets' do
18
- ui.task('Initialize') { something }
19
-
20
- progress = ui.progress 'Connect to server...'
21
- 20.times do
22
- progress.step
23
- some
24
- end
25
- progress.ok 'Connected'
26
-
27
- ui.task('Collect files...') { something }
28
-
29
- ui.task 'Compile files...' do
30
- %w[readme.txt main.css main.html sub.html].each do |name|
31
- ui.msg "Compile file [bright_yellow]./source/#{name}[/]...", glyph: :dot
32
- something
33
- end
34
- ui.done 'Files compiled.'
35
- end
36
-
37
- progress = ui.progress('Compress files', max_value: 11)
38
- 11.times do
39
- progress.step
40
- something
41
- end
42
- progress.done 'All compressed'
43
-
44
- ui.task('Signing') { something }
45
-
46
- ui.task('Store assembled results') { something }
47
- end
48
-
49
- ui.puts(
50
- 'The details are removed ([i]in ANSI version[/i]) when the task',
51
- 'ended sucessfully.'
52
- )
53
- end
54
-
55
- ui.info 'Details of failed tasks will not be cleaned.' do
56
- ui.task 'Assemble assets' do
57
- ui.task('Initialize') { something }
58
- ui.task('Connect to Server') do
59
- something
60
- ui.failed 'Unable to connect to server'
61
- end
62
- ui.error 'This code will not be reachd!'
63
- end
64
- end
65
-
66
- ui.space
data/examples/query.rb DELETED
@@ -1,39 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative '../lib/natty-ui'
4
-
5
- ui.h1 'NattyUI: User Queries', space: 2
6
-
7
- # little helper
8
- def abort!
9
- ui.failed 'aborted'
10
- ui.space
11
- exit
12
- end
13
-
14
- unless ui.ask('Do you like to continute? (Y|n): ')
15
- ui.info 'ok, try later!'
16
- ui.space
17
- exit
18
- end
19
-
20
- choice =
21
- ui.query(
22
- 'Which fruits do you prefer?',
23
- 'Apples',
24
- '[yellow]Bananas[/]',
25
- 'Cherries',
26
- x: 'No fruits'
27
- )
28
- abort! unless choice
29
- ui.info "Your choice: #{choice}"
30
-
31
- answer = ui.request 'What is your favorite verb?: '
32
- abort! unless answer
33
- ui.info "Your answer: #{answer.inspect}"
34
-
35
- answer = ui.request('What is your current password?:', password: true)
36
- abort! unless answer
37
- ui.info "I'll keep your secret!"
38
-
39
- ui.space
data/examples/read_key.rb DELETED
@@ -1,13 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative '../lib/natty-ui'
4
-
5
- ui.puts '⌨️ Display Keyboard Input [bright_black](Exit with Ctrl+C)'
6
-
7
- ui.section prefix: '[blue]:[/fg] ' do
8
- while true
9
- raw, name = NattyUI.read_key(mode: :both)
10
- ui.puts "[yellow]#{raw.inspect}[/] [bold bright_green]#{name}[/]"
11
- break if name == 'Ctrl+C'
12
- end
13
- end
data/examples/table.rb DELETED
@@ -1,39 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative '../lib/natty-ui'
4
-
5
- ui.h1 'NattyUI: Tables', space: 2
6
-
7
- User = Struct.new(:id, :name, :mail, :notes)
8
- users = [
9
- User.new(
10
- 1,
11
- 'Henry',
12
- 'henry@some.test',
13
- 'This is fill text to generate a wide column ' \
14
- 'which maybe rendered as multi line.'
15
- ),
16
- User.new(2, 'Sam', 'sam-sam@some.test', "enforced\nmulti-line"),
17
- User.new(3, 'Taylor', 'taylor@some.test')
18
- ]
19
-
20
- ui.message 'Simple Table' do
21
- ui.space
22
- ui.table User.members.map(&:capitalize), *users
23
- end
24
-
25
- ui.space
26
-
27
- ui.message 'Styled Table' do
28
- users[0].notes = 'Short notice'
29
-
30
- ui.space
31
- ui.table(expand: true) do |table|
32
- table.add(User.members.map(&:capitalize), style: 'bold green')
33
- users.each { |user| table.add(user) }
34
- table.style_column(0, 'bold green')
35
- table.align_column(0, :center)
36
- end
37
- end
38
-
39
- ui.space
@@ -1,36 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module NattyUI
4
- module Animation
5
- class Binary < Base
6
- protected
7
-
8
- def write(stream)
9
- @style = attribute(:style, :default)
10
- @alt_style = attribute(:alt_style, :bright_white)
11
- binary = @lines.map { |_, size| Array.new(size) { rand_char } }
12
- 35.times do |i|
13
- binary.each do |chars|
14
- rc = rand_char
15
- chars.pop
16
- chars.unshift(rc.size == 1 ? @style + rc : rc)
17
- puts(stream, chars.join)
18
- end
19
- (stream << @top).flush
20
- sleep(i / 300.0)
21
- end
22
- super
23
- end
24
-
25
- def rand_char
26
- return "#{@alt_style}#{CHARS.sample}#{@style}" if rand < 0.2
27
- CHARS.sample
28
- end
29
-
30
- CHARS = %w[0 1].freeze
31
- end
32
-
33
- define binary: Binary
34
- private_constant :Binary
35
- end
36
- end
@@ -1,38 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module NattyUI
4
- module Animation
5
- class Default < Base
6
- protected
7
-
8
- def write(stream)
9
- num = 0
10
- style = attribute(:style, :default)
11
- @lines.each do |line, size|
12
- time = 0.25 / size
13
- stream << style
14
- line = Text.plain(line)
15
- if (num += 1).odd?
16
- stream << @pos1
17
- line.each_char do |char|
18
- (stream << char).flush
19
- sleep(time)
20
- end
21
- else
22
- stream << Ansi.cursor_column(@prefix_width + size - 1)
23
- line.reverse.each_char do |char|
24
- (stream << char << CURSOR_LEFT).flush
25
- sleep(time)
26
- end
27
- end
28
- stream << Ansi::RESET << @pos1 << line << Ansi::LINE_NEXT
29
- end
30
- end
31
-
32
- CURSOR_LEFT = Ansi.cursor_back(2).freeze
33
- end
34
-
35
- define default: Default
36
- private_constant :Default
37
- end
38
- end
@@ -1,51 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module NattyUI
4
- module Animation
5
- class Matrix < Base
6
- protected
7
-
8
- def write(stream)
9
- plains = @lines.map { |line, _| Text.plain(line) }
10
- encs = @lines.map { Array.new(_2) { CHARS.sample }.join }
11
- poss = @lines.map { Array.new(_2, &:itself).shuffle }
12
- stream << attribute(:style, :default)
13
- until poss.all?(&:empty?)
14
- poss.each_with_index do |pos, idx|
15
- next stream << Ansi::LINE_NEXT if pos.empty?
16
- line = plains[idx]
17
- if (count = (pos.size / 11.0).round) < 2
18
- encs[idx] = enc = line
19
- pos.clear
20
- else
21
- enc = encs[idx]
22
- pos.pop(count).each { enc[_1] = line[_1] }
23
- pos.sample(pos.size / 3).each { enc[_1] = CHARS.sample }
24
- end
25
- puts(stream, enc)
26
- end
27
- (stream << @top).flush
28
- sleep(0.1)
29
- end
30
- super
31
- end
32
-
33
- def print2(line)
34
- line = Text.plain(line)
35
- str = Array.new(line.size) { CHARS.sample }.join
36
- pos = Array.new(line.size, &:itself).shuffle
37
- until pos.size < 4
38
- pos.shift(pos.size / 4).each { str[_1] = line[_1] }
39
- pos.sample(pos.size / 2).each { str[_1] = CHARS.sample }
40
- (@stream << "#{@prefix}#{str}").flush
41
- sleep(0.08)
42
- end
43
- end
44
-
45
- CHARS = '2598Z*):.\=+-¦|_ヲアウエオカキケコサシスセソタツテナニヌネハヒホマミムメモヤユラリワ'.chars.freeze
46
- end
47
-
48
- define matrix: Matrix
49
- private_constant :Matrix
50
- end
51
- end
@@ -1,28 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module NattyUI
4
- module Animation
5
- class Rainbow < Base
6
- protected
7
-
8
- def write(stream)
9
- plain = @lines.map { |line, _| Text.plain(line) }
10
- 11.upto(180) do |spread|
11
- spread /= 100.0
12
- plain.each do |line|
13
- puts(
14
- stream,
15
- Ansi.rainbow(line, spread: spread, frequence: 0.1, seed: 0)
16
- )
17
- end
18
- (stream << Ansi::RESET << @top).flush
19
- sleep(0.01)
20
- end
21
- super
22
- end
23
- end
24
-
25
- define rainbow: Rainbow
26
- private_constant :Rainbow
27
- end
28
- end
@@ -1,44 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module NattyUI
4
- module Animation
5
- class TypeWriter < Base
6
- protected
7
-
8
- def write(stream)
9
- num = 0
10
- @style = attribute(:style, :default)
11
- @cursor_style = attribute(:cursor_style, 0x2e)
12
- @lines.each do |line, size|
13
- line = Text.plain(line)
14
- if (num += 1).odd?
15
- stream << @pos1
16
- line.each_char { cursor(stream, _1).flush }
17
- else
18
- stream << Ansi.cursor_column(@prefix_width + size - 1)
19
- line.reverse.each_char do |char|
20
- (cursor(stream, char) << CURSOR_2LEFT).flush
21
- end
22
- end
23
- stream << Ansi::RESET << @pos1 << line << Ansi::LINE_NEXT
24
- end
25
- end
26
-
27
- def cursor(stream, char)
28
- stream << @cursor_style
29
- (SPACE.match?(char) ? '▁' : '▁▂▃▄▅▆▇█').each_char do |cursor|
30
- (stream << cursor << CURSOR_1LEFT).flush
31
- sleep(0.002)
32
- end
33
- stream << @style << char
34
- end
35
-
36
- CURSOR_1LEFT = Ansi.cursor_back(1).freeze
37
- CURSOR_2LEFT = Ansi.cursor_back(2).freeze
38
- SPACE = /[[:space:]]/
39
- end
40
-
41
- define type_writer: TypeWriter
42
- private_constant :TypeWriter
43
- end
44
- end
@@ -1,69 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module NattyUI
4
- module Animation
5
- def self.names = @all.keys
6
-
7
- def self.[](name)
8
- return if name.nil?
9
- klass = @all[name] || @all[:default]
10
- return klass unless klass.is_a?(String)
11
- require(klass)
12
- klass = @all[name] and return klass
13
- raise(LoadError, "unknown animation - #{name}")
14
- end
15
-
16
- def self.define(**kwargs) = @all.merge!(kwargs)
17
-
18
- class Base
19
- attr_reader :lines_written
20
-
21
- def initialize(wrapper, args, kwargs)
22
- @prefix = Text.embellish(kwargs[:prefix])
23
- @suffix = Text.embellish(kwargs[:suffix])
24
- @prefix_width = kwargs[:prefix_width] || Text.width(@prefix)
25
- @lines =
26
- Text.as_lines(
27
- args.map! { Ansi.blemish(_1) },
28
- kwargs[:max_width] ||
29
- wrapper.screen_columns - @prefix_width -
30
- (kwargs[:suffix_width] || Text.width(@suffix))
31
- )
32
- diff = @lines.size - wrapper.screen_rows + 1
33
- @lines = @lines[diff, wrapper.screen_rows] if diff.positive?
34
- @options = kwargs
35
- @prefix_width += 1
36
- @top = Ansi.cursor_up(@lines_written = @lines.count)
37
- @pos1 = Ansi.cursor_column(@prefix_width)
38
- end
39
-
40
- def perform(stream)
41
- @lines.each { stream << "#{@prefix}#{' ' * _2}#{@suffix}\n" }
42
- stream << @top
43
- write(stream)
44
- end
45
-
46
- protected
47
-
48
- def attribute(name, *default)
49
- att = @options[name] or return Ansi[*default]
50
- return Ansi[*att] if att.is_a?(Enumerable)
51
- Ansi.try_convert(att.to_s) || Ansi[*default]
52
- end
53
-
54
- def write(stream) = @lines.each { |line, _| puts(stream, line) }
55
- def puts(stream, line) = stream << @pos1 << line << Ansi::LINE_NEXT
56
- end
57
-
58
- private_constant :Base
59
-
60
- dir = __dir__
61
- @all = {
62
- binary: "#{dir}/animation/binary",
63
- default: "#{dir}/animation/default",
64
- matrix: "#{dir}/animation/matrix",
65
- rainbow: "#{dir}/animation/rainbow",
66
- type_writer: "#{dir}/animation/type_writer"
67
- }.compare_by_identity
68
- end
69
- end
@@ -1,75 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module NattyUI::Ansi
4
- CURSOR_SHOW = "\e[?25h"
5
- CURSOR_HIDE = "\e[?25l"
6
-
7
- CURSOR_HOME = cursor_pos(nil, nil)
8
- CURSOR_FIRST_ROW = cursor_pos(1).freeze
9
- CURSOR_FIRST_COLUMN = cursor_column(1).freeze
10
-
11
- CURSOR_SAFE_POS_SCO = "\e[s"
12
- CURSOR_SAFE_POS_DEC = "\e7"
13
- CURSOR_SAFE_POS = CURSOR_SAFE_POS_DEC
14
-
15
- CURSOR_RESTORE_POS_SCO = "\e[u"
16
- CURSOR_RESTORE_POS_DEC = "\e8"
17
- CURSOR_RESTORE_POS = CURSOR_RESTORE_POS_DEC
18
-
19
- SCREEN_ERASE = screen_erase(:entire)
20
-
21
- SCREEN_SAVE = "\e[?47h"
22
- SCREEN_RESTORE = "\e[?47l"
23
-
24
- SCREEN_ALTERNATE = "\e[?1049h"
25
- SCREEN_ALTERNATE_OFF = "\e[?1049l"
26
-
27
- LINE_PREVIOUS = cursor_previous_line(1).freeze
28
- LINE_NEXT = cursor_next_line(1).freeze
29
- LINE_ERASE = line_erase(:entire)
30
-
31
- RESET = self[:reset].freeze
32
-
33
- BOLD = self[:bold].freeze
34
- BOLD_OFF = self[:bold].freeze
35
-
36
- FAINT = self[:faint].freeze
37
- FAINT_OFF = self[:faint_off].freeze
38
-
39
- ITALIC = self[:italic].freeze
40
- ITALIC_OFF = self[:italic_off].freeze
41
-
42
- STRIKE = self[:strike].freeze
43
- STRIKE_OFF = self[:strike_off].freeze
44
-
45
- UNDERLINE = self[:underline].freeze
46
- DOUBLE_UNDERLINE = self[:double_underline].freeze
47
- UNDERLINE_OFF = self[:underline_off].freeze
48
-
49
- CURLY_UNDERLINE = self[:curly_underline].freeze
50
- CURLY_UNDERLINE_OFF = self[:curly_underline_off].freeze
51
-
52
- BLINK = self[:blink].freeze
53
- BLINK_OFF = self[:blink_off].freeze
54
-
55
- INVERT = self[:invert].freeze
56
- INVERT_OFF = self[:invert_off].freeze
57
-
58
- HIDE = self[:hide].freeze
59
- REVEAL = self[:reveal].freeze
60
-
61
- # @!visibility private
62
- CLS = "#{CURSOR_HOME}#{SCREEN_ERASE}".freeze
63
-
64
- # @!visibility private
65
- CLL = "#{CURSOR_FIRST_COLUMN}#{LINE_ERASE}".freeze
66
-
67
- # @!visibility private
68
- SCREEN_BLANK =
69
- "#{CURSOR_SAFE_POS}#{
70
- SCREEN_ALTERNATE
71
- }#{CURSOR_HOME}#{SCREEN_ERASE}#{RESET}".freeze
72
-
73
- # @!visibility private
74
- SCREEN_UNBLANK = "#{RESET}#{SCREEN_ALTERNATE_OFF}#{CURSOR_RESTORE_POS}".freeze
75
- end