eskimo 1.0.0 → 2.0.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 (42) hide show
  1. checksums.yaml +4 -4
  2. data/lib/eskimo.rb +20 -4
  3. data/lib/eskimo/component.rb +2 -2
  4. data/lib/eskimo/components/did_you_mean.rb +34 -0
  5. data/lib/eskimo/components/either.rb +30 -0
  6. data/lib/eskimo/components/highlight.rb +31 -0
  7. data/lib/eskimo/components/highlight_column.rb +61 -0
  8. data/lib/eskimo/components/indent.rb +25 -0
  9. data/lib/eskimo/components/line_break.rb +18 -0
  10. data/lib/eskimo/components/soft_break.rb +16 -0
  11. data/lib/eskimo/components/squeeze.rb +43 -0
  12. data/lib/eskimo/components/strip.rb +15 -0
  13. data/lib/eskimo/components/strip_left.rb +15 -0
  14. data/lib/eskimo/components/strip_right.rb +15 -0
  15. data/lib/eskimo/components/style.rb +25 -0
  16. data/lib/eskimo/components/truncate.rb +31 -0
  17. data/lib/eskimo/components/truncate_rear.rb +25 -0
  18. data/lib/eskimo/components/wrap.rb +26 -0
  19. data/lib/eskimo/constants.rb +7 -0
  20. data/lib/eskimo/renderer.rb +15 -17
  21. data/lib/eskimo/version.rb +1 -1
  22. data/spec/component_spec.rb +13 -0
  23. data/spec/components/did_you_mean_spec.rb +21 -0
  24. data/spec/components/either_spec.rb +21 -0
  25. data/spec/components/highlight_column_spec.rb +63 -0
  26. data/spec/components/highlight_spec.rb +25 -0
  27. data/spec/components/indent_spec.rb +15 -0
  28. data/spec/components/line_break_spec.rb +17 -0
  29. data/spec/components/soft_break_spec.rb +17 -0
  30. data/spec/components/squeeze_spec.rb +61 -0
  31. data/spec/components/strip_left_spec.rb +15 -0
  32. data/spec/components/strip_right_spec.rb +15 -0
  33. data/spec/components/strip_spec.rb +15 -0
  34. data/spec/components/style_spec.rb +25 -0
  35. data/spec/components/truncate_rear_spec.rb +35 -0
  36. data/spec/components/truncate_spec.rb +35 -0
  37. data/spec/components/wrap_spec.rb +15 -0
  38. data/spec/spec_helper.rb +8 -0
  39. data/spec/support/component_suite.rb +15 -0
  40. metadata +52 -5
  41. data/lib/eskimo/components.rb +0 -114
  42. data/spec/components_spec.rb +0 -159
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5912c4b1987656f45fa2fc0beb17228f1cc967db41c084675774baf24167bb9f
4
- data.tar.gz: d8f3d3d02a29fabd13444207a972e3f92e0403d1ff5612d4fc40876e1dc349d6
3
+ metadata.gz: 7882c146ce7e288df43b38765be92f216137d746c1efb13cf76b1ac7e1ec13ad
4
+ data.tar.gz: 1e2bff1433d29f448a74bf39b54b083b6bc79869af86b00c293fefaa09493624
5
5
  SHA512:
6
- metadata.gz: fa006a58bbd5ad12d24e52a3401ed14d7ecc8a98cc5e494856dcba95666df4ff3be54eab24902e8167d687f7e6d8daca5e3d33da90ddf67efdce6cc2e87cab01
7
- data.tar.gz: 4c249f2b9b14cc4521b516ba78c0f1bbbbf7454600888a4eaab4ce55492f9e51447e48897be98d47c1d639b0a41fc70c2febbed6be955a0d978bcebcd2592f87
6
+ metadata.gz: 77d8528c5d5f839c7bbf8daf9bb049fe752c5077b34107e007bdba14b1192723760763750ea4061d2a4e60bf8573c11133ff3d174363d3eadb8f2fe1252eaa11
7
+ data.tar.gz: 8dfa377b6eb2e05e09eb8e5d70b2a747fc5b9073e5859055145bf66c413e3051239ea55ca9d386936ee5905e1382dd2938140c512aaf4360af9010fb16986a49
@@ -2,9 +2,25 @@ require 'pastel'
2
2
  require 'strings'
3
3
  require 'tty-screen'
4
4
 
5
- require_relative './eskimo/version'
5
+ require 'eskimo/version'
6
6
 
7
- require_relative './eskimo/component'
8
- require_relative './eskimo/renderer'
7
+ require 'eskimo/constants'
9
8
 
10
- require_relative './eskimo/components'
9
+ require 'eskimo/component'
10
+ require 'eskimo/renderer'
11
+
12
+ require 'eskimo/components/did_you_mean'
13
+ require 'eskimo/components/either'
14
+ require 'eskimo/components/highlight'
15
+ require 'eskimo/components/highlight_column'
16
+ require 'eskimo/components/indent'
17
+ require 'eskimo/components/line_break'
18
+ require 'eskimo/components/soft_break'
19
+ require 'eskimo/components/squeeze'
20
+ require 'eskimo/components/strip'
21
+ require 'eskimo/components/strip_left'
22
+ require 'eskimo/components/strip_right'
23
+ require 'eskimo/components/style'
24
+ require 'eskimo/components/truncate'
25
+ require 'eskimo/components/truncate_rear'
26
+ require 'eskimo/components/wrap'
@@ -20,8 +20,8 @@ module Eskimo
20
20
  # `render` prop provided by {Renderer#apply} with the tracked children
21
21
  # which converts them to a String and returns them.
22
22
  class Component
23
- def initialize(&children)
24
- @children = children
23
+ def initialize(*, **, &children_gen)
24
+ @children = children_gen
25
25
  end
26
26
 
27
27
  def render(render:, **)
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Eskimo
4
+ module Components
5
+ # Present the user with the closest possible correction, if any.
6
+ #
7
+ # DidYouMean.new(dictionary: [ 'abc', 'bca' ], item: 'abd')
8
+ # # => "hint: Did you mean? abc"
9
+ #
10
+ # DidYouMean.new(dictionary: [ 'abc', 'bca' ], item: 'asdfasdf')
11
+ # # => ""
12
+ #
13
+ # See https://github.com/yuki24/did_you_mean#using-the-didyoumeanspellchecker
14
+ class DidYouMean < Component
15
+ attr_reader :corrections, :separator
16
+
17
+ def initialize(dictionary:, item:, separator: " or ", &children)
18
+ @corrections = ::DidYouMean::SpellChecker.new(
19
+ dictionary: dictionary
20
+ ).correct(item)
21
+
22
+ @separator = separator
23
+
24
+ super
25
+ end
26
+
27
+ def render(**)
28
+ if corrections.any?
29
+ "Did you mean? #{corrections.join(separator)}"
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Eskimo
4
+ module Components
5
+ # Render a fallback component in case the first one evaluates to an empty
6
+ # String.
7
+ #
8
+ # Either.new(->(**) { false }, "Fallback here")
9
+ # # => "Fallback here"
10
+ #
11
+ # Either.new(->(**) { "Hi!" }, "Fallback here")
12
+ # # => "Hi!"
13
+ #
14
+ class Either
15
+ attr_reader :children
16
+
17
+ def initialize(primary, fallback)
18
+ @children = [ primary, fallback ]
19
+ end
20
+
21
+ def render(render:, **)
22
+ for child in children do
23
+ rendered = render[child]
24
+
25
+ return rendered unless rendered.empty?
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Eskimo
4
+ module Components
5
+ # Highlight a substring with ASCII arrows.
6
+ #
7
+ # Highlight.new(pattern: /lol/) do
8
+ # "- include: lol://file.yml"
9
+ # end
10
+ # # => "- include: lol://file.yml"
11
+ # # ^^^
12
+ #
13
+ class Highlight < Component
14
+ attr_reader :pastel, :pattern, :style
15
+
16
+ def initialize(pattern:, style: [:red, :bold, :underline], &children)
17
+ @pastel = Pastel.new
18
+ @pattern = pattern
19
+ @style = style
20
+
21
+ super(&children)
22
+ end
23
+
24
+ def render(**)
25
+ super.sub(pattern) do |substring|
26
+ pastel.decorate(substring, *style)
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,61 @@
1
+ module Eskimo
2
+ module Components
3
+ # Highlight a particular character of a string with an ASCII arrow.
4
+ #
5
+ # HighlightColumn.new(line: 0, column: 14) do
6
+ # "- include: lol://wut.yml"
7
+ # end
8
+ # => "- include: lol://wut.yml"
9
+ # " ^ "
10
+ # " here "
11
+ class HighlightColumn < Component
12
+ def initialize(
13
+ column:,
14
+ line:,
15
+ markers: ['^', 'here'],
16
+ style: [:bold, :red],
17
+ &children
18
+ )
19
+ pastel = Pastel.new
20
+
21
+ @colorize = ->(str) { pastel.decorate(str, *style) }
22
+ @column = column
23
+ @line = line
24
+ @marker_padding = ' ' * @column
25
+ @markers = markers
26
+
27
+ super
28
+ end
29
+
30
+ def render(**)
31
+ lines = super.lines
32
+ line = lines[@line]
33
+
34
+ unless line.nil? || line[@column].nil?
35
+ lines[@line] = transform_line!(line, @column, &@colorize)
36
+ end
37
+
38
+ lines.join
39
+ end
40
+
41
+ protected
42
+
43
+ def create_markers()
44
+ buf = ''
45
+
46
+ for marker in @markers do
47
+ buf << @marker_padding + @colorize[marker] + "\n"
48
+ end
49
+
50
+ buf
51
+ end
52
+
53
+ def transform_line!(line, column, &fn)
54
+ line[column] = fn[line[column]]
55
+ line << "\n" unless line.end_with?("\n")
56
+ line << create_markers
57
+ line
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Eskimo
4
+ module Components
5
+ # Indent text from the left.
6
+ #
7
+ # Indent.new(width: 8) do
8
+ # [ "Hello", SoftBreak.new, "World!" ]
9
+ # end
10
+ # # => " Hello"
11
+ # # " World!"
12
+ class Indent < Component
13
+ attr_reader :width
14
+
15
+ def initialize(width: 4, &children)
16
+ @width = width
17
+ super
18
+ end
19
+
20
+ def render(**)
21
+ Strings.pad(super, [0,0,0,width])
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Eskimo
4
+ module Components
5
+ # Insert a paragraph-like line-break.
6
+ #
7
+ # [ "Hello", LineBreak.new, "World!" ]
8
+ # # => "Hello"
9
+ # # ""
10
+ # # ""
11
+ # # "World!"
12
+ class LineBreak
13
+ def render(**)
14
+ "\n \n"
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Eskimo
4
+ module Components
5
+ # Insert a soft line-break.
6
+ #
7
+ # [ "Hello", SoftBreak.new, "World!" ]
8
+ # # => "Hello"
9
+ # # "World!"
10
+ class SoftBreak
11
+ def render(**)
12
+ "\n"
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Eskimo
4
+ module Components
5
+ # Squeeze immediate consecutive soft breaks.
6
+ #
7
+ # Squeeze.new do
8
+ # [
9
+ # SoftBreak.new,
10
+ # ConditionalComponent.new,
11
+ #
12
+ # SoftBreak.new,
13
+ # false && SomeOtherComponent.new,
14
+ #
15
+ # SoftBreak.new,
16
+ # 'hello',
17
+ # ]
18
+ # end
19
+ # # => ""
20
+ # # "hello"
21
+ #
22
+ # The soft breaks for each conditional component will be preserved only
23
+ # if they do render some content.
24
+ class Squeeze
25
+ def initialize(children)
26
+ if !children.is_a?(Array) || block_given?
27
+ raise ArgumentError.new("Squeeze works only with an Array of components")
28
+ end
29
+
30
+ @children = children
31
+ end
32
+
33
+ def render(**props)
34
+ rendered = @children.map(&props[:render])
35
+
36
+ without_blanks = rendered.reject(&:empty?)
37
+ without_blanks.reject.with_index do |element, index|
38
+ element == "\n" && without_blanks[index+1] == "\n"
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Eskimo
4
+ module Components
5
+ # Remove surrounding whitespace.
6
+ #
7
+ # Strip.new { " hello world " }
8
+ # # => "hello world"
9
+ class Strip < Component
10
+ def render(**)
11
+ super.strip
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Eskimo
4
+ module Components
5
+ # Remove whitespace from the beginning.
6
+ #
7
+ # StripLeft.new { " hello world " }
8
+ # # => "hello world "
9
+ class StripLeft < Component
10
+ def render(**)
11
+ super.lstrip
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Eskimo
4
+ module Components
5
+ # Remove whitespace from the end.
6
+ #
7
+ # StripRight.new { " hello world " }
8
+ # # => " hello world"
9
+ class StripRight < Component
10
+ def render(**)
11
+ super.rstrip
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Eskimo
4
+ module Components
5
+ # Style text with colors and custom formatting.
6
+ #
7
+ # See [Pastel's documentation][pastel] for the accepted styles.
8
+ #
9
+ # [pastel]: https://github.com/piotrmurach/pastel
10
+ class Style < Component
11
+ attr_reader :pastel, :style
12
+
13
+ def initialize(*style, &children)
14
+ @style = style.flatten
15
+ @pastel = Pastel.new
16
+
17
+ super
18
+ end
19
+
20
+ def render(**)
21
+ pastel.decorate(super, *style)
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Eskimo
4
+ module Components
5
+ # Truncate text from the beginning if it exceeds a certain width.
6
+ #
7
+ # Truncate.new(width: 3) do
8
+ # "foo bar"
9
+ # end
10
+ # # => "... bar"
11
+ class Truncate < Component
12
+ attr_reader :maxlen
13
+
14
+ def initialize(reserve: 0, width: Constants::SCREEN_COLUMNS, &children)
15
+ @maxlen = [0, width - reserve].max
16
+
17
+ super
18
+ end
19
+
20
+ def render(**)
21
+ text = super
22
+
23
+ if text.length >= maxlen
24
+ '...' + text[text.length - maxlen - 1 .. -1]
25
+ else
26
+ text
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'eskimo/components/truncate'
4
+
5
+ module Eskimo
6
+ module Components
7
+ # Truncate text from the rear if it exceeds a certain width.
8
+ #
9
+ # TruncateRear.new(width: 3) do
10
+ # "foo bar"
11
+ # end
12
+ # # => "foo..."
13
+ class TruncateRear < Truncate
14
+ def render(render:, **)
15
+ text = render[@children]
16
+
17
+ if text.length >= maxlen
18
+ text[0..maxlen - 1] + '...'
19
+ else
20
+ text
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end