marvi 0.4.1 → 0.4.2
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/CHANGELOG.md +7 -0
- data/lib/marvi/ast_walker.rb +52 -26
- data/lib/marvi/renderer/curses.rb +16 -2
- data/lib/marvi/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d5ff0488e214dd427a028dabe9d240bee43e48ac27cef895e7f8584b41695435
|
|
4
|
+
data.tar.gz: 71dcd3de576d8926b90cae6ec4b79732be3627b85922351585b624b064eafb94
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1f90d2999b6336d1fa26f8ef441c8e51e551f4f7d229633053acc9ab8418fe115bcd6ea3f8fa3b67ce678781b29198acc33fd1ed69f591611a47bc97b456901c
|
|
7
|
+
data.tar.gz: 82bcdfbe5166bcd2f48d2367da468df0290c89e831d16fa06dced445dba98a2ba0846c659a87e9f69a1dd2e68c900f9cccdaaa57790bb0f35ddcb2c4b8d8dc0e
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [0.4.2] - 2026-05-31
|
|
4
|
+
|
|
5
|
+
- Add left/right padding in the curses pager so content no longer sits flush against the terminal edges. Padding scales with terminal width.
|
|
6
|
+
- Render every line of a multi-line blockquote with its `│ ` prefix.
|
|
7
|
+
- Stop emitting an empty `│ ` line at the end of blockquotes.
|
|
8
|
+
- Collapse consecutive blank lines so block-level elements are separated by a single blank line.
|
|
9
|
+
|
|
3
10
|
## [0.4.1] - 2026-05-26
|
|
4
11
|
|
|
5
12
|
- Wrap long text in bulleted/ordered lists, paragraphs, headers, and blockquotes so it no longer overflows the terminal width. List items and headers use a hanging indent for continuation lines. (#1)
|
data/lib/marvi/ast_walker.rb
CHANGED
|
@@ -16,7 +16,7 @@ module Marvi
|
|
|
16
16
|
doc = Kramdown::Document.new(markdown, input: "GFM")
|
|
17
17
|
lines = render_block(doc.root)
|
|
18
18
|
lines.pop while lines.last&.plain_text&.empty?
|
|
19
|
-
lines
|
|
19
|
+
collapse_consecutive_blanks(lines)
|
|
20
20
|
end
|
|
21
21
|
|
|
22
22
|
private
|
|
@@ -131,9 +131,26 @@ module Marvi
|
|
|
131
131
|
@max_width = [saved_width - prefix_width, MIN_COL_WIDTH].max
|
|
132
132
|
inner = el.children.flat_map { |child| render_block(child) }
|
|
133
133
|
@max_width = saved_width
|
|
134
|
+
# Trim trailing blanks and collapse runs of blanks so the │ prefix doesn't produce
|
|
135
|
+
# dangling/duplicated "│ " lines (kramdown emits both :p trailing blanks and explicit
|
|
136
|
+
# :blank elements between siblings).
|
|
137
|
+
inner.pop while inner.last&.plain_text&.empty?
|
|
138
|
+
inner = collapse_consecutive_blanks(inner)
|
|
134
139
|
inner.map { |line| RichLine.new([prefix] + line.spans, source_line: line.source_line) } + [RichLine.blank]
|
|
135
140
|
end
|
|
136
141
|
|
|
142
|
+
def collapse_consecutive_blanks(lines)
|
|
143
|
+
out = []
|
|
144
|
+
prev_blank = false
|
|
145
|
+
lines.each do |line|
|
|
146
|
+
is_blank = line.plain_text.empty?
|
|
147
|
+
next if is_blank && prev_blank
|
|
148
|
+
out << line
|
|
149
|
+
prev_blank = is_blank
|
|
150
|
+
end
|
|
151
|
+
out
|
|
152
|
+
end
|
|
153
|
+
|
|
137
154
|
def render_table(el)
|
|
138
155
|
src = el.options[:location]
|
|
139
156
|
rows = el.children.flat_map(&:children)
|
|
@@ -210,34 +227,43 @@ module Marvi
|
|
|
210
227
|
lines = [[]]
|
|
211
228
|
current_width = 0
|
|
212
229
|
spans.each do |span|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
230
|
+
# Split on \n so embedded hard line breaks become separate RichLines downstream,
|
|
231
|
+
# otherwise Curses.addstr resets the cursor to column 0 and bypasses padding/prefix.
|
|
232
|
+
parts = span.text.split("\n", -1)
|
|
233
|
+
parts.each_with_index do |part, idx|
|
|
234
|
+
if idx > 0 && !lines.last.empty?
|
|
217
235
|
lines << []
|
|
218
236
|
current_width = 0
|
|
219
|
-
remaining = width
|
|
220
|
-
end
|
|
221
|
-
taken = 0
|
|
222
|
-
chunk_width = 0
|
|
223
|
-
text.each_char do |c|
|
|
224
|
-
cw = Unicode::DisplayWidth.of(c)
|
|
225
|
-
break if chunk_width + cw > remaining
|
|
226
|
-
chunk_width += cw
|
|
227
|
-
taken += c.bytesize
|
|
228
|
-
end
|
|
229
|
-
if taken.zero?
|
|
230
|
-
first_char = text.each_char.first
|
|
231
|
-
taken = first_char.bytesize
|
|
232
|
-
chunk_width = Unicode::DisplayWidth.of(first_char)
|
|
233
237
|
end
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
238
|
+
text = part.dup
|
|
239
|
+
until text.empty?
|
|
240
|
+
remaining = width - current_width
|
|
241
|
+
if remaining <= 0
|
|
242
|
+
lines << []
|
|
243
|
+
current_width = 0
|
|
244
|
+
remaining = width
|
|
245
|
+
end
|
|
246
|
+
taken = 0
|
|
247
|
+
chunk_width = 0
|
|
248
|
+
text.each_char do |c|
|
|
249
|
+
cw = Unicode::DisplayWidth.of(c)
|
|
250
|
+
break if chunk_width + cw > remaining
|
|
251
|
+
chunk_width += cw
|
|
252
|
+
taken += c.bytesize
|
|
253
|
+
end
|
|
254
|
+
if taken.zero?
|
|
255
|
+
first_char = text.each_char.first
|
|
256
|
+
taken = first_char.bytesize
|
|
257
|
+
chunk_width = Unicode::DisplayWidth.of(first_char)
|
|
258
|
+
end
|
|
259
|
+
chunk = text.byteslice(0, taken)
|
|
260
|
+
text = text.byteslice(taken..) || ""
|
|
261
|
+
lines.last << Span.new(text: chunk, bold: span.bold, italic: span.italic, color: span.color, bg_color: span.bg_color)
|
|
262
|
+
current_width += chunk_width
|
|
263
|
+
unless text.empty?
|
|
264
|
+
lines << []
|
|
265
|
+
current_width = 0
|
|
266
|
+
end
|
|
241
267
|
end
|
|
242
268
|
end
|
|
243
269
|
end
|
|
@@ -23,6 +23,9 @@ module Marvi
|
|
|
23
23
|
CTRL_D = 4
|
|
24
24
|
CTRL_U = 21
|
|
25
25
|
|
|
26
|
+
MIN_HORIZONTAL_PADDING = 2
|
|
27
|
+
HORIZONTAL_PADDING_DIVISOR = 12
|
|
28
|
+
|
|
26
29
|
def render(markdown, file: nil)
|
|
27
30
|
@file = file
|
|
28
31
|
@markdown = markdown
|
|
@@ -127,7 +130,17 @@ module Marvi
|
|
|
127
130
|
end
|
|
128
131
|
|
|
129
132
|
def rewalk
|
|
130
|
-
@lines = ASTWalker.new.walk(@markdown, max_width:
|
|
133
|
+
@lines = ASTWalker.new.walk(@markdown, max_width: content_width)
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def horizontal_padding
|
|
137
|
+
cols = ::Curses.cols
|
|
138
|
+
return 0 if cols <= MIN_HORIZONTAL_PADDING * 2
|
|
139
|
+
[MIN_HORIZONTAL_PADDING, cols / HORIZONTAL_PADDING_DIVISOR].max
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def content_width
|
|
143
|
+
[::Curses.cols - horizontal_padding * 2, 1].max
|
|
131
144
|
end
|
|
132
145
|
|
|
133
146
|
def reload_from_key
|
|
@@ -214,8 +227,9 @@ module Marvi
|
|
|
214
227
|
|
|
215
228
|
def draw
|
|
216
229
|
::Curses.clear
|
|
230
|
+
padding = horizontal_padding
|
|
217
231
|
visible_lines.each_with_index do |line, row|
|
|
218
|
-
::Curses.setpos(row,
|
|
232
|
+
::Curses.setpos(row, padding)
|
|
219
233
|
render_line(line)
|
|
220
234
|
end
|
|
221
235
|
draw_status_bar
|
data/lib/marvi/version.rb
CHANGED