marvi 0.4.0 → 0.4.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b0110473458c01229add5274f0ab0df77dad55587286ee01c426612fa0505707
4
- data.tar.gz: 8e59b8386b4fb283613a2fc81d2841473ccd78eaa216a4608e10c17ae62c61b0
3
+ metadata.gz: 519a600dd8ba2e4c6934cf57f37914337ce252ced2a51d6b05dff2ab2c1dda4b
4
+ data.tar.gz: '02669ac614cde421459555a5068429e1371036dd90eb549f5a90d6f3e3aea90c'
5
5
  SHA512:
6
- metadata.gz: 3abaf2190555600e5e04cd0a04d7176d6ef5b8384afc902cff76389ec782a448bd99609cf2474d7f62827bc24750514b7517cf780b61739c327a665bb3cc9821
7
- data.tar.gz: 2caddfb8de48b8fc5f6c894f839d06239b57845993a67f576f8cde2cb6591509d3167dbe35d11636e1c03f5cb140e2c16cfeec945bf8204eeb4095f3a31c8bcb
6
+ metadata.gz: 37a67589e93f21f02d2c7cec09130e2a63ce83e88ebe21c61cf643b4810506ff4ece12ca39d8c36a40cbccaca35ecf8984e1c8276f953b0e17bf2b9caf4f98de
7
+ data.tar.gz: 12fa9234e6fb3dd1b13b72b5008a239acea242b049ae4086d6e2a8565435b4727fd5850c5766d79f05bbc48332719f7a2b97609725c8834ca1f6083d4a7acf02
data/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.4.1] - 2026-05-26
4
+
5
+ - 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)
6
+
3
7
  ## [0.4.0] - 2026-05-18
4
8
 
5
9
  - Bind `Ctrl-D` / `Ctrl-U` for vim-style half-page scrolling in the curses pager.
@@ -29,7 +29,8 @@ module Marvi
29
29
  render_header(el)
30
30
  when :p
31
31
  src = el.options[:location]
32
- [RichLine.new(render_inline_children(el), source_line: src), RichLine.blank]
32
+ wrapped = wrap_spans(render_inline_children(el), @max_width)
33
+ wrapped.each_with_index.map { |spans, i| RichLine.new(spans, source_line: (i.zero? ? src : nil)) } + [RichLine.blank]
33
34
  when :ul
34
35
  el.children.flat_map { |child| render_block(child, indent: indent, list_type: :ul) } + [RichLine.blank]
35
36
  when :ol
@@ -62,12 +63,15 @@ module Marvi
62
63
  content = render_inline_children(el).map do |s|
63
64
  Span.new(text: s.text, bold: true, italic: s.italic, color: s.color || color, bg_color: s.bg_color)
64
65
  end
65
- [RichLine.new([prefix] + content, source_line: src), RichLine.blank]
66
+ wrap_with_prefix([prefix], content, @max_width, source_line: src) + [RichLine.blank]
66
67
  end
67
68
 
68
69
  def render_li(el, indent:, list_type:, list_index:)
69
70
  bullet = (list_type == :ol) ? "#{list_index}." : "•"
70
71
  prefix = Span.new(text: "#{" " * indent}#{bullet} ", color: :cyan)
72
+ prefix_width = spans_display_width([prefix])
73
+ hanging = Span.new(text: " " * prefix_width)
74
+ inner_width = [@max_width - prefix_width, MIN_COL_WIDTH].max
71
75
  src = el.options[:location]
72
76
  lines = []
73
77
 
@@ -78,16 +82,25 @@ module Marvi
78
82
  nested.pop while nested.last&.plain_text&.empty?
79
83
  lines += nested
80
84
  when :p
85
+ content_spans = render_inline_children(child)
81
86
  if lines.empty?
82
- lines << RichLine.new([prefix] + render_inline_children(child), source_line: src)
87
+ lines += wrap_with_prefix([prefix], content_spans, @max_width, source_line: src)
83
88
  else
84
- lines += render_block(child)
89
+ child_src = child.options[:location]
90
+ wrapped = wrap_spans(content_spans, inner_width)
91
+ wrapped.each_with_index do |spans, i|
92
+ lines << RichLine.new([hanging] + spans, source_line: (i.zero? ? child_src : nil))
93
+ end
94
+ lines << RichLine.blank
85
95
  end
86
96
  else
87
- lines << if lines.empty?
88
- RichLine.new([prefix] + render_inline(child), source_line: src)
97
+ content_spans = render_inline(child)
98
+ if lines.empty?
99
+ lines += wrap_with_prefix([prefix], content_spans, @max_width, source_line: src)
89
100
  else
90
- RichLine.new(render_inline(child))
101
+ wrap_spans(content_spans, inner_width).each do |spans|
102
+ lines << RichLine.new([hanging] + spans)
103
+ end
91
104
  end
92
105
  end
93
106
  end
@@ -110,9 +123,14 @@ module Marvi
110
123
  end
111
124
 
112
125
  def render_blockquote(el)
113
- inner = el.children.flat_map { |child| render_block(child) }
114
126
  prefix = Span.new(text: "│ ", color: :cyan)
115
- # preserve source_line from inner lines
127
+ prefix_width = spans_display_width([prefix])
128
+ # Reduce @max_width while rendering inner content so the │ prefix fits within @max_width
129
+ # without forcing a second wrap pass on already-wrapped lines.
130
+ saved_width = @max_width
131
+ @max_width = [saved_width - prefix_width, MIN_COL_WIDTH].max
132
+ inner = el.children.flat_map { |child| render_block(child) }
133
+ @max_width = saved_width
116
134
  inner.map { |line| RichLine.new([prefix] + line.spans, source_line: line.source_line) } + [RichLine.blank]
117
135
  end
118
136
 
@@ -177,6 +195,17 @@ module Marvi
177
195
  shrunk
178
196
  end
179
197
 
198
+ def wrap_with_prefix(prefix_spans, content_spans, max_width, source_line: nil)
199
+ prefix_width = spans_display_width(prefix_spans)
200
+ inner_width = [max_width - prefix_width, MIN_COL_WIDTH].max
201
+ wrapped = wrap_spans(content_spans, inner_width)
202
+ indent = Span.new(text: " " * prefix_width)
203
+ wrapped.each_with_index.map do |spans, i|
204
+ line_prefix = i.zero? ? prefix_spans : [indent]
205
+ RichLine.new(line_prefix + spans, source_line: (i.zero? ? source_line : nil))
206
+ end
207
+ end
208
+
180
209
  def wrap_spans(spans, width)
181
210
  lines = [[]]
182
211
  current_width = 0
data/lib/marvi/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Marvi
4
- VERSION = "0.4.0"
4
+ VERSION = "0.4.1"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: marvi
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mitsutaka Mimura