hyperlist 1.4.2 → 1.4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1e6315c6d2ea2f89a99a74e0d1b9e06b0f0aee972f53f8b9b098e0bbe1d38545
4
- data.tar.gz: 21e2b64e3c54fc9969114c6382b3bbe50526022aab77edc13ea1d8b9ebdb562f
3
+ metadata.gz: 735c8dad200fdf5f2ac019def34b0b9f11eed7df0c49f962385bc723b0263cf4
4
+ data.tar.gz: db4f459832acaa5d04509d070797aae448062cd507810666a743c1194e61fd32
5
5
  SHA512:
6
- metadata.gz: cc3ffc31138c89a0bf68ea1636297c7f261884f4e6b734e0dd96b176b85fd53d361fed3f7889d850ace5d7dde70d040e5d6eecb4b339d596b6a7017085c6ee02
7
- data.tar.gz: d5a210e0c40b9f0eccae343c698ef694d418e2feda327b5e341bad60df3d1e24f4e0917b5b3e4920a5db047f98d271596f26a36130f8c273bbc483da9462639e
6
+ metadata.gz: fb8aa40308aad944488acfcaf2c1319fa65dfed27ce2135d74384b240deb8b2f3fd327def196206f501f134995dd17affae874e6800bb42a440789b9610bc588
7
+ data.tar.gz: 88e64082e113bdb8f38ae69f6579fdb4711a62c6699bd7f58ded56a08d32e52367e00062e41b1ecf0d6c80742d2467f833ef05d42fe476f816e1aaa83d8a697b
data/hyperlist CHANGED
@@ -7,7 +7,7 @@
7
7
  # Check for help/version BEFORE loading any libraries
8
8
  if ARGV[0] == '-h' || ARGV[0] == '--help'
9
9
  puts <<~HELP
10
- HyperList v1.4.2 - Terminal User Interface for HyperList files
10
+ HyperList v1.4.3 - Terminal User Interface for HyperList files
11
11
 
12
12
  USAGE
13
13
  hyperlist [OPTIONS] [FILE]
@@ -72,7 +72,7 @@ class HyperListApp
72
72
  include Rcurses::Input
73
73
  include Rcurses::Cursor
74
74
 
75
- VERSION = "1.4.2"
75
+ VERSION = "1.4.3"
76
76
 
77
77
  def initialize(filename = nil)
78
78
  @filename = filename ? File.expand_path(filename) : nil
@@ -253,6 +253,28 @@ class HyperListApp
253
253
  next
254
254
  end
255
255
 
256
+ # Check if this is a continuation line for a multi-line item
257
+ # According to HyperList spec: continuation lines start with space after the indent
258
+ is_continuation = false
259
+ if @items.length > 0
260
+ last_item = @items.last
261
+ # Check if previous item started with + (multi-line indicator)
262
+ if last_item["text"].strip.start_with?("+")
263
+ # For continuation lines, we expect: same indent level + one space prefix
264
+ # Calculate the expected spaces for a continuation line
265
+ expected_spaces = last_item["level"] * @indent_size + 1
266
+ actual_spaces = line[/^ */].length
267
+
268
+ # Check if this matches the continuation pattern
269
+ if actual_spaces == expected_spaces
270
+ # This is a continuation line - append it to the previous item
271
+ continuation_text = line[expected_spaces..-1] || ""
272
+ last_item["text"] += "\n " + continuation_text
273
+ next # Skip adding as a new item
274
+ end
275
+ end
276
+ end
277
+
256
278
  # Detect level based on leading whitespace
257
279
  if line.start_with?("\t")
258
280
  # Tab-based indentation
@@ -589,7 +611,18 @@ class HyperListApp
589
611
 
590
612
  # Prepare content
591
613
  content = @items.map do |item|
592
- (' ' * @indent_size) * item["level"] + item["text"]
614
+ # Handle multi-line items (those with embedded newlines)
615
+ if item["text"].include?("\n")
616
+ lines = item["text"].split("\n")
617
+ first_line = (' ' * @indent_size) * item["level"] + lines[0]
618
+ # Continuation lines get the same indent + space prefix
619
+ continuation_lines = lines[1..-1].map do |line|
620
+ (' ' * @indent_size) * item["level"] + line
621
+ end
622
+ [first_line, *continuation_lines].join("\n")
623
+ else
624
+ (' ' * @indent_size) * item["level"] + item["text"]
625
+ end
593
626
  end.join("\n")
594
627
 
595
628
  # Append config line if present
@@ -935,7 +968,16 @@ class HyperListApp
935
968
  if first_line
936
969
  # First line gets the multi-line indicator if needed
937
970
  if remaining.length <= effective_width
938
- wrapped << (has_plus || wrapped.any? ? "+ #{remaining}" : remaining)
971
+ # If line already had +, it was removed earlier, so we add it back
972
+ # If line didn't have + but needs wrapping (wrapped.any?), add +
973
+ # Otherwise, leave as is
974
+ if has_plus
975
+ wrapped << "+ #{remaining}"
976
+ elsif wrapped.any?
977
+ wrapped << "+ #{remaining}"
978
+ else
979
+ wrapped << remaining
980
+ end
939
981
  break
940
982
  else
941
983
  # Find a good break point (prefer spaces)
@@ -971,14 +1013,28 @@ class HyperListApp
971
1013
  in_literal_block = false
972
1014
  literal_start_level = -1
973
1015
 
1016
+ # Track which line number each item starts at (for scroll calculation)
1017
+ item_line_starts = {}
1018
+
974
1019
  visible_items.each_with_index do |item, idx|
975
1020
  next unless item
976
1021
 
977
- # Handle line wrapping if enabled
978
- if @wrap
979
- text_lines = wrap_line(item["text"], @cols, item["level"])
980
- else
981
- text_lines = [item["text"]]
1022
+ # Record where this item starts in the display
1023
+ item_line_starts[idx] = lines.length
1024
+
1025
+ # Handle line wrapping and multi-line items
1026
+ # First, split by embedded newlines (from multi-line items with + indicator)
1027
+ embedded_lines = item["text"].split("\n")
1028
+ text_lines = []
1029
+
1030
+ embedded_lines.each do |embedded_line|
1031
+ if @wrap
1032
+ # Wrap each embedded line separately
1033
+ wrapped = wrap_line(embedded_line, @cols, item["level"])
1034
+ text_lines.concat(wrapped)
1035
+ else
1036
+ text_lines << embedded_line
1037
+ end
982
1038
  end
983
1039
 
984
1040
  text_lines.each_with_index do |text_line, line_idx|
@@ -1087,23 +1143,26 @@ class HyperListApp
1087
1143
  end
1088
1144
  end
1089
1145
 
1090
- # Calculate scroll position exactly like RTFM does, but account for wrapping
1091
- # Treat the content as having one extra line (the blank line at bottom)
1146
+ # Calculate scroll position based on actual line positions, not item indices
1147
+ # The current item starts at line item_line_starts[@current]
1092
1148
  scrolloff = 3
1093
- total = visible_items.length + 1 # +1 for the blank line
1094
- page = @main.h
1149
+ total_lines = lines.length # Total number of actual display lines
1150
+ page = @main.h # Height of the display area
1151
+
1152
+ # Get the actual line where the current item starts
1153
+ current_line = item_line_starts[@current] || 0
1095
1154
 
1096
- if total <= page
1155
+ if total_lines <= page
1097
1156
  # If everything fits, always start from the very top
1098
1157
  @main.ix = 0
1099
- elsif @current - @main.ix < scrolloff
1158
+ elsif current_line - @main.ix < scrolloff
1100
1159
  # If we're too close to the top of the pane, scroll up
1101
- @main.ix = [@current - scrolloff, 0].max
1102
- elsif (@main.ix + page - 1 - @current) < scrolloff
1160
+ @main.ix = [current_line - scrolloff, 0].max
1161
+ elsif (@main.ix + page - 1 - current_line) < scrolloff
1103
1162
  # If we're too close to the bottom of the pane, scroll down
1104
- # Account for wrapped lines dynamically
1105
- max_off = [total - page + extra_wrapped_lines, 0].max
1106
- @main.ix = [@current + scrolloff - page + 1, max_off].min
1163
+ # Make sure we don't scroll past the last line
1164
+ max_scroll = [total_lines - page, 0].max
1165
+ @main.ix = [current_line + scrolloff - page + 1, max_scroll].min
1107
1166
  end
1108
1167
 
1109
1168
  @main.refresh
@@ -4874,46 +4933,77 @@ class HyperListApp
4874
4933
 
4875
4934
  # Build ALL lines for the pane (like we do for main pane)
4876
4935
  lines = []
4936
+
4937
+ # Track which line number each item starts at (for scroll calculation)
4938
+ item_line_starts = {}
4939
+
4877
4940
  visible_items.each_with_index do |item, idx|
4878
4941
  next unless item
4879
4942
 
4943
+ # Record where this item starts in the display
4944
+ item_line_starts[idx] = lines.length
4945
+
4880
4946
  # Find the item's position in the original split_items array
4881
4947
  real_idx = @split_items.index(item)
4882
4948
 
4883
- # Add line number if enabled
4884
- line = ""
4885
- if @show_numbers
4886
- actual_line_number = real_idx ? real_idx + 1 : 0 # +1 for 1-based line numbers
4887
- line = "#{actual_line_number.to_s.rjust(4)} "
4888
- end
4889
-
4890
- line += " " * item["level"]
4949
+ # Handle multi-line items (split by embedded newlines)
4950
+ embedded_lines = item["text"].split("\n")
4951
+ text_lines = []
4891
4952
 
4892
- # Add fold indicator with colors
4893
- if real_idx && has_children_in_array?(real_idx, @split_items)
4894
- if item["fold"]
4895
- line += "▶".fg("245") + " "
4953
+ embedded_lines.each do |embedded_line|
4954
+ if @wrap
4955
+ # Wrap each embedded line separately
4956
+ wrapped = wrap_line(embedded_line, @split_pane.w - 10, item["level"])
4957
+ text_lines.concat(wrapped)
4896
4958
  else
4897
- line += "▷".fg("245") + " "
4959
+ text_lines << embedded_line
4898
4960
  end
4899
- else
4900
- line += " "
4901
4961
  end
4902
4962
 
4903
- # Apply process_text for syntax highlighting
4904
- processed = process_text(item["text"], false)
4905
- line += processed
4906
-
4907
- # Apply background highlighting for current item in split pane
4908
- if idx == @split_current
4909
- # Choose background color based on whether this is the active pane
4910
- bg_color = @active_pane == :split ? "237" : "234"
4911
- bg_code = "\e[48;5;#{bg_color}m"
4912
- reset_bg = "\e[49m"
4913
- line = bg_code + line.gsub(/\e\[49m/, '') + reset_bg
4963
+ text_lines.each_with_index do |text_line, line_idx|
4964
+ # Add line number if enabled (only on first line)
4965
+ line = ""
4966
+ if @show_numbers
4967
+ if line_idx == 0
4968
+ actual_line_number = real_idx ? real_idx + 1 : 0 # +1 for 1-based line numbers
4969
+ line = "#{actual_line_number.to_s.rjust(4)} "
4970
+ else
4971
+ line = " " # Empty space for continuation lines
4972
+ end
4973
+ end
4974
+
4975
+ line += " " * item["level"]
4976
+
4977
+ # Add fold indicator with colors (only on first line)
4978
+ if line_idx == 0
4979
+ if real_idx && has_children_in_array?(real_idx, @split_items)
4980
+ if item["fold"]
4981
+ line += "▶".fg("245") + " "
4982
+ else
4983
+ line += "▷".fg("245") + " "
4984
+ end
4985
+ else
4986
+ line += " "
4987
+ end
4988
+ else
4989
+ line += " " # Just spacing for continuation lines
4990
+ end
4991
+
4992
+ # Apply process_text for syntax highlighting
4993
+ processed = process_text(text_line, false)
4994
+ line += processed
4995
+
4996
+ # Apply background highlighting for current item in split pane (all lines)
4997
+ if idx == @split_current
4998
+ # Choose background color based on whether this is the active pane
4999
+ bg_color = @active_pane == :split ? "237" : "234"
5000
+ bg_code = "\e[48;5;#{bg_color}m"
5001
+ reset_bg = "\e[49m"
5002
+ line = bg_code + line.gsub(/\e\[49m/, '') + reset_bg
5003
+ end
5004
+
5005
+ lines << line
4914
5006
  end
4915
-
4916
- lines << line
4917
5007
  end
4918
5008
 
4919
5009
  # Add a blank line at the bottom to show end of document
@@ -4934,22 +5024,25 @@ class HyperListApp
4934
5024
  end
4935
5025
  end
4936
5026
 
4937
- # Calculate scroll position exactly like RTFM does, but account for wrapping
5027
+ # Calculate scroll position based on actual line positions, not item indices
4938
5028
  scrolloff = 3
4939
- total = visible_items.length + 1 # +1 for the blank line
4940
- page = @split_pane.h
5029
+ total_lines = lines.length # Total number of actual display lines
5030
+ page = @split_pane.h # Height of the display area
5031
+
5032
+ # Get the actual line where the current item starts
5033
+ current_line = item_line_starts[@split_current] || 0
4941
5034
 
4942
- if total <= page
5035
+ if total_lines <= page
4943
5036
  # If everything fits, always start from the very top
4944
5037
  @split_pane.ix = 0
4945
- elsif @split_current - @split_pane.ix < scrolloff
5038
+ elsif current_line - @split_pane.ix < scrolloff
4946
5039
  # If we're too close to the top of the pane, scroll up
4947
- @split_pane.ix = [@split_current - scrolloff, 0].max
4948
- elsif (@split_pane.ix + page - 1 - @split_current) < scrolloff
5040
+ @split_pane.ix = [current_line - scrolloff, 0].max
5041
+ elsif (@split_pane.ix + page - 1 - current_line) < scrolloff
4949
5042
  # If we're too close to the bottom of the pane, scroll down
4950
- # Account for wrapped lines dynamically
4951
- max_off = [total - page + extra_wrapped_lines, 0].max
4952
- @split_pane.ix = [@split_current + scrolloff - page + 1, max_off].min
5043
+ # Make sure we don't scroll past the last line
5044
+ max_scroll = [total_lines - page, 0].max
5045
+ @split_pane.ix = [current_line + scrolloff - page + 1, max_scroll].min
4953
5046
  end
4954
5047
 
4955
5048
  @split_pane.refresh
data/hyperlist.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |spec|
2
2
  spec.name = "hyperlist"
3
- spec.version = "1.4.2"
3
+ spec.version = "1.4.3"
4
4
  spec.authors = ["Geir Isene"]
5
5
  spec.email = ["g@isene.com"]
6
6
 
@@ -1,77 +1,401 @@
1
1
  <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
- <svg xmlns="http://www.w3.org/2000/svg" width="512" height="512" viewBox="0 0 512 512">
3
- <defs>
4
- <!-- Terminal glow effect -->
5
- <filter id="glow">
6
- <feGaussianBlur stdDeviation="3" result="coloredBlur"/>
7
- <feMerge>
8
- <feMergeNode in="coloredBlur"/>
9
- <feMergeNode in="SourceGraphic"/>
2
+ <!-- Created with Inkscape (http://www.inkscape.org/) -->
3
+
4
+ <svg
5
+ width="134.72328mm"
6
+ height="134.55478mm"
7
+ viewBox="0 0 134.72328 134.55478"
8
+ version="1.1"
9
+ id="svg1"
10
+ xml:space="preserve"
11
+ sodipodi:docname="hyperlistlogo.svg"
12
+ inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)"
13
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
14
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
15
+ xmlns="http://www.w3.org/2000/svg"
16
+ xmlns:svg="http://www.w3.org/2000/svg"><sodipodi:namedview
17
+ id="namedview1"
18
+ pagecolor="#ffffff"
19
+ bordercolor="#000000"
20
+ borderopacity="0.25"
21
+ inkscape:showpageshadow="2"
22
+ inkscape:pageopacity="0.0"
23
+ inkscape:pagecheckerboard="0"
24
+ inkscape:deskcolor="#d1d1d1"
25
+ inkscape:document-units="mm"
26
+ inkscape:zoom="1.332716"
27
+ inkscape:cx="231.85734"
28
+ inkscape:cy="219.10144"
29
+ inkscape:window-width="1920"
30
+ inkscape:window-height="951"
31
+ inkscape:window-x="0"
32
+ inkscape:window-y="29"
33
+ inkscape:window-maximized="1"
34
+ inkscape:current-layer="svg1" />
35
+ <defs
36
+ id="defs1">
37
+ <linearGradient
38
+ id="linearGradient33"
39
+ x1="0"
40
+ y1="0"
41
+ x2="1"
42
+ y2="1">
43
+ <stop
44
+ offset="0"
45
+ style="stop-color:#00fa86;stop-opacity:1;"
46
+ id="stop32" />
47
+ <stop
48
+ offset="1"
49
+ style="stop-color:#00cc66;stop-opacity:1"
50
+ id="stop33" />
51
+ </linearGradient>
52
+ <filter
53
+ id="glow"
54
+ x="-1.184409"
55
+ y="-2.3688181"
56
+ width="3.3688181"
57
+ height="5.7376362">
58
+ <feGaussianBlur
59
+ stdDeviation="2.9610226"
60
+ result="coloredBlur"
61
+ id="feGaussianBlur1" />
62
+ <feMerge
63
+ id="feMerge2">
64
+ <feMergeNode
65
+ in="coloredBlur"
66
+ id="feMergeNode1" />
67
+ <feMergeNode
68
+ in="SourceGraphic"
69
+ id="feMergeNode2" />
10
70
  </feMerge>
11
71
  </filter>
12
- <!-- Gradient for depth -->
13
- <linearGradient id="grad" x1="0%" y1="0%" x2="100%" y2="100%">
14
- <stop offset="0%" style="stop-color:#00ff88;stop-opacity:1" />
15
- <stop offset="100%" style="stop-color:#00cc66;stop-opacity:1" />
72
+ <linearGradient
73
+ id="grad"
74
+ x1="0"
75
+ y1="0"
76
+ x2="1"
77
+ y2="1">
78
+ <stop
79
+ offset="0%"
80
+ style="stop-color:#00ff88;stop-opacity:1"
81
+ id="stop2" />
82
+ <stop
83
+ offset="100%"
84
+ style="stop-color:#00cc66;stop-opacity:1"
85
+ id="stop3" />
16
86
  </linearGradient>
87
+ <filter
88
+ style="color-interpolation-filters:sRGB"
89
+ id="filter6"
90
+ x="-0.39473927"
91
+ y="-0.17425425"
92
+ width="1.7894785"
93
+ height="1.3485085">
94
+ <feGaussianBlur
95
+ stdDeviation="0.4 0.4"
96
+ result="fbSourceGraphic"
97
+ id="feGaussianBlur6" />
98
+ <feColorMatrix
99
+ result="fbSourceGraphicAlpha"
100
+ in="fbSourceGraphic"
101
+ values="0 0 0 -1 0 0 0 0 -1 0 0 0 0 -1 0 0 0 0 1 0"
102
+ id="feColorMatrix8" />
103
+ <feGaussianBlur
104
+ id="feGaussianBlur8"
105
+ stdDeviation="0.4 0.4"
106
+ result="blur"
107
+ in="fbSourceGraphic" />
108
+ </filter>
109
+ <filter
110
+ style="color-interpolation-filters:sRGB"
111
+ id="filter22"
112
+ x="-0.0064666744"
113
+ y="-0.45590055"
114
+ width="1.0129333"
115
+ height="1.9118011">
116
+ <feGaussianBlur
117
+ stdDeviation="0.01 0.1"
118
+ result="blur"
119
+ id="feGaussianBlur22" />
120
+ </filter>
121
+ <filter
122
+ style="color-interpolation-filters:sRGB"
123
+ id="filter23"
124
+ x="-0.00056465436"
125
+ y="-0.20969008"
126
+ width="1.0011293"
127
+ height="1.4193802">
128
+ <feGaussianBlur
129
+ stdDeviation="0.01 0.11"
130
+ result="blur"
131
+ id="feGaussianBlur23" />
132
+ </filter>
133
+ <filter
134
+ id="filter28"
135
+ x="-0.040088417"
136
+ y="-0.21380489"
137
+ width="1.0801768"
138
+ height="1.4276098">
139
+ <feGaussianBlur
140
+ stdDeviation="2.1380488"
141
+ result="coloredBlur"
142
+ id="feGaussianBlur27" />
143
+ <feMerge
144
+ id="feMerge28">
145
+ <feMergeNode
146
+ in="coloredBlur"
147
+ id="feMergeNode27" />
148
+ <feMergeNode
149
+ in="SourceGraphic"
150
+ id="feMergeNode28" />
151
+ </feMerge>
152
+ </filter>
153
+ <filter
154
+ id="filter35"
155
+ x="-0.40035462"
156
+ y="-0.048042555"
157
+ width="1.8007092"
158
+ height="1.0960851">
159
+ <feGaussianBlur
160
+ stdDeviation="4.003546"
161
+ result="coloredBlur"
162
+ id="feGaussianBlur34" />
163
+ <feMerge
164
+ id="feMerge35">
165
+ <feMergeNode
166
+ in="coloredBlur"
167
+ id="feMergeNode34" />
168
+ <feMergeNode
169
+ in="SourceGraphic"
170
+ id="feMergeNode35" />
171
+ </feMerge>
172
+ </filter>
173
+ <filter
174
+ style="color-interpolation-filters:sRGB"
175
+ id="filter36"
176
+ x="-0.092322366"
177
+ y="-0.059838278"
178
+ width="1.1846447"
179
+ height="1.1196766">
180
+ <feGaussianBlur
181
+ stdDeviation="0.25392894"
182
+ id="feGaussianBlur36" />
183
+ </filter>
17
184
  </defs>
185
+ <rect
186
+ width="135.46666"
187
+ height="135.46666"
188
+ fill="#0d1117"
189
+ id="rect3"
190
+ x="-0.15747385"
191
+ y="-0.34253129"
192
+ style="stroke-width:0.264583" />
193
+ <rect
194
+ x="8.3091898"
195
+ y="8.124136"
196
+ width="118.27769"
197
+ height="10.583333"
198
+ rx="4.2242026"
199
+ ry="4.2333331"
200
+ fill="#161b22"
201
+ id="rect5"
202
+ style="stroke-width:0.264298" />
203
+ <rect
204
+ x="8.3091898"
205
+ y="8.124136"
206
+ width="118.53333"
207
+ height="118.53333"
208
+ rx="4.2333331"
209
+ ry="4.2333331"
210
+ fill="none"
211
+ stroke="#00ff88"
212
+ stroke-width="0.79375"
213
+ opacity="0.8"
214
+ id="rect4" />
215
+ <circle
216
+ cx="14.659192"
217
+ cy="13.4158"
218
+ fill="#ff5f56"
219
+ id="circle5"
220
+ style="stroke-width:0.264583"
221
+ r="1.5875" />
222
+ <circle
223
+ cx="19.950855"
224
+ cy="13.4158"
225
+ fill="#ffbd2e"
226
+ id="circle6"
227
+ style="stroke-width:0.264583"
228
+ r="1.5875" />
229
+ <circle
230
+ cx="25.242527"
231
+ cy="13.4158"
232
+ fill="#27c93f"
233
+ id="circle7"
234
+ style="stroke-width:0.264583"
235
+ r="1.5875" />
236
+ <rect
237
+ x="96"
238
+ y="120"
239
+ width="24"
240
+ height="200"
241
+ fill="url(#grad)"
242
+ id="rect7"
243
+ style="fill:#00e878;fill-opacity:1;filter:url(#glow)"
244
+ transform="matrix(0.26458333,0,0,0.26458333,-0.15747435,-0.3425329)" />
245
+ <rect
246
+ x="200"
247
+ y="120"
248
+ width="24"
249
+ height="200"
250
+ fill="url(#grad)"
251
+ id="rect8"
252
+ style="fill:#00e979;fill-opacity:1;filter:url(#filter35)"
253
+ transform="matrix(0.26458333,0,0,0.26458333,-0.15747435,-0.3425329)" />
254
+ <rect
255
+ x="96"
256
+ y="208"
257
+ width="128"
258
+ height="24"
259
+ fill="url(#grad)"
260
+ id="rect9"
261
+ style="mix-blend-mode:normal;fill:#00ea7a;fill-opacity:1;filter:url(#filter28)"
262
+ transform="matrix(0.26111189,0,0,0.26713774,0.40397665,-0.8584999)" />
263
+ <rect
264
+ x="260"
265
+ y="160"
266
+ width="8"
267
+ height="8"
268
+ fill="#00ff88"
269
+ id="rect11"
270
+ transform="matrix(0.26458333,0,0,0.26458333,-0.15747435,-0.3425329)"
271
+ style="filter:url(#glow)" />
272
+ <rect
273
+ x="276"
274
+ y="162"
275
+ width="100"
276
+ height="4"
277
+ fill="#00ff88"
278
+ opacity="0.6"
279
+ id="rect12"
280
+ transform="matrix(0.26458333,0,0,0.26458333,-0.15747435,-0.3425329)"
281
+ style="filter:url(#glow)" />
282
+ <rect
283
+ x="260"
284
+ y="190"
285
+ width="12"
286
+ height="12"
287
+ fill="none"
288
+ stroke="#00ff88"
289
+ stroke-width="2"
290
+ id="rect13"
291
+ transform="matrix(0.26458333,0,0,0.26458333,-0.15747435,-0.3425329)"
292
+ style="filter:url(#glow)" />
293
+ <polyline
294
+ points="263,196 266,199 270,193"
295
+ stroke="#00ff88"
296
+ stroke-width="2"
297
+ fill="none"
298
+ id="polyline13"
299
+ transform="matrix(0.26458333,0,0,0.26458333,-0.15747435,-0.3425329)"
300
+ style="filter:url(#glow)" />
301
+ <rect
302
+ x="280"
303
+ y="194"
304
+ width="96"
305
+ height="4"
306
+ fill="#00ff88"
307
+ opacity="0.6"
308
+ id="rect14"
309
+ transform="matrix(0.26458333,0,0,0.26458333,-0.15747435,-0.3425329)"
310
+ style="filter:url(#glow)" />
311
+ <rect
312
+ x="260"
313
+ y="220"
314
+ width="8"
315
+ height="8"
316
+ fill="#00ff88"
317
+ id="rect15"
318
+ transform="matrix(0.26458333,0,0,0.26458333,-0.15747435,-0.3425329)"
319
+ style="filter:url(#glow)" />
320
+ <rect
321
+ x="276"
322
+ y="222"
323
+ width="100"
324
+ height="4"
325
+ fill="#00ff88"
326
+ opacity="0.6"
327
+ id="rect16"
328
+ transform="matrix(0.26458333,0,0,0.26458333,-0.15747435,-0.3425329)"
329
+ style="filter:url(#glow)" />
330
+ <rect
331
+ x="288"
332
+ y="250"
333
+ width="6"
334
+ height="6"
335
+ fill="#00cc66"
336
+ id="rect17"
337
+ transform="matrix(0.26458333,0,0,0.26458333,-0.15747435,-0.3425329)"
338
+ style="filter:url(#glow)" />
339
+ <rect
340
+ x="300"
341
+ y="251"
342
+ width="76"
343
+ height="3"
344
+ fill="#00cc66"
345
+ opacity="0.5"
346
+ id="rect18"
347
+ transform="matrix(0.26458333,0,0,0.26458333,-0.15747435,-0.3425329)"
348
+ style="filter:url(#glow)" />
349
+ <rect
350
+ x="260"
351
+ y="280"
352
+ width="8"
353
+ height="8"
354
+ fill="#00ff88"
355
+ id="rect19"
356
+ transform="matrix(0.26458333,0,0,0.26458333,-0.15747435,-0.3425329)"
357
+ style="filter:url(#glow)" />
358
+ <rect
359
+ x="276"
360
+ y="282"
361
+ width="100"
362
+ height="4"
363
+ fill="#00ff88"
364
+ opacity="0.6"
365
+ id="rect20"
366
+ transform="matrix(0.26458333,0,0,0.26458333,-0.15747435,-0.3425329)"
367
+ style="filter:url(#glow)" />
368
+ <text
369
+ x="24.334553"
370
+ y="97.818535"
371
+ font-family="monospace"
372
+ font-size="4.57279px"
373
+ fill="#00ff88"
374
+ opacity="0.4"
375
+ id="text21"
376
+ style="stroke-width:0.326627">hyperlist v1.4.0 $</text>
377
+ <rect
378
+ style="fill:#00fe87;fill-opacity:1;stroke:none;stroke-width:5.98157;filter:url(#filter22)"
379
+ id="rect22"
380
+ width="3.7113357"
381
+ height="0.52643061"
382
+ x="68.35778"
383
+ y="52.855618"
384
+ ry="0" />
385
+ <rect
386
+ style="fill:#00e878;fill-opacity:1;stroke:none;stroke-width:6.174;filter:url(#filter36)"
387
+ id="rect35"
388
+ width="6.6011028"
389
+ height="10.184608"
390
+ x="101.5478"
391
+ y="73.953667"
392
+ ry="0.096021399">
393
+ <animate
394
+ attributeName="opacity"
395
+ values="1;0;1"
396
+ dur="1s"
397
+ repeatCount="indefinite" />
398
+ </rect>
399
+ </svg>
400
+ <!-- Terminal cursor blink -->
18
401
 
19
- <!-- Dark terminal background -->
20
- <rect width="512" height="512" fill="#0d1117"/>
21
-
22
- <!-- Terminal frame with rounded corners -->
23
- <rect x="32" y="32" width="448" height="448" rx="16" ry="16"
24
- fill="none" stroke="#00ff88" stroke-width="3" opacity="0.8"/>
25
-
26
- <!-- Terminal header bar -->
27
- <rect x="32" y="32" width="448" height="40" rx="16" ry="16" fill="#161b22"/>
28
- <circle cx="56" cy="52" r="6" fill="#ff5f56"/>
29
- <circle cx="76" cy="52" r="6" fill="#ffbd2e"/>
30
- <circle cx="96" cy="52" r="6" fill="#27c93f"/>
31
-
32
- <!-- Main HyperList logo design -->
33
- <g filter="url(#glow)">
34
- <!-- Large H that forms into list structure -->
35
- <!-- Left vertical of H -->
36
- <rect x="96" y="120" width="24" height="200" fill="url(#grad)"/>
37
- <!-- Right vertical of H -->
38
- <rect x="200" y="120" width="24" height="200" fill="url(#grad)"/>
39
- <!-- Horizontal crossbar of H -->
40
- <rect x="96" y="208" width="128" height="24" fill="url(#grad)"/>
41
-
42
- <!-- List items branching from H -->
43
- <!-- Main branch -->
44
- <rect x="224" y="208" width="160" height="4" fill="#00ff88" opacity="0.8"/>
45
-
46
- <!-- List item 1 -->
47
- <rect x="260" y="160" width="8" height="8" fill="#00ff88"/>
48
- <rect x="276" y="162" width="100" height="4" fill="#00ff88" opacity="0.6"/>
49
-
50
- <!-- List item 2 with checkbox -->
51
- <rect x="260" y="190" width="12" height="12" fill="none" stroke="#00ff88" stroke-width="2"/>
52
- <polyline points="263,196 266,199 270,193" stroke="#00ff88" stroke-width="2" fill="none"/>
53
- <rect x="280" y="194" width="96" height="4" fill="#00ff88" opacity="0.6"/>
54
-
55
- <!-- List item 3 -->
56
- <rect x="260" y="220" width="8" height="8" fill="#00ff88"/>
57
- <rect x="276" y="222" width="100" height="4" fill="#00ff88" opacity="0.6"/>
58
-
59
- <!-- Nested item -->
60
- <rect x="288" y="250" width="6" height="6" fill="#00cc66"/>
61
- <rect x="300" y="251" width="76" height="3" fill="#00cc66" opacity="0.5"/>
62
-
63
- <!-- List item 4 -->
64
- <rect x="260" y="280" width="8" height="8" fill="#00ff88"/>
65
- <rect x="276" y="282" width="100" height="4" fill="#00ff88" opacity="0.6"/>
66
-
67
- <!-- Terminal cursor blink -->
68
- <rect x="384" y="280" width="16" height="24" fill="#00ff88">
69
- <animate attributeName="opacity" values="1;0;1" dur="1s" repeatCount="indefinite"/>
70
- </rect>
71
- </g>
72
-
73
- <!-- Subtle terminal prompt at bottom -->
74
- <text x="96" y="380" font-family="monospace" font-size="14" fill="#00ff88" opacity="0.4">
75
- hyperlist v1.0.0 $
76
- </text>
77
- </svg>
data/sample.hl CHANGED
@@ -81,5 +81,29 @@ HyperList Sample Document
81
81
  _Underlined text example_
82
82
  Combined: *bold and /italic/ together*
83
83
  Hash tags: #important #urgent #review
84
+ Multi-line Items (HyperList spec)
85
+ + This is a multi-line item that continues
86
+ on the next line with a space prefix
87
+ + Items with the plus sign can span multiple lines
88
+ making it easy to write longer descriptions
89
+ without creating separate items
90
+ Consistency Rule Example
91
+ 1 When one item at a level has a starter (identifier)
92
+ all items at that level need starters
93
+ 2 This second item also needs an identifier
94
+ + Or you can use a plus sign as starter
95
+ Nested Multi-line Items
96
+ + Parent item that spans multiple lines
97
+ with detailed information on the first level
98
+ + Child item also spanning multiple lines
99
+ providing more specific details
100
+ Regular child item after multi-line
101
+ Real-world Examples
102
+ + Meeting notes from project kickoff: Discussed timeline,
103
+ budget constraints, resource allocation, and identified
104
+ key stakeholders who need to be involved
105
+ + Action item: Research competitive solutions in the market,
106
+ compile findings into a report, and present recommendations
107
+ to the management team by end of month
84
108
 
85
109
  ((fold_level=3))
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hyperlist
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.2
4
+ version: 1.4.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Geir Isene
8
8
  autorequire:
9
9
  bindir: "."
10
10
  cert_chain: []
11
- date: 2025-08-29 00:00:00.000000000 Z
11
+ date: 2025-08-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rcurses