charming 0.1.2 → 0.1.3

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 (68) hide show
  1. checksums.yaml +4 -4
  2. data/lib/charming/application.rb +3 -3
  3. data/lib/charming/controller/class_methods.rb +2 -2
  4. data/lib/charming/controller/command_palette.rb +2 -2
  5. data/lib/charming/controller/rendering.rb +2 -2
  6. data/lib/charming/controller/session_state.rb +1 -1
  7. data/lib/charming/generators/component_generator.rb +1 -1
  8. data/lib/charming/generators/templates/app/application.template +1 -1
  9. data/lib/charming/generators/templates/app/layout.template +3 -6
  10. data/lib/charming/generators/templates/app/view.template +1 -1
  11. data/lib/charming/generators/templates/component/component.rb.template +1 -1
  12. data/lib/charming/generators/templates/screen/view.rb.template +1 -1
  13. data/lib/charming/generators/templates/view/view.rb.template +1 -1
  14. data/lib/charming/internal/renderer/differential.rb +13 -5
  15. data/lib/charming/internal/terminal/tty_backend.rb +22 -2
  16. data/lib/charming/presentation/component.rb +3 -5
  17. data/lib/charming/presentation/components/activity_indicator.rb +173 -134
  18. data/lib/charming/presentation/components/command_palette.rb +94 -96
  19. data/lib/charming/presentation/components/command_palette_modal.rb +33 -0
  20. data/lib/charming/presentation/components/empty_state.rb +47 -49
  21. data/lib/charming/presentation/components/form/builder.rb +52 -54
  22. data/lib/charming/presentation/components/form/confirm.rb +49 -51
  23. data/lib/charming/presentation/components/form/field.rb +94 -96
  24. data/lib/charming/presentation/components/form/input.rb +53 -55
  25. data/lib/charming/presentation/components/form/note.rb +27 -29
  26. data/lib/charming/presentation/components/form/select.rb +84 -86
  27. data/lib/charming/presentation/components/form/textarea.rb +67 -69
  28. data/lib/charming/presentation/components/form.rb +120 -122
  29. data/lib/charming/presentation/components/keyboard_handler.rb +41 -43
  30. data/lib/charming/presentation/components/list.rb +123 -125
  31. data/lib/charming/presentation/components/markdown.rb +21 -23
  32. data/lib/charming/presentation/components/modal.rb +46 -48
  33. data/lib/charming/presentation/components/progressbar.rb +51 -53
  34. data/lib/charming/presentation/components/spinner.rb +40 -42
  35. data/lib/charming/presentation/components/table.rb +109 -111
  36. data/lib/charming/presentation/components/text_area.rb +219 -221
  37. data/lib/charming/presentation/components/text_input.rb +120 -122
  38. data/lib/charming/presentation/components/viewport.rb +218 -220
  39. data/lib/charming/presentation/layout/builder.rb +64 -66
  40. data/lib/charming/presentation/layout/overlay.rb +48 -50
  41. data/lib/charming/presentation/layout/pane.rb +122 -118
  42. data/lib/charming/presentation/layout/rect.rb +14 -16
  43. data/lib/charming/presentation/layout/screen_layout.rb +40 -42
  44. data/lib/charming/presentation/layout/split.rb +101 -103
  45. data/lib/charming/presentation/layout.rb +28 -30
  46. data/lib/charming/presentation/markdown/block_renderers.rb +94 -96
  47. data/lib/charming/presentation/markdown/inline_renderers.rb +52 -54
  48. data/lib/charming/presentation/markdown/render_context.rb +12 -14
  49. data/lib/charming/presentation/markdown/renderer.rb +84 -86
  50. data/lib/charming/presentation/markdown/syntax_highlighter.rb +57 -59
  51. data/lib/charming/presentation/markdown.rb +4 -6
  52. data/lib/charming/presentation/template_view.rb +22 -24
  53. data/lib/charming/presentation/templates/erb_handler.rb +4 -6
  54. data/lib/charming/presentation/templates.rb +47 -49
  55. data/lib/charming/presentation/ui/ansi_codes.rb +66 -68
  56. data/lib/charming/presentation/ui/ansi_slicer.rb +67 -69
  57. data/lib/charming/presentation/ui/border.rb +24 -26
  58. data/lib/charming/presentation/ui/border_painter.rb +37 -39
  59. data/lib/charming/presentation/ui/canvas.rb +59 -61
  60. data/lib/charming/presentation/ui/style.rb +173 -175
  61. data/lib/charming/presentation/ui/theme.rb +133 -135
  62. data/lib/charming/presentation/ui/width.rb +12 -14
  63. data/lib/charming/presentation/ui.rb +69 -71
  64. data/lib/charming/presentation/view.rb +103 -105
  65. data/lib/charming/runtime.rb +23 -10
  66. data/lib/charming/version.rb +1 -1
  67. data/lib/charming.rb +3 -2
  68. metadata +2 -1
@@ -1,67 +1,65 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Charming
4
- module Presentation
5
- module Markdown
6
- # InlineRenderer dispatches Kramdown inline-level elements (text, strong, em,
7
- # codespan, link, line break, HTML entity) to their individual rendering handlers.
8
- # Handlers are built once at construction as a frozen hash of element-type symbols
9
- # to callables.
10
- class InlineRenderer
11
- # *renderer* is the parent Renderer (used to render nested inlines and look up styles).
12
- def initialize(renderer:)
13
- @renderer = renderer
14
- build_handlers
15
- end
4
+ module Markdown
5
+ # InlineRenderer dispatches Kramdown inline-level elements (text, strong, em,
6
+ # codespan, link, line break, HTML entity) to their individual rendering handlers.
7
+ # Handlers are built once at construction as a frozen hash of element-type symbols
8
+ # to callables.
9
+ class InlineRenderer
10
+ # *renderer* is the parent Renderer (used to render nested inlines and look up styles).
11
+ def initialize(renderer:)
12
+ @renderer = renderer
13
+ build_handlers
14
+ end
16
15
 
17
- # Renders *element* using the handler registered for `element.type`. Unknown types
18
- # fall through to `render_unknown`.
19
- def render(element, context:)
20
- handler = @handlers[element.type] || method(:render_unknown)
21
- handler.call(element, context)
22
- end
16
+ # Renders *element* using the handler registered for `element.type`. Unknown types
17
+ # fall through to `render_unknown`.
18
+ def render(element, context:)
19
+ handler = @handlers[element.type] || method(:render_unknown)
20
+ handler.call(element, context)
21
+ end
23
22
 
24
- private
23
+ private
25
24
 
26
- # The frozen hash of element-type → handler mapping.
27
- attr_reader :handlers
25
+ # The frozen hash of element-type → handler mapping.
26
+ attr_reader :handlers
28
27
 
29
- # Builds the handler hash for text, strong, em, codespan, link, br, and entity.
30
- def build_handlers
31
- r = @renderer
32
- @handlers = {
33
- text: ->(element, _context) { element.value.to_s },
34
- strong: ->(element, context) { render_styled(element, context, :markdown_strong) { |s| s.bold } },
35
- em: ->(element, context) { render_styled(element, context, :markdown_emphasis) { |s| s.italic } },
36
- codespan: ->(element, _context) { r.style_for(:markdown_inline_code, fallback: r.theme_style(:warn)).render(element.value.to_s) },
37
- a: ->(element, context) { send(:render_link, element, context) },
38
- br: ->(_element, _context) { "\n" },
39
- entity: ->(element, _context) { element.value.respond_to?(:char) ? element.value.char : element.value.to_s }
40
- }.freeze
41
- end
28
+ # Builds the handler hash for text, strong, em, codespan, link, br, and entity.
29
+ def build_handlers
30
+ r = @renderer
31
+ @handlers = {
32
+ text: ->(element, _context) { element.value.to_s },
33
+ strong: ->(element, context) { render_styled(element, context, :markdown_strong) { |s| s.bold } },
34
+ em: ->(element, context) { render_styled(element, context, :markdown_emphasis) { |s| s.italic } },
35
+ codespan: ->(element, _context) { r.style_for(:markdown_inline_code, fallback: r.theme_style(:warn)).render(element.value.to_s) },
36
+ a: ->(element, context) { send(:render_link, element, context) },
37
+ br: ->(_element, _context) { "\n" },
38
+ entity: ->(element, _context) { element.value.respond_to?(:char) ? element.value.char : element.value.to_s }
39
+ }.freeze
40
+ end
42
41
 
43
- # Renders a styled inline (strong/em) by first rendering children, then applying
44
- # the theme style and the block-form (e.g., `bold`/`italic`) decoration.
45
- def render_styled(element, context, style_name)
46
- rendered = @renderer.render_inlines(element.children, width: context.width)
47
- style = @renderer.style_for(style_name, fallback: yield(@renderer.theme_style(:text)))
48
- style.render(rendered)
49
- end
42
+ # Renders a styled inline (strong/em) by first rendering children, then applying
43
+ # the theme style and the block-form (e.g., `bold`/`italic`) decoration.
44
+ def render_styled(element, context, style_name)
45
+ rendered = @renderer.render_inlines(element.children, width: context.width)
46
+ style = @renderer.style_for(style_name, fallback: yield(@renderer.theme_style(:text)))
47
+ style.render(rendered)
48
+ end
50
49
 
51
- # Renders a Markdown link as "label <href>" (URL omitted when empty), styled with
52
- # the markdown_link theme token or the info+underline fallback.
53
- def render_link(element, context)
54
- label = @renderer.render_inlines(element.children, width: context.width)
55
- href = element.attr["href"].to_s
56
- rendered = href.empty? ? label : "#{label} <#{href}>"
57
- @renderer.style_for(:markdown_link, fallback: @renderer.theme_style(:info).underline).render(rendered)
58
- end
50
+ # Renders a Markdown link as "label <href>" (URL omitted when empty), styled with
51
+ # the markdown_link theme token or the info+underline fallback.
52
+ def render_link(element, context)
53
+ label = @renderer.render_inlines(element.children, width: context.width)
54
+ href = element.attr["href"].to_s
55
+ rendered = href.empty? ? label : "#{label} <#{href}>"
56
+ @renderer.style_for(:markdown_link, fallback: @renderer.theme_style(:info).underline).render(rendered)
57
+ end
59
58
 
60
- # Fallback for unknown inline types: returns the value when there are no children,
61
- # otherwise recurses into the children.
62
- def render_unknown(element, context)
63
- element.children.empty? ? element.value.to_s : @renderer.render_inlines(element.children, width: context.width)
64
- end
59
+ # Fallback for unknown inline types: returns the value when there are no children,
60
+ # otherwise recurses into the children.
61
+ def render_unknown(element, context)
62
+ element.children.empty? ? element.value.to_s : @renderer.render_inlines(element.children, width: context.width)
65
63
  end
66
64
  end
67
65
  end
@@ -1,21 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Charming
4
- module Presentation
5
- module Markdown
6
- # RenderContext carries the state needed to render nested Markdown blocks: the current
7
- # list nesting depth (used for indentation) and the wrap width.
8
- RenderContext = Data.define(:list_depth, :width) do
9
- # Builds a new RenderContext with the given *width* and optional starting *list_depth*.
10
- def self.from(width:, list_depth: 0)
11
- new(list_depth: list_depth, width: width)
12
- end
4
+ module Markdown
5
+ # RenderContext carries the state needed to render nested Markdown blocks: the current
6
+ # list nesting depth (used for indentation) and the wrap width.
7
+ RenderContext = Data.define(:list_depth, :width) do
8
+ # Builds a new RenderContext with the given *width* and optional starting *list_depth*.
9
+ def self.from(width:, list_depth: 0)
10
+ new(list_depth: list_depth, width: width)
11
+ end
13
12
 
14
- # Returns a derived context with the list depth incremented by *depth_increment*
15
- # and the wrap width overridden to *width* (defaults to the current width).
16
- def nested(depth_increment: 0, width: self.width)
17
- self.class.new(list_depth: list_depth + depth_increment, width: width)
18
- end
13
+ # Returns a derived context with the list depth incremented by *depth_increment*
14
+ # and the wrap width overridden to *width* (defaults to the current width).
15
+ def nested(depth_increment: 0, width: self.width)
16
+ self.class.new(list_depth: list_depth + depth_increment, width: width)
19
17
  end
20
18
  end
21
19
  end
@@ -3,110 +3,108 @@
3
3
  require "kramdown"
4
4
 
5
5
  module Charming
6
- module Presentation
7
- module Markdown
8
- # Renderer is the top-level Markdown-to-ANSI renderer. Parses the *content* with
9
- # Kramdown, then walks the document's block and inline trees to produce styled
10
- # terminal output. Code blocks are highlighted via Rouge when `syntax_highlighting`
11
- # is enabled.
12
- class Renderer
13
- # Wrap width used by `render_rule` when no width is otherwise specified.
14
- DEFAULT_RULE_WIDTH = 40
15
-
16
- # The Markdown source, configured wrap width, theme, and syntax-highlighting flag.
17
- attr_reader :content, :width, :theme, :syntax_highlighting
18
-
19
- # *content* is the Markdown source string. *width* optionally wraps paragraphs to that
20
- # many display columns. *theme* is the Charming theme used to style blocks/inlines.
21
- # *syntax_highlighting* enables Rouge-backed code block highlighting (default true).
22
- def initialize(content:, width: nil, theme: UI::Theme.default, syntax_highlighting: true)
23
- @content = content
24
- @width = width
25
- @theme = theme || UI::Theme.default
26
- @syntax_highlighting = syntax_highlighting
27
- end
6
+ module Markdown
7
+ # Renderer is the top-level Markdown-to-ANSI renderer. Parses the *content* with
8
+ # Kramdown, then walks the document's block and inline trees to produce styled
9
+ # terminal output. Code blocks are highlighted via Rouge when `syntax_highlighting`
10
+ # is enabled.
11
+ class Renderer
12
+ # Wrap width used by `render_rule` when no width is otherwise specified.
13
+ DEFAULT_RULE_WIDTH = 40
14
+
15
+ # The Markdown source, configured wrap width, theme, and syntax-highlighting flag.
16
+ attr_reader :content, :width, :theme, :syntax_highlighting
17
+
18
+ # *content* is the Markdown source string. *width* optionally wraps paragraphs to that
19
+ # many display columns. *theme* is the Charming theme used to style blocks/inlines.
20
+ # *syntax_highlighting* enables Rouge-backed code block highlighting (default true).
21
+ def initialize(content:, width: nil, theme: UI::Theme.default, syntax_highlighting: true)
22
+ @content = content
23
+ @width = width
24
+ @theme = theme || UI::Theme.default
25
+ @syntax_highlighting = syntax_highlighting
26
+ end
28
27
 
29
- # Parses the content and returns the fully-rendered Markdown as a single string.
30
- def render
31
- document = Kramdown::Document.new(content.to_s)
32
- render_blocks(document.root.children)
33
- end
28
+ # Parses the content and returns the fully-rendered Markdown as a single string.
29
+ def render
30
+ document = Kramdown::Document.new(content.to_s)
31
+ render_blocks(document.root.children)
32
+ end
34
33
 
35
- # Renders a list of Kramdown block *elements* into a string, joined by blank lines.
36
- # *list_depth* is forwarded to the render context for list indentation. *width*
37
- # defaults to the renderer's configured width.
38
- def render_blocks(elements, list_depth: 0, width: @width)
39
- context = RenderContext.from(width: width, list_depth: list_depth)
40
- elements.filter_map do |element|
41
- rendered = block_renderer.render(element, context: context)
42
- rendered unless rendered.to_s.empty?
43
- end.join("\n\n")
44
- end
34
+ # Renders a list of Kramdown block *elements* into a string, joined by blank lines.
35
+ # *list_depth* is forwarded to the render context for list indentation. *width*
36
+ # defaults to the renderer's configured width.
37
+ def render_blocks(elements, list_depth: 0, width: @width)
38
+ context = RenderContext.from(width: width, list_depth: list_depth)
39
+ elements.filter_map do |element|
40
+ rendered = block_renderer.render(element, context: context)
41
+ rendered unless rendered.to_s.empty?
42
+ end.join("\n\n")
43
+ end
45
44
 
46
- # Renders a list of Kramdown inline *elements* into a single concatenated string.
47
- # *width* defaults to the renderer's configured width.
48
- def render_inlines(elements, width: @width)
49
- context = RenderContext.from(width: width)
50
- elements.map { |element| inline_renderer.render(element, context: context) }.join
51
- end
45
+ # Renders a list of Kramdown inline *elements* into a single concatenated string.
46
+ # *width* defaults to the renderer's configured width.
47
+ def render_inlines(elements, width: @width)
48
+ context = RenderContext.from(width: width)
49
+ elements.map { |element| inline_renderer.render(element, context: context) }.join
50
+ end
52
51
 
53
- # Word-wraps *value* to *width* display columns (when *width* is given), preserving
54
- # any ANSI styling on each line. Returns *value* unchanged when *width* is nil.
55
- def wrap(value, width:)
56
- return value unless width
52
+ # Word-wraps *value* to *width* display columns (when *width* is given), preserving
53
+ # any ANSI styling on each line. Returns *value* unchanged when *width* is nil.
54
+ def wrap(value, width:)
55
+ return value unless width
57
56
 
58
- value.to_s.lines(chomp: true).map { |line| wrap_line(line, width) }.join("\n")
59
- end
57
+ value.to_s.lines(chomp: true).map { |line| wrap_line(line, width) }.join("\n")
58
+ end
60
59
 
61
- # Returns the theme's style for *name* if the theme defines it, otherwise returns
62
- # *fallback*. Lets views override markdown-specific theme tokens.
63
- def style_for(name, fallback:)
64
- return theme.public_send(name) if theme.respond_to?(name)
60
+ # Returns the theme's style for *name* if the theme defines it, otherwise returns
61
+ # *fallback*. Lets views override markdown-specific theme tokens.
62
+ def style_for(name, fallback:)
63
+ return theme.public_send(name) if theme.respond_to?(name)
65
64
 
66
- fallback
67
- end
65
+ fallback
66
+ end
68
67
 
69
- # Returns the theme's style for *name*, building a one-token default theme when
70
- # the active theme doesn't define it. Used as a final fallback for markdown styling.
71
- def theme_style(name)
72
- return theme.public_send(name) if theme.respond_to?(name)
68
+ # Returns the theme's style for *name*, building a one-token default theme when
69
+ # the active theme doesn't define it. Used as a final fallback for markdown styling.
70
+ def theme_style(name)
71
+ return theme.public_send(name) if theme.respond_to?(name)
73
72
 
74
- UI::Theme::DEFAULT_TOKENS.fetch(name).then { |token| UI::Theme.new(name => token).public_send(name) }
75
- end
73
+ UI::Theme::DEFAULT_TOKENS.fetch(name).then { |token| UI::Theme.new(name => token).public_send(name) }
74
+ end
76
75
 
77
- private
76
+ private
78
77
 
79
- # The BlockRenderer instance, lazily built.
80
- def block_renderer
81
- @block_renderer ||= BlockRenderer.new(renderer: self)
82
- end
78
+ # The BlockRenderer instance, lazily built.
79
+ def block_renderer
80
+ @block_renderer ||= BlockRenderer.new(renderer: self)
81
+ end
83
82
 
84
- # The InlineRenderer instance, lazily built.
85
- def inline_renderer
86
- @inline_renderer ||= InlineRenderer.new(renderer: self)
87
- end
83
+ # The InlineRenderer instance, lazily built.
84
+ def inline_renderer
85
+ @inline_renderer ||= InlineRenderer.new(renderer: self)
86
+ end
88
87
 
89
- # Word-wraps a single *line* to *width* display columns using greedy space-splitting.
90
- def wrap_line(line, width)
91
- return line if UI::Width.measure(line) <= width
88
+ # Word-wraps a single *line* to *width* display columns using greedy space-splitting.
89
+ def wrap_line(line, width)
90
+ return line if UI::Width.measure(line) <= width
92
91
 
93
- lines = []
94
- current = +""
92
+ lines = []
93
+ current = +""
95
94
 
96
- line.split(/\s+/).each do |word|
97
- candidate = current.empty? ? word : "#{current} #{word}"
95
+ line.split(/\s+/).each do |word|
96
+ candidate = current.empty? ? word : "#{current} #{word}"
98
97
 
99
- if !current.empty? && UI::Width.measure(candidate) > width
100
- lines << current.rstrip
101
- current = word
102
- else
103
- current = candidate
104
- end
98
+ if !current.empty? && UI::Width.measure(candidate) > width
99
+ lines << current.rstrip
100
+ current = word
101
+ else
102
+ current = candidate
105
103
  end
106
-
107
- lines << current.rstrip unless current.empty?
108
- lines.join("\n")
109
104
  end
105
+
106
+ lines << current.rstrip unless current.empty?
107
+ lines.join("\n")
110
108
  end
111
109
  end
112
110
  end
@@ -3,76 +3,74 @@
3
3
  require "rouge"
4
4
 
5
5
  module Charming
6
- module Presentation
7
- module Markdown
8
- # SyntaxHighlighter turns a code block string into ANSI-styled terminal text using
9
- # Rouge lexers. The theme provides markdown_code_* tokens for per-token styling;
10
- # when a token is undefined in the theme, the highlighter falls back to a sensible
11
- # base style (muted italic for comments, title for keywords, etc.).
12
- class SyntaxHighlighter
13
- # *theme* is the active Charming theme. Defaults to UI::Theme.default.
14
- def initialize(theme: UI::Theme.default)
15
- @theme = theme || UI::Theme.default
16
- end
6
+ module Markdown
7
+ # SyntaxHighlighter turns a code block string into ANSI-styled terminal text using
8
+ # Rouge lexers. The theme provides markdown_code_* tokens for per-token styling;
9
+ # when a token is undefined in the theme, the highlighter falls back to a sensible
10
+ # base style (muted italic for comments, title for keywords, etc.).
11
+ class SyntaxHighlighter
12
+ # *theme* is the active Charming theme. Defaults to UI::Theme.default.
13
+ def initialize(theme: UI::Theme.default)
14
+ @theme = theme || UI::Theme.default
15
+ end
17
16
 
18
- # Highlights *code* (using Rouge) for the given *language* (auto-detected when nil)
19
- # and returns a styled multi-line string. Each Rouge token is rendered with the
20
- # theme style matching its token type.
21
- def render(code, language: nil)
22
- lexer = lexer_for(language, code)
23
- lexer.lex(code.to_s).map do |token, value|
24
- style_for(token).render(value)
25
- end.join
26
- end
17
+ # Highlights *code* (using Rouge) for the given *language* (auto-detected when nil)
18
+ # and returns a styled multi-line string. Each Rouge token is rendered with the
19
+ # theme style matching its token type.
20
+ def render(code, language: nil)
21
+ lexer = lexer_for(language, code)
22
+ lexer.lex(code.to_s).map do |token, value|
23
+ style_for(token).render(value)
24
+ end.join
25
+ end
27
26
 
28
- private
27
+ private
29
28
 
30
- # The Charming theme used for token styling.
31
- attr_reader :theme
29
+ # The Charming theme used for token styling.
30
+ attr_reader :theme
32
31
 
33
- # Picks a Rouge lexer for *language* and *code*, falling back to plain text.
34
- def lexer_for(language, code)
35
- Rouge::Lexer.find_fancy(language, code) || Rouge::Lexers::PlainText
36
- end
32
+ # Picks a Rouge lexer for *language* and *code*, falling back to plain text.
33
+ def lexer_for(language, code)
34
+ Rouge::Lexer.find_fancy(language, code) || Rouge::Lexers::PlainText
35
+ end
37
36
 
38
- # Returns the Charming style for a given Rouge *token*, mapping token qualifiers
39
- # to theme tokens and falling back to a sensible base style per category.
40
- def style_for(token)
41
- name = token_name(token)
37
+ # Returns the Charming style for a given Rouge *token*, mapping token qualifiers
38
+ # to theme tokens and falling back to a sensible base style per category.
39
+ def style_for(token)
40
+ name = token_name(token)
42
41
 
43
- case name
44
- when /Comment/
45
- theme_style(:markdown_code_comment, fallback: theme_style(:muted).italic)
46
- when /Keyword/
47
- theme_style(:markdown_code_keyword, fallback: theme_style(:title))
48
- when /String/
49
- theme_style(:markdown_code_string, fallback: theme_style(:warn))
50
- when /Number|Literal/
51
- theme_style(:markdown_code_literal, fallback: theme_style(:info))
52
- when /Name\.(Class|Constant|Function|Namespace)/
53
- theme_style(:markdown_code_constant, fallback: theme_style(:info))
54
- when /Error/
55
- theme_style(:markdown_code_error, fallback: theme_style(:warn).bold)
56
- else
57
- theme_style(:markdown_code, fallback: theme_style(:text))
58
- end
42
+ case name
43
+ when /Comment/
44
+ theme_style(:markdown_code_comment, fallback: theme_style(:muted).italic)
45
+ when /Keyword/
46
+ theme_style(:markdown_code_keyword, fallback: theme_style(:title))
47
+ when /String/
48
+ theme_style(:markdown_code_string, fallback: theme_style(:warn))
49
+ when /Number|Literal/
50
+ theme_style(:markdown_code_literal, fallback: theme_style(:info))
51
+ when /Name\.(Class|Constant|Function|Namespace)/
52
+ theme_style(:markdown_code_constant, fallback: theme_style(:info))
53
+ when /Error/
54
+ theme_style(:markdown_code_error, fallback: theme_style(:warn).bold)
55
+ else
56
+ theme_style(:markdown_code, fallback: theme_style(:text))
59
57
  end
58
+ end
60
59
 
61
- # Returns the qualified token name when the token object supports it, otherwise
62
- # the token's default `to_s`.
63
- def token_name(token)
64
- return token.qualname if token.respond_to?(:qualname)
60
+ # Returns the qualified token name when the token object supports it, otherwise
61
+ # the token's default `to_s`.
62
+ def token_name(token)
63
+ return token.qualname if token.respond_to?(:qualname)
65
64
 
66
- token.to_s
67
- end
65
+ token.to_s
66
+ end
68
67
 
69
- # Returns the theme's style for *name*, falling back to *fallback* (or a default
70
- # empty style) when the theme doesn't define it.
71
- def theme_style(name, fallback: nil)
72
- return theme.public_send(name) if theme.respond_to?(name)
68
+ # Returns the theme's style for *name*, falling back to *fallback* (or a default
69
+ # empty style) when the theme doesn't define it.
70
+ def theme_style(name, fallback: nil)
71
+ return theme.public_send(name) if theme.respond_to?(name)
73
72
 
74
- fallback || UI.style
75
- end
73
+ fallback || UI.style
76
74
  end
77
75
  end
78
76
  end
@@ -1,11 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Charming
4
- module Presentation
5
- # Markdown is the namespace for the Markdown rendering pipeline. Parsing is delegated to
6
- # Kramdown; per-block and per-inline element rendering is handled by `BlockRenderer`
7
- # and `InlineRenderer`; code blocks are highlighted by `SyntaxHighlighter` (Rouge-backed).
8
- module Markdown
9
- end
4
+ # Markdown is the namespace for the Markdown rendering pipeline. Parsing is delegated to
5
+ # Kramdown; per-block and per-inline element rendering is handled by `BlockRenderer`
6
+ # and `InlineRenderer`; code blocks are highlighted by `SyntaxHighlighter` (Rouge-backed).
7
+ module Markdown
10
8
  end
11
9
  end
@@ -1,34 +1,32 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Charming
4
- module Presentation
5
- # TemplateView wraps a resolved ERB template and exposes it as a renderable View. The
6
- # template is rendered with the view's helpers (`text`, `box`, `row`, `column`, `style`,
7
- # `theme`, etc.) and the view's assigns available as reader methods inside the template.
8
- class TemplateView < View
9
- def initialize(template:, namespace: nil, **assigns)
10
- super(**assigns)
11
- @template = template
12
- @namespace = namespace
13
- end
4
+ # TemplateView wraps a resolved ERB template and exposes it as a renderable View. The
5
+ # template is rendered with the view's helpers (`text`, `box`, `row`, `column`, `style`,
6
+ # `theme`, etc.) and the view's assigns available as reader methods inside the template.
7
+ class TemplateView < View
8
+ def initialize(template:, namespace: nil, **assigns)
9
+ super(**assigns)
10
+ @template = template
11
+ @namespace = namespace
12
+ end
14
13
 
15
- # Renders the wrapped template to a string, evaluated in the view's binding context.
16
- def render
17
- template.render(self).to_s
18
- end
14
+ # Renders the wrapped template to a string, evaluated in the view's binding context.
15
+ def render
16
+ template.render(self).to_s
17
+ end
19
18
 
20
- # Returns the binding used by ERB handlers to evaluate the template body. When *namespace*
21
- # is set, the binding is created by a proc generated in the namespace's context so the
22
- # template can resolve constants relative to the application.
23
- def template_binding
24
- return binding unless namespace
19
+ # Returns the binding used by ERB handlers to evaluate the template body. When *namespace*
20
+ # is set, the binding is created by a proc generated in the namespace's context so the
21
+ # template can resolve constants relative to the application.
22
+ def template_binding
23
+ return binding unless namespace
25
24
 
26
- namespace.module_eval("->(view) { view.instance_eval { binding } }", __FILE__, __LINE__).call(self)
27
- end
25
+ namespace.module_eval("->(view) { view.instance_eval { binding } }", __FILE__, __LINE__).call(self)
26
+ end
28
27
 
29
- private
28
+ private
30
29
 
31
- attr_reader :template, :namespace
32
- end
30
+ attr_reader :template, :namespace
33
31
  end
34
32
  end
@@ -3,12 +3,10 @@
3
3
  require "erb"
4
4
 
5
5
  module Charming
6
- module Presentation
7
- module Templates
8
- class ErbHandler
9
- def self.render(path, view)
10
- ERB.new(File.read(path), trim_mode: "-").result(view.template_binding)
11
- end
6
+ module Templates
7
+ class ErbHandler
8
+ def self.render(path, view)
9
+ ERB.new(File.read(path), trim_mode: "-").result(view.template_binding)
12
10
  end
13
11
  end
14
12
  end