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.
- checksums.yaml +4 -4
- data/lib/charming/application.rb +3 -3
- data/lib/charming/controller/class_methods.rb +2 -2
- data/lib/charming/controller/command_palette.rb +2 -2
- data/lib/charming/controller/rendering.rb +2 -2
- data/lib/charming/controller/session_state.rb +1 -1
- data/lib/charming/generators/component_generator.rb +1 -1
- data/lib/charming/generators/templates/app/application.template +1 -1
- data/lib/charming/generators/templates/app/layout.template +3 -6
- data/lib/charming/generators/templates/app/view.template +1 -1
- data/lib/charming/generators/templates/component/component.rb.template +1 -1
- data/lib/charming/generators/templates/screen/view.rb.template +1 -1
- data/lib/charming/generators/templates/view/view.rb.template +1 -1
- data/lib/charming/internal/renderer/differential.rb +13 -5
- data/lib/charming/internal/terminal/tty_backend.rb +22 -2
- data/lib/charming/presentation/component.rb +3 -5
- data/lib/charming/presentation/components/activity_indicator.rb +173 -134
- data/lib/charming/presentation/components/command_palette.rb +94 -96
- data/lib/charming/presentation/components/command_palette_modal.rb +33 -0
- data/lib/charming/presentation/components/empty_state.rb +47 -49
- data/lib/charming/presentation/components/form/builder.rb +52 -54
- data/lib/charming/presentation/components/form/confirm.rb +49 -51
- data/lib/charming/presentation/components/form/field.rb +94 -96
- data/lib/charming/presentation/components/form/input.rb +53 -55
- data/lib/charming/presentation/components/form/note.rb +27 -29
- data/lib/charming/presentation/components/form/select.rb +84 -86
- data/lib/charming/presentation/components/form/textarea.rb +67 -69
- data/lib/charming/presentation/components/form.rb +120 -122
- data/lib/charming/presentation/components/keyboard_handler.rb +41 -43
- data/lib/charming/presentation/components/list.rb +123 -125
- data/lib/charming/presentation/components/markdown.rb +21 -23
- data/lib/charming/presentation/components/modal.rb +46 -48
- data/lib/charming/presentation/components/progressbar.rb +51 -53
- data/lib/charming/presentation/components/spinner.rb +40 -42
- data/lib/charming/presentation/components/table.rb +109 -111
- data/lib/charming/presentation/components/text_area.rb +219 -221
- data/lib/charming/presentation/components/text_input.rb +120 -122
- data/lib/charming/presentation/components/viewport.rb +218 -220
- data/lib/charming/presentation/layout/builder.rb +64 -66
- data/lib/charming/presentation/layout/overlay.rb +48 -50
- data/lib/charming/presentation/layout/pane.rb +122 -118
- data/lib/charming/presentation/layout/rect.rb +14 -16
- data/lib/charming/presentation/layout/screen_layout.rb +40 -42
- data/lib/charming/presentation/layout/split.rb +101 -103
- data/lib/charming/presentation/layout.rb +28 -30
- data/lib/charming/presentation/markdown/block_renderers.rb +94 -96
- data/lib/charming/presentation/markdown/inline_renderers.rb +52 -54
- data/lib/charming/presentation/markdown/render_context.rb +12 -14
- data/lib/charming/presentation/markdown/renderer.rb +84 -86
- data/lib/charming/presentation/markdown/syntax_highlighter.rb +57 -59
- data/lib/charming/presentation/markdown.rb +4 -6
- data/lib/charming/presentation/template_view.rb +22 -24
- data/lib/charming/presentation/templates/erb_handler.rb +4 -6
- data/lib/charming/presentation/templates.rb +47 -49
- data/lib/charming/presentation/ui/ansi_codes.rb +66 -68
- data/lib/charming/presentation/ui/ansi_slicer.rb +67 -69
- data/lib/charming/presentation/ui/border.rb +24 -26
- data/lib/charming/presentation/ui/border_painter.rb +37 -39
- data/lib/charming/presentation/ui/canvas.rb +59 -61
- data/lib/charming/presentation/ui/style.rb +173 -175
- data/lib/charming/presentation/ui/theme.rb +133 -135
- data/lib/charming/presentation/ui/width.rb +12 -14
- data/lib/charming/presentation/ui.rb +69 -71
- data/lib/charming/presentation/view.rb +103 -105
- data/lib/charming/runtime.rb +23 -10
- data/lib/charming/version.rb +1 -1
- data/lib/charming.rb +3 -2
- metadata +2 -1
|
@@ -1,128 +1,126 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Charming
|
|
4
|
-
module
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
@cursor = cursor.clamp(0, value.length)
|
|
125
|
-
end
|
|
4
|
+
module Components
|
|
5
|
+
# TextInput is a single-line text editor component. Supports printable character insertion,
|
|
6
|
+
# cursor movement (left/right/home/end), and deletion (backspace/delete). The component
|
|
7
|
+
# exposes its `value` and `cursor` positions as reader methods; when an explicit `width:`
|
|
8
|
+
# is given, the rendered output is padded to that width via a UI::Style.
|
|
9
|
+
class TextInput < Component
|
|
10
|
+
include KeyboardHandler
|
|
11
|
+
|
|
12
|
+
# Maps editing keys (left/right/home/end/backspace/delete) to the instance
|
|
13
|
+
# methods they dispatch via KeyboardHandler. Each symbol key (e.g., :left)
|
|
14
|
+
# maps to a method (e.g., :move_left) that adjusts cursor position or text content.
|
|
15
|
+
KEY_ACTIONS = {
|
|
16
|
+
left: :move_left,
|
|
17
|
+
right: :move_right,
|
|
18
|
+
home: :move_home,
|
|
19
|
+
end: :move_end,
|
|
20
|
+
backspace: :delete_before_cursor,
|
|
21
|
+
delete: :delete_at_cursor
|
|
22
|
+
}.freeze
|
|
23
|
+
|
|
24
|
+
# The current input string and the byte offset of the cursor within it.
|
|
25
|
+
attr_reader :value, :cursor
|
|
26
|
+
|
|
27
|
+
# *value* is the initial text. *placeholder* is shown when the value is empty.
|
|
28
|
+
# *width* optionally constrains the rendered output width; *cursor* defaults to the end.
|
|
29
|
+
def initialize(value: "", placeholder: "", width: nil, cursor: nil)
|
|
30
|
+
super()
|
|
31
|
+
@value = value.dup
|
|
32
|
+
@placeholder = placeholder
|
|
33
|
+
@width = width
|
|
34
|
+
@cursor = cursor || @value.length
|
|
35
|
+
clamp_position
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Handles key events. Inserts printable characters, otherwise dispatches via KEY_ACTIONS.
|
|
39
|
+
# Returns :handled when the event was consumed, nil otherwise.
|
|
40
|
+
def handle_key(event)
|
|
41
|
+
return :handled if character_event?(event) && insert(event.char)
|
|
42
|
+
|
|
43
|
+
super
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Renders the value with a cursor marker. When *width* was given at construction, the
|
|
47
|
+
# output is padded to that width via the configured style.
|
|
48
|
+
def render
|
|
49
|
+
rendered = render_value
|
|
50
|
+
@width ? style.width(@width).render(rendered) : rendered
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
private
|
|
54
|
+
|
|
55
|
+
attr_reader :placeholder
|
|
56
|
+
|
|
57
|
+
# True when *event* carries a single printable character that should be inserted.
|
|
58
|
+
def character_event?(event)
|
|
59
|
+
event.respond_to?(:char) && event.char && event.char.length == 1 && printable?(event.char)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# True when *char* is not a control character (and therefore safe to insert).
|
|
63
|
+
def printable?(char)
|
|
64
|
+
!char.match?(/[[:cntrl:]]/)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Inserts *char* at the cursor and advances the cursor by its byte length.
|
|
68
|
+
def insert(char)
|
|
69
|
+
@value = value[0...cursor] + char + value[cursor..]
|
|
70
|
+
@cursor += char.length
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Moves the cursor one position left, when possible.
|
|
74
|
+
def move_left
|
|
75
|
+
@cursor -= 1 if cursor.positive?
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Moves the cursor one position right, when possible.
|
|
79
|
+
def move_right
|
|
80
|
+
@cursor += 1 if cursor < value.length
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Moves the cursor to the start of the value.
|
|
84
|
+
def move_home
|
|
85
|
+
@cursor = 0
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# Moves the cursor to the end of the value.
|
|
89
|
+
def move_end
|
|
90
|
+
@cursor = value.length
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# Deletes the character before the cursor (backspace behavior).
|
|
94
|
+
def delete_before_cursor
|
|
95
|
+
return if cursor.zero?
|
|
96
|
+
|
|
97
|
+
@value = value[0...(cursor - 1)] + value[cursor..]
|
|
98
|
+
@cursor -= 1
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Deletes the character at the cursor (delete-key behavior).
|
|
102
|
+
def delete_at_cursor
|
|
103
|
+
return if cursor >= value.length
|
|
104
|
+
|
|
105
|
+
@value = value[0...cursor] + value[(cursor + 1)..]
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# Renders the value with a "|" cursor marker at the current position. When the value is
|
|
109
|
+
# empty, the placeholder is rendered instead, preceded by the cursor marker.
|
|
110
|
+
def render_value
|
|
111
|
+
return cursor_marker + placeholder if value.empty?
|
|
112
|
+
|
|
113
|
+
value[0...cursor] + cursor_marker + value[cursor..]
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# The literal character used to mark the cursor position in `render`.
|
|
117
|
+
def cursor_marker
|
|
118
|
+
"|"
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# Clamps the cursor to the valid range `[0, value.length]`.
|
|
122
|
+
def clamp_position
|
|
123
|
+
@cursor = cursor.clamp(0, value.length)
|
|
126
124
|
end
|
|
127
125
|
end
|
|
128
126
|
end
|