natty-ui 0.12.0 → 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 +23 -24
  4. data/examples/24bit-colors.rb +4 -9
  5. data/examples/3bit-colors.rb +28 -8
  6. data/examples/8bit-colors.rb +18 -23
  7. data/examples/attributes.rb +30 -25
  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 -18
  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 +47 -56
  36. data/examples/animate.rb +0 -44
  37. data/examples/attributes_list.rb +0 -14
  38. data/examples/demo.rb +0 -53
  39. data/examples/message.rb +0 -32
  40. data/examples/progress.rb +0 -68
  41. data/examples/query.rb +0 -41
  42. data/examples/read_key.rb +0 -13
  43. data/examples/table.rb +0 -41
  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 -521
  52. data/lib/natty-ui/ansi_wrapper.rb +0 -199
  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 -60
  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 -67
  70. data/lib/natty-ui/wrapper/progress.rb +0 -74
  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 -551
  76. data/lib/natty-ui/wrapper/task.rb +0 -55
  77. data/lib/natty-ui/wrapper.rb +0 -230
data/examples/progress.rb DELETED
@@ -1,68 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative '../lib/natty-ui'
4
-
5
- ui.space
6
- ui.h1 'NattyUI: Progress Indication'
7
- ui.space
8
-
9
- # just simulate some work
10
- if ENV.key?('NO_WAIT')
11
- def something = nil
12
- def some = nil
13
- else
14
- def something = sleep(0.5)
15
- def some = sleep(0.15)
16
- end
17
-
18
- ui.info 'Tasks are sections to visualize step by step processing.' do
19
- ui.task 'Assemble assets' do
20
- ui.task('Initialize') { something }
21
-
22
- progress = ui.progress 'Connect to server...'
23
- 20.times do
24
- progress.step
25
- some
26
- end
27
- progress.ok 'Connected'
28
-
29
- ui.task('Collect files...') { something }
30
-
31
- ui.task 'Compile files...' do
32
- %w[readme.txt main.css main.html sub.html].each do |name|
33
- ui.msg "Compile file [bright_yellow]./source/#{name}[/]...", glyph: :dot
34
- something
35
- end
36
- ui.done 'Files compiled.'
37
- end
38
-
39
- progress = ui.progress('Compress files', max_value: 11)
40
- 11.times do
41
- progress.step
42
- something
43
- end
44
- progress.done 'All compressed'
45
-
46
- ui.task('Signing') { something }
47
-
48
- ui.task('Store assembled results') { something }
49
- end
50
-
51
- ui.puts(
52
- 'The details are removed ([i]in ANSI version[/i]) when the task',
53
- 'ended sucessfully.'
54
- )
55
- end
56
-
57
- ui.info 'Details of failed tasks will not be cleaned.' do
58
- ui.task 'Assemble assets' do
59
- ui.task('Initialize') { something }
60
- ui.task('Connect to Server') do
61
- something
62
- ui.failed 'Unable to connect to server'
63
- end
64
- ui.error 'This code will not be reachd!'
65
- end
66
- end
67
-
68
- ui.space
data/examples/query.rb DELETED
@@ -1,41 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative '../lib/natty-ui'
4
-
5
- ui.space
6
- ui.h1 'NattyUI: User Queries'
7
- ui.space
8
-
9
- # little helper
10
- def abort!
11
- ui.failed 'aborted'
12
- ui.space
13
- exit
14
- end
15
-
16
- unless ui.ask('Do you like to continute? (Y|n): ')
17
- ui.info 'ok, try later!'
18
- ui.space
19
- exit
20
- end
21
-
22
- choice =
23
- ui.query(
24
- 'Which fruits do you prefer?',
25
- 'Apples',
26
- '[yellow]Bananas[/]',
27
- 'Cherries',
28
- x: 'No fruits'
29
- )
30
- abort! unless choice
31
- ui.info "Your choice: #{choice}"
32
-
33
- answer = ui.request 'What is your favorite verb?: '
34
- abort! unless answer
35
- ui.info "Your answer: #{answer.inspect}"
36
-
37
- answer = ui.request('What is your current password?:', password: true)
38
- abort! unless answer
39
- ui.info "I'll keep your secret!"
40
-
41
- 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]:[/] ' 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,41 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative '../lib/natty-ui'
4
-
5
- ui.space
6
- ui.h1 'NattyUI: Tables'
7
- ui.space
8
-
9
- User = Struct.new(:id, :name, :mail, :notes)
10
- users = [
11
- User.new(
12
- 1,
13
- 'Henry',
14
- 'henry@some.test',
15
- 'This is fill text to generate a wide column ' \
16
- 'which maybe rendered as multi line.'
17
- ),
18
- User.new(2, 'Sam', 'sam-sam@some.test', "enforced\nmulti-line"),
19
- User.new(3, 'Taylor', 'taylor@some.test')
20
- ]
21
-
22
- ui.message 'Simple Table' do
23
- ui.space
24
- ui.table User.members.map(&:capitalize), *users
25
- end
26
-
27
- ui.space
28
-
29
- ui.message 'Styled Table' do
30
- users[0].notes = 'Short notice'
31
-
32
- ui.space
33
- ui.table(expand: true) do |table|
34
- table.add(User.members.map(&:capitalize), style: 'bold green')
35
- users.each { |user| table.add(user) }
36
- table.style_column(0, 'bold green')
37
- table.align_column(0, :center)
38
- end
39
- end
40
-
41
- 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