hyperlist 1.4.2 → 1.4.4
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 +21 -0
- data/hyperlist +219 -80
- data/hyperlist.gemspec +1 -1
- data/img/hyperlist_logo.svg +395 -71
- data/sample.hl +24 -0
- metadata +2 -3
- data/test.hl +0 -154
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3dc0016e32134b62af690e6f612eac1820b601cbf86246fb9969441371600a4e
|
4
|
+
data.tar.gz: 9be26ded0329bc112f10a79f2fffdb3c28174812665956a79b4ec1b88c854a6f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dbe6dbcec4e20da66ff2e7cea0a8f57d7f7001790a3d5313498ae5be5e170509ad777155b09e1b969dc47fdb630923ebebbc1cb17016608615cd3378d3158652
|
7
|
+
data.tar.gz: 57bf4c6764337eba7502ccaceb7a158d8ce8dd09c7840cf9c05047e2787910f0d28e446f913456fd7ee8893ec9be5fadb7b1b8f5766aebfd181a4cd7154fc8a6
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,27 @@
|
|
2
2
|
|
3
3
|
All notable changes to the HyperList Ruby TUI will be documented in this file.
|
4
4
|
|
5
|
+
## [1.4.4] - 2025-09-01
|
6
|
+
|
7
|
+
### Added
|
8
|
+
- **Case conversion commands**
|
9
|
+
- `gU` to convert current line to UPPERCASE
|
10
|
+
- `gu` to convert current line to lowercase
|
11
|
+
- Works with all HyperList elements (checkboxes, operators, etc.)
|
12
|
+
|
13
|
+
### Fixed
|
14
|
+
- **Color code display issues**
|
15
|
+
- Fixed bracket content extraction in safe_regex_replace to preserve qualifier text
|
16
|
+
- Updated operator regex pattern to match after ANSI placeholders
|
17
|
+
- Both numbered lists (1.) and operators (NOT:) now color correctly when combined
|
18
|
+
|
19
|
+
## [1.4.3] - 2025-08-30
|
20
|
+
|
21
|
+
### Fixed
|
22
|
+
- **Multi-line item handling**
|
23
|
+
- Proper handling of multi-line items per HyperList specification
|
24
|
+
- Fixed display and editing of items with embedded newlines
|
25
|
+
|
5
26
|
## [1.4.2] - 2025-08-29
|
6
27
|
|
7
28
|
### Fixed
|
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.
|
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.
|
75
|
+
VERSION = "1.4.4"
|
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
|
-
|
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
|
-
|
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
|
-
#
|
978
|
-
|
979
|
-
|
980
|
-
|
981
|
-
|
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
|
1091
|
-
#
|
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
|
-
|
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
|
1155
|
+
if total_lines <= page
|
1097
1156
|
# If everything fits, always start from the very top
|
1098
1157
|
@main.ix = 0
|
1099
|
-
elsif
|
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 = [
|
1102
|
-
elsif (@main.ix + page - 1 -
|
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
|
-
#
|
1105
|
-
|
1106
|
-
@main.ix = [
|
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
|
@@ -1278,7 +1337,10 @@ class HyperListApp
|
|
1278
1337
|
elsif !processed_checkbox
|
1279
1338
|
# Only handle other qualifiers if we didn't process a checkbox
|
1280
1339
|
# Based on hyperlist.vim: '\[.\{-}\]'
|
1281
|
-
result
|
1340
|
+
result = safe_regex_replace(result, /\[([^\]]*)\]/) do |match|
|
1341
|
+
content = match[1..-2] # Extract content between brackets
|
1342
|
+
"[#{content}]".fg(colors["green"]) # Green for all qualifiers
|
1343
|
+
end
|
1282
1344
|
end
|
1283
1345
|
|
1284
1346
|
# We'll handle parentheses AFTER operators/properties to avoid conflicts
|
@@ -1292,21 +1354,27 @@ class HyperListApp
|
|
1292
1354
|
# Handle operators and properties with colon pattern
|
1293
1355
|
# Operators: ALL-CAPS followed by colon (with or without space)
|
1294
1356
|
# Properties: Mixed case followed by colon and space
|
1295
|
-
|
1296
|
-
|
1297
|
-
|
1298
|
-
|
1299
|
-
|
1300
|
-
|
1301
|
-
|
1302
|
-
|
1303
|
-
|
1304
|
-
|
1305
|
-
|
1306
|
-
|
1357
|
+
# Modified pattern to also match after ANSI placeholders (⟨ANSI\d+⟩)
|
1358
|
+
result = safe_regex_replace(result, /(\A|\s+|⟨ANSI\d+⟩)([a-zA-Z][a-zA-Z0-9_\-() .\/=]*):(\s*)/) do |match|
|
1359
|
+
# Extract parts from the match
|
1360
|
+
if match =~ /(\A|\s+|⟨ANSI\d+⟩)([a-zA-Z][a-zA-Z0-9_\-() .\/=]*):(\s*)/
|
1361
|
+
prefix_space = $1
|
1362
|
+
text_part = $2
|
1363
|
+
space_after = $3 || ""
|
1364
|
+
colon_space = ":#{space_after}"
|
1365
|
+
|
1366
|
+
# Check if it's an operator (ALL-CAPS with optional _, -, (), /, =, spaces)
|
1367
|
+
if text_part =~ /^[A-Z][A-Z_\-() \/=]*$/
|
1368
|
+
prefix_space + text_part.fg(colors["blue"]) + colon_space.fg(colors["blue"]) # Blue for operators (including S: and T:)
|
1369
|
+
elsif text_part.length >= 2 && space_after.include?(" ")
|
1370
|
+
# It's a property (mixed case, at least 2 chars, has space after colon)
|
1371
|
+
prefix_space + text_part.fg(colors["red"]) + colon_space.fg(colors["red"]) # Red for properties
|
1372
|
+
else
|
1373
|
+
# Leave as is
|
1374
|
+
match
|
1375
|
+
end
|
1307
1376
|
else
|
1308
|
-
|
1309
|
-
prefix_space + text_part + colon_space
|
1377
|
+
match
|
1310
1378
|
end
|
1311
1379
|
end
|
1312
1380
|
|
@@ -2275,6 +2343,34 @@ class HyperListApp
|
|
2275
2343
|
clear_cache # Clear cache when content changes
|
2276
2344
|
end
|
2277
2345
|
|
2346
|
+
def uppercase_line
|
2347
|
+
visible = get_visible_items
|
2348
|
+
return if @current >= visible.length
|
2349
|
+
|
2350
|
+
item = visible[@current]
|
2351
|
+
real_idx = get_real_index(item)
|
2352
|
+
|
2353
|
+
save_undo_state # Save state before modification
|
2354
|
+
@items[real_idx]["text"] = item["text"].upcase
|
2355
|
+
@modified = true
|
2356
|
+
clear_cache # Clear cache when content changes
|
2357
|
+
@message = "Line converted to uppercase"
|
2358
|
+
end
|
2359
|
+
|
2360
|
+
def lowercase_line
|
2361
|
+
visible = get_visible_items
|
2362
|
+
return if @current >= visible.length
|
2363
|
+
|
2364
|
+
item = visible[@current]
|
2365
|
+
real_idx = get_real_index(item)
|
2366
|
+
|
2367
|
+
save_undo_state # Save state before modification
|
2368
|
+
@items[real_idx]["text"] = item["text"].downcase
|
2369
|
+
@modified = true
|
2370
|
+
clear_cache # Clear cache when content changes
|
2371
|
+
@message = "Line converted to lowercase"
|
2372
|
+
end
|
2373
|
+
|
2278
2374
|
def delete_line(with_children = false)
|
2279
2375
|
visible = get_visible_items
|
2280
2376
|
return if visible.empty?
|
@@ -2824,6 +2920,7 @@ class HyperListApp
|
|
2824
2920
|
help_lines << help_line("#{"i/Enter".fg("10")}", "Edit line", "#{"o".fg("10")}", "Insert line below")
|
2825
2921
|
help_lines << help_line("#{"O".fg("10")}", "Insert line above", "#{"a".fg("10")}", "Insert child")
|
2826
2922
|
help_lines << help_line("#{"A".fg("10")}", "Insert outdented", "#{"W".fg("10")}", "Save and quit")
|
2923
|
+
help_lines << help_line("#{"gU".fg("10")}", "Uppercase line", "#{"gu".fg("10")}", "Lowercase line")
|
2827
2924
|
help_lines << help_line("#{"I".fg("10")}", "Cycle indent (2-5)")
|
2828
2925
|
help_lines << help_line("#{"D".fg("10")}", "Delete+yank line", "#{"C-D".fg("10")}", "Delete+yank item&descendants")
|
2829
2926
|
help_lines << help_line("#{"y".fg("10")}" + "/".fg("10") + "#{"Y".fg("10")}", "Copy line/tree", "#{"p".fg("10")}", "Paste")
|
@@ -4874,46 +4971,77 @@ class HyperListApp
|
|
4874
4971
|
|
4875
4972
|
# Build ALL lines for the pane (like we do for main pane)
|
4876
4973
|
lines = []
|
4974
|
+
|
4975
|
+
# Track which line number each item starts at (for scroll calculation)
|
4976
|
+
item_line_starts = {}
|
4977
|
+
|
4877
4978
|
visible_items.each_with_index do |item, idx|
|
4878
4979
|
next unless item
|
4879
4980
|
|
4981
|
+
# Record where this item starts in the display
|
4982
|
+
item_line_starts[idx] = lines.length
|
4983
|
+
|
4880
4984
|
# Find the item's position in the original split_items array
|
4881
4985
|
real_idx = @split_items.index(item)
|
4882
4986
|
|
4883
|
-
#
|
4884
|
-
|
4885
|
-
|
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"]
|
4987
|
+
# Handle multi-line items (split by embedded newlines)
|
4988
|
+
embedded_lines = item["text"].split("\n")
|
4989
|
+
text_lines = []
|
4891
4990
|
|
4892
|
-
|
4893
|
-
|
4894
|
-
|
4895
|
-
|
4991
|
+
embedded_lines.each do |embedded_line|
|
4992
|
+
if @wrap
|
4993
|
+
# Wrap each embedded line separately
|
4994
|
+
wrapped = wrap_line(embedded_line, @split_pane.w - 10, item["level"])
|
4995
|
+
text_lines.concat(wrapped)
|
4896
4996
|
else
|
4897
|
-
|
4997
|
+
text_lines << embedded_line
|
4898
4998
|
end
|
4899
|
-
else
|
4900
|
-
line += " "
|
4901
4999
|
end
|
4902
5000
|
|
4903
|
-
|
4904
|
-
|
4905
|
-
|
4906
|
-
|
4907
|
-
|
4908
|
-
|
4909
|
-
|
4910
|
-
|
4911
|
-
|
4912
|
-
|
4913
|
-
|
5001
|
+
text_lines.each_with_index do |text_line, line_idx|
|
5002
|
+
# Add line number if enabled (only on first line)
|
5003
|
+
line = ""
|
5004
|
+
if @show_numbers
|
5005
|
+
if line_idx == 0
|
5006
|
+
actual_line_number = real_idx ? real_idx + 1 : 0 # +1 for 1-based line numbers
|
5007
|
+
line = "#{actual_line_number.to_s.rjust(4)} "
|
5008
|
+
else
|
5009
|
+
line = " " # Empty space for continuation lines
|
5010
|
+
end
|
5011
|
+
end
|
5012
|
+
|
5013
|
+
line += " " * item["level"]
|
5014
|
+
|
5015
|
+
# Add fold indicator with colors (only on first line)
|
5016
|
+
if line_idx == 0
|
5017
|
+
if real_idx && has_children_in_array?(real_idx, @split_items)
|
5018
|
+
if item["fold"]
|
5019
|
+
line += "▶".fg("245") + " "
|
5020
|
+
else
|
5021
|
+
line += "▷".fg("245") + " "
|
5022
|
+
end
|
5023
|
+
else
|
5024
|
+
line += " "
|
5025
|
+
end
|
5026
|
+
else
|
5027
|
+
line += " " # Just spacing for continuation lines
|
5028
|
+
end
|
5029
|
+
|
5030
|
+
# Apply process_text for syntax highlighting
|
5031
|
+
processed = process_text(text_line, false)
|
5032
|
+
line += processed
|
5033
|
+
|
5034
|
+
# Apply background highlighting for current item in split pane (all lines)
|
5035
|
+
if idx == @split_current
|
5036
|
+
# Choose background color based on whether this is the active pane
|
5037
|
+
bg_color = @active_pane == :split ? "237" : "234"
|
5038
|
+
bg_code = "\e[48;5;#{bg_color}m"
|
5039
|
+
reset_bg = "\e[49m"
|
5040
|
+
line = bg_code + line.gsub(/\e\[49m/, '') + reset_bg
|
5041
|
+
end
|
5042
|
+
|
5043
|
+
lines << line
|
4914
5044
|
end
|
4915
|
-
|
4916
|
-
lines << line
|
4917
5045
|
end
|
4918
5046
|
|
4919
5047
|
# Add a blank line at the bottom to show end of document
|
@@ -4934,22 +5062,25 @@ class HyperListApp
|
|
4934
5062
|
end
|
4935
5063
|
end
|
4936
5064
|
|
4937
|
-
# Calculate scroll position
|
5065
|
+
# Calculate scroll position based on actual line positions, not item indices
|
4938
5066
|
scrolloff = 3
|
4939
|
-
|
4940
|
-
page = @split_pane.h
|
5067
|
+
total_lines = lines.length # Total number of actual display lines
|
5068
|
+
page = @split_pane.h # Height of the display area
|
5069
|
+
|
5070
|
+
# Get the actual line where the current item starts
|
5071
|
+
current_line = item_line_starts[@split_current] || 0
|
4941
5072
|
|
4942
|
-
if
|
5073
|
+
if total_lines <= page
|
4943
5074
|
# If everything fits, always start from the very top
|
4944
5075
|
@split_pane.ix = 0
|
4945
|
-
elsif
|
5076
|
+
elsif current_line - @split_pane.ix < scrolloff
|
4946
5077
|
# If we're too close to the top of the pane, scroll up
|
4947
|
-
@split_pane.ix = [
|
4948
|
-
elsif (@split_pane.ix + page - 1 -
|
5078
|
+
@split_pane.ix = [current_line - scrolloff, 0].max
|
5079
|
+
elsif (@split_pane.ix + page - 1 - current_line) < scrolloff
|
4949
5080
|
# If we're too close to the bottom of the pane, scroll down
|
4950
|
-
#
|
4951
|
-
|
4952
|
-
@split_pane.ix = [
|
5081
|
+
# Make sure we don't scroll past the last line
|
5082
|
+
max_scroll = [total_lines - page, 0].max
|
5083
|
+
@split_pane.ix = [current_line + scrolloff - page + 1, max_scroll].min
|
4953
5084
|
end
|
4954
5085
|
|
4955
5086
|
@split_pane.refresh
|
@@ -5520,13 +5651,21 @@ class HyperListApp
|
|
5520
5651
|
@current = [visible.length - 1, 0].max
|
5521
5652
|
update_presentation_focus if @presentation_mode
|
5522
5653
|
end
|
5523
|
-
when "g" # Go to top (
|
5524
|
-
|
5525
|
-
|
5526
|
-
|
5527
|
-
@
|
5528
|
-
|
5529
|
-
|
5654
|
+
when "g" # Go to top (gg) or text case commands (gU/gu)
|
5655
|
+
next_c = getchr
|
5656
|
+
case next_c
|
5657
|
+
when "g" # gg - go to top
|
5658
|
+
if @split_view && @active_pane == :split
|
5659
|
+
@split_current = 0
|
5660
|
+
else
|
5661
|
+
@current = 0
|
5662
|
+
@offset = 0
|
5663
|
+
update_presentation_focus if @presentation_mode
|
5664
|
+
end
|
5665
|
+
when "U" # gU - uppercase line
|
5666
|
+
uppercase_line
|
5667
|
+
when "u" # gu - lowercase line
|
5668
|
+
lowercase_line
|
5530
5669
|
end
|
5531
5670
|
when "G" # Go to bottom
|
5532
5671
|
if @split_view && @active_pane == :split
|
data/hyperlist.gemspec
CHANGED
data/img/hyperlist_logo.svg
CHANGED
@@ -1,77 +1,401 @@
|
|
1
1
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
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
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
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.
|
4
|
+
version: 1.4.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Geir Isene
|
8
8
|
autorequire:
|
9
9
|
bindir: "."
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-
|
11
|
+
date: 2025-09-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rcurses
|
@@ -79,7 +79,6 @@ files:
|
|
79
79
|
- img/screenshot_help.png
|
80
80
|
- img/screenshot_sample.png
|
81
81
|
- sample.hl
|
82
|
-
- test.hl
|
83
82
|
homepage: https://github.com/isene/HyperList
|
84
83
|
licenses:
|
85
84
|
- Unlicense
|
data/test.hl
DELETED
@@ -1,154 +0,0 @@
|
|
1
|
-
HyperList Ruby TUI Test Suite v1.0
|
2
|
-
About This Test Suite
|
3
|
-
Purpose: Test all features of the HyperList Ruby TUI application
|
4
|
-
Run with: ./hyperlist test.hl
|
5
|
-
Navigate through and test each feature systematically
|
6
|
-
SYNTAX HIGHLIGHTING & COLORS
|
7
|
-
Check: Property in red; Dates like 2025-08-12 should be red
|
8
|
-
AND: OR: IF: THEN: Operators should appear in blue
|
9
|
-
[?] Conditional checkboxes should be green
|
10
|
-
#hashtags should appear in yellow/orange
|
11
|
-
<references> should appear in magenta
|
12
|
-
(parentheses content) should be in cyan
|
13
|
-
"quoted strings" should be in bright cyan
|
14
|
-
*bold text* should appear bold
|
15
|
-
/italic text/ should appear italic
|
16
|
-
_underlined text_ should appear underlined
|
17
|
-
Templates with = markers for filling
|
18
|
-
NAVIGATION TESTS
|
19
|
-
Basic Movement
|
20
|
-
j/↓ Move down through items
|
21
|
-
k/↑ Move up through items
|
22
|
-
h Go to parent item (move cursor here and press h)
|
23
|
-
l Go to first child (press l from parent)
|
24
|
-
g/Home Go to top of document
|
25
|
-
G/End Go to bottom of document
|
26
|
-
PgUp/PgDn Page up and down
|
27
|
-
Search
|
28
|
-
Slash key: Search for text (try searching for "test")
|
29
|
-
n Jump to next search match
|
30
|
-
Marks and Jumps
|
31
|
-
ma Set mark 'a' at current position
|
32
|
-
'a Jump back to mark 'a'
|
33
|
-
'' Jump to previous position
|
34
|
-
R Jump to reference (place cursor on <NAVIGATION TESTS> and press R)
|
35
|
-
Template Navigation
|
36
|
-
First template =
|
37
|
-
Second template =
|
38
|
-
Third template =
|
39
|
-
Press N to jump to next template marker and edit
|
40
|
-
FOLDING TESTS
|
41
|
-
Space Toggle fold on this item
|
42
|
-
This child should hide/show when parent is folded
|
43
|
-
And this grandchild too
|
44
|
-
Even deeper nesting works
|
45
|
-
za Toggle all folds recursively
|
46
|
-
zo Open fold / zc Close fold
|
47
|
-
zR Open all folds / zM Close all folds
|
48
|
-
1-9 Expand to specific level (try pressing 2)
|
49
|
-
Level 2 item
|
50
|
-
Level 3 item
|
51
|
-
Level 4 item
|
52
|
-
Level 5 item
|
53
|
-
0 Multi-digit fold level (press 0 then 1 then 2 for level 12)
|
54
|
-
EDITING TESTS
|
55
|
-
Basic Editing
|
56
|
-
i/Enter Edit current line
|
57
|
-
o Insert new line below
|
58
|
-
O Insert new line above
|
59
|
-
a Insert child item
|
60
|
-
Delete Operations
|
61
|
-
D Delete and yank current line only
|
62
|
-
C-D Delete and yank item with all descendants
|
63
|
-
Copy/Paste
|
64
|
-
y Copy current line only
|
65
|
-
Y Copy item with descendants
|
66
|
-
p Paste yanked content
|
67
|
-
Undo/Redo
|
68
|
-
u Undo last change
|
69
|
-
r/C-R Redo undone change
|
70
|
-
. Repeat last action
|
71
|
-
Moving Items
|
72
|
-
S-UP/S-DOWN Move single item up/down
|
73
|
-
C-UP/C-DOWN Move item with descendants up/down
|
74
|
-
Indentation
|
75
|
-
Tab Indent item and children
|
76
|
-
S-Tab Unindent item and children
|
77
|
-
→ Indent item only
|
78
|
-
← Unindent item only
|
79
|
-
CHECKBOX TESTS
|
80
|
-
[ ] Press v to add/toggle checkbox
|
81
|
-
[X] Completed checkbox (green)
|
82
|
-
[O] In progress checkbox (bright green bold)
|
83
|
-
[-] Partial checkbox (dim green)
|
84
|
-
[?] Conditional checkbox (green)
|
85
|
-
[3] Numbered checkbox
|
86
|
-
[2025-08-12 14:30] Date checkbox
|
87
|
-
Press V to toggle with timestamp
|
88
|
-
SPECIAL FEATURES
|
89
|
-
Presentation Mode
|
90
|
-
Press P to enter presentation mode
|
91
|
-
Current item and ancestors shown, rest hidden
|
92
|
-
Press P again to exit
|
93
|
-
Underline Toggle
|
94
|
-
\u Toggle underlining of state/transition items
|
95
|
-
S: State items (descriptive)
|
96
|
-
T: Transition items (actions)
|
97
|
-
File Operations
|
98
|
-
F Open file reference (place cursor on file path)
|
99
|
-
<sample.hl> Try opening this reference with F
|
100
|
-
FILE COMMANDS
|
101
|
-
:w Save file
|
102
|
-
:q Quit (asks to save if modified)
|
103
|
-
:wq Save and quit
|
104
|
-
Q Force quit without saving
|
105
|
-
:e filename Open another file
|
106
|
-
:recent Show recent files
|
107
|
-
:export md Export to Markdown
|
108
|
-
:export html Export to HTML
|
109
|
-
:export txt Export to plain text
|
110
|
-
:graph Generate PNG graph visualization
|
111
|
-
:vsplit Split view vertically
|
112
|
-
ww Switch between split panes
|
113
|
-
:as on Enable autosave
|
114
|
-
:as off Disable autosave
|
115
|
-
:as 30 Set autosave interval to 30 seconds
|
116
|
-
ADVANCED TESTS
|
117
|
-
Complex Nesting
|
118
|
-
Parent 1
|
119
|
-
Child 1.1
|
120
|
-
Grandchild 1.1.1
|
121
|
-
Great-grandchild 1.1.1.1
|
122
|
-
Great-great-grandchild 1.1.1.1.1
|
123
|
-
Child 1.2
|
124
|
-
Grandchild 1.2.1
|
125
|
-
Grandchild 1.2.2
|
126
|
-
Parent 2
|
127
|
-
Child 2.1
|
128
|
-
Child 2.2
|
129
|
-
Mixed Formatting
|
130
|
-
Item with *bold* and /italic/ and _underline_
|
131
|
-
Item with #multiple #hash #tags
|
132
|
-
Item with <reference> and (parentheses) and "quotes"
|
133
|
-
AND: Operator with [X] checkbox and 2025-08-12: date
|
134
|
-
Long Lines
|
135
|
-
This is a very long line that should wrap properly in the terminal display and maintain proper indentation when it continues on the next visual line without breaking the hierarchical structure of the HyperList
|
136
|
-
Special Characters
|
137
|
-
Item with special chars: @#$%^&*(){}[]|\\:;"'<>,.?/
|
138
|
-
Unicode: ★ ☆ ♠ ♣ ♥ ♦ → ← ↑ ↓
|
139
|
-
Emojis: 😀 🎉 ✓ ✗ ⚠️ 📝
|
140
|
-
HELP SYSTEM
|
141
|
-
? Show help screen with key bindings
|
142
|
-
?? Show full documentation
|
143
|
-
Use UP/DOWN to scroll through help
|
144
|
-
Press any other key to exit help
|
145
|
-
TEST COMPLETION
|
146
|
-
[ ] All syntax highlighting verified
|
147
|
-
[ ] All navigation features tested
|
148
|
-
[ ] All folding operations work
|
149
|
-
[ ] All editing functions tested
|
150
|
-
[ ] Checkboxes functioning correctly
|
151
|
-
[ ] Special features operational
|
152
|
-
[ ] File commands working
|
153
|
-
[ ] Help system accessible
|
154
|
-
If all tests pass, the Ruby HyperList TUI is working correctly!
|