hyperlist 1.9.1 → 1.9.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 +9 -0
- data/README.md +8 -1
- data/hyperlist +79 -85
- data/hyperlist.gemspec +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: bb81e544d2363e852a1e29bb1eef3d2fd891e766b2ade2a3e5c56fdc3073302e
|
|
4
|
+
data.tar.gz: 14f24e55bfb6f3241ef9120cadcc680971617bfa5378893c3523e4eb1cb1105b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 067b8ba96f97768aa5461e2458b7215cf045926875765ac631b450c9a15ed2313ded67f7986163c6fef8c5408dddf0160a10fa7933ffedbe23722822078e9060
|
|
7
|
+
data.tar.gz: c10a7a1e147fadd212445b9d5ee7baadada737f53ccc55aa89db86f95f2cb208edf1d56a373020c4ac51c5a898e5c2198cb1458cccbfea36526dff104cfe61a7
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to the HyperList Ruby TUI will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [1.9.2] - 2025-12-02
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
- **Presentation mode completely rewritten**
|
|
9
|
+
- Now dynamically folds/unfolds as you navigate (like hyperlist.vim)
|
|
10
|
+
- Entering presentation mode (C-P) now stays on the current item instead of jumping to the first line
|
|
11
|
+
- Moving up/down properly reveals the path to the current item while folding everything else
|
|
12
|
+
- Uses proper item tracking via real indices to handle fold state changes correctly
|
|
13
|
+
|
|
5
14
|
## [1.9.1] - 2025-12-02
|
|
6
15
|
|
|
7
16
|
### Added
|
data/README.md
CHANGED
|
@@ -29,7 +29,14 @@ For historical context and the original VIM implementation, see: [hyperlist.vim]
|
|
|
29
29
|
### Help Screen
|
|
30
30
|

|
|
31
31
|
|
|
32
|
-
## What's New in v1.9.
|
|
32
|
+
## What's New in v1.9.2
|
|
33
|
+
|
|
34
|
+
### Presentation Mode Fixed
|
|
35
|
+
- **Dynamic folding**: Presentation mode now works like hyperlist.vim - folds/unfolds dynamically as you navigate
|
|
36
|
+
- **Cursor preservation**: Entering presentation mode (C-P) stays on the current item instead of jumping to the first line
|
|
37
|
+
- **Proper navigation**: Moving up/down reveals the path to the current item while folding everything else
|
|
38
|
+
|
|
39
|
+
## Previous Release: v1.9.1
|
|
33
40
|
|
|
34
41
|
### External File Change Detection
|
|
35
42
|
- **Auto-detect external changes**: HyperList now monitors when the file is modified by other processes (vim, another Claude Code session, etc.)
|
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.9.
|
|
10
|
+
HyperList v1.9.2 - Terminal User Interface for HyperList files
|
|
11
11
|
|
|
12
12
|
USAGE
|
|
13
13
|
hyperlist [OPTIONS] [FILE]
|
|
@@ -52,7 +52,7 @@ if ARGV[0] == '-h' || ARGV[0] == '--help'
|
|
|
52
52
|
HELP
|
|
53
53
|
exit 0
|
|
54
54
|
elsif ARGV[0] == '-v' || ARGV[0] == '--version'
|
|
55
|
-
puts "HyperList v1.9.
|
|
55
|
+
puts "HyperList v1.9.2"
|
|
56
56
|
exit 0
|
|
57
57
|
end
|
|
58
58
|
|
|
@@ -73,7 +73,7 @@ class HyperListApp
|
|
|
73
73
|
include Rcurses::Input
|
|
74
74
|
include Rcurses::Cursor
|
|
75
75
|
|
|
76
|
-
VERSION = "1.9.
|
|
76
|
+
VERSION = "1.9.2"
|
|
77
77
|
|
|
78
78
|
def initialize(filename = nil)
|
|
79
79
|
@filename = filename ? File.expand_path(filename) : nil
|
|
@@ -2043,28 +2043,28 @@ class HyperListApp
|
|
|
2043
2043
|
|
|
2044
2044
|
def move_up
|
|
2045
2045
|
if @presentation_mode
|
|
2046
|
-
# In presentation mode
|
|
2047
|
-
|
|
2048
|
-
|
|
2046
|
+
# In presentation mode: move to target, then update folds
|
|
2047
|
+
visible = get_visible_items
|
|
2048
|
+
return if visible.empty?
|
|
2049
|
+
|
|
2050
|
+
# Calculate target position
|
|
2049
2051
|
if @current == 0
|
|
2050
|
-
|
|
2051
|
-
target_index = visible_before.length - 1
|
|
2052
|
+
target_index = visible.length - 1
|
|
2052
2053
|
else
|
|
2053
2054
|
target_index = @current - 1
|
|
2054
2055
|
end
|
|
2055
|
-
|
|
2056
|
-
# Get the
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
# Update presentation focus for the target item
|
|
2056
|
+
|
|
2057
|
+
# Get the real index of the target item
|
|
2058
|
+
target_real_idx = get_real_index(visible[target_index])
|
|
2059
|
+
|
|
2060
|
+
# Temporarily set current to target so update_presentation_focus works on it
|
|
2061
2061
|
@current = target_index
|
|
2062
2062
|
update_presentation_focus
|
|
2063
|
-
|
|
2064
|
-
#
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
if
|
|
2063
|
+
|
|
2064
|
+
# After fold changes, find where the target item is now
|
|
2065
|
+
new_visible = get_visible_items
|
|
2066
|
+
new_visible.each_with_index do |item, idx|
|
|
2067
|
+
if item["_real_index"] == target_real_idx
|
|
2068
2068
|
@current = idx
|
|
2069
2069
|
break
|
|
2070
2070
|
end
|
|
@@ -2072,9 +2072,8 @@ class HyperListApp
|
|
|
2072
2072
|
else
|
|
2073
2073
|
# Normal mode navigation
|
|
2074
2074
|
max_items = get_visible_items.length - 1
|
|
2075
|
-
|
|
2075
|
+
|
|
2076
2076
|
if @current == 0
|
|
2077
|
-
# Wrap around to last item
|
|
2078
2077
|
@current = max_items
|
|
2079
2078
|
else
|
|
2080
2079
|
@current = [@current - 1, 0].max
|
|
@@ -2084,29 +2083,29 @@ class HyperListApp
|
|
|
2084
2083
|
|
|
2085
2084
|
def move_down
|
|
2086
2085
|
if @presentation_mode
|
|
2087
|
-
# In presentation mode
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2086
|
+
# In presentation mode: move to target, then update folds
|
|
2087
|
+
visible = get_visible_items
|
|
2088
|
+
return if visible.empty?
|
|
2089
|
+
max = visible.length - 1
|
|
2090
|
+
|
|
2091
|
+
# Calculate target position
|
|
2092
|
+
if @current >= max
|
|
2093
2093
|
target_index = 0
|
|
2094
2094
|
else
|
|
2095
2095
|
target_index = @current + 1
|
|
2096
2096
|
end
|
|
2097
|
-
|
|
2098
|
-
# Get the
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
# Update presentation focus for the target item
|
|
2097
|
+
|
|
2098
|
+
# Get the real index of the target item
|
|
2099
|
+
target_real_idx = get_real_index(visible[target_index])
|
|
2100
|
+
|
|
2101
|
+
# Temporarily set current to target so update_presentation_focus works on it
|
|
2103
2102
|
@current = target_index
|
|
2104
2103
|
update_presentation_focus
|
|
2105
|
-
|
|
2106
|
-
#
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
if
|
|
2104
|
+
|
|
2105
|
+
# After fold changes, find where the target item is now
|
|
2106
|
+
new_visible = get_visible_items
|
|
2107
|
+
new_visible.each_with_index do |item, idx|
|
|
2108
|
+
if item["_real_index"] == target_real_idx
|
|
2110
2109
|
@current = idx
|
|
2111
2110
|
break
|
|
2112
2111
|
end
|
|
@@ -2114,9 +2113,8 @@ class HyperListApp
|
|
|
2114
2113
|
else
|
|
2115
2114
|
# Normal mode navigation
|
|
2116
2115
|
max = get_visible_items.length - 1
|
|
2117
|
-
|
|
2118
|
-
if @current
|
|
2119
|
-
# Wrap around to first item
|
|
2116
|
+
|
|
2117
|
+
if @current >= max
|
|
2120
2118
|
@current = 0
|
|
2121
2119
|
else
|
|
2122
2120
|
@current = [@current + 1, max].min
|
|
@@ -2345,84 +2343,80 @@ class HyperListApp
|
|
|
2345
2343
|
# Enter presentation mode
|
|
2346
2344
|
# Remember which item we're on before any folding changes
|
|
2347
2345
|
visible_items = get_visible_items
|
|
2348
|
-
if @current
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2346
|
+
return if visible_items.empty? || @current >= visible_items.length
|
|
2347
|
+
|
|
2348
|
+
# Get the real index of the current item
|
|
2349
|
+
target_real_idx = visible_items[@current]["_real_index"]
|
|
2350
|
+
|
|
2352
2351
|
@presentation_mode = true
|
|
2353
|
-
# Clear cache to force re-rendering
|
|
2352
|
+
# Clear cache to force re-rendering
|
|
2354
2353
|
@processed_cache.clear
|
|
2355
2354
|
update_presentation_focus
|
|
2356
|
-
|
|
2357
|
-
#
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2355
|
+
|
|
2356
|
+
# Find where the target item is after fold changes
|
|
2357
|
+
new_visible = get_visible_items
|
|
2358
|
+
new_visible.each_with_index do |item, idx|
|
|
2359
|
+
if item["_real_index"] == target_real_idx
|
|
2360
|
+
@current = idx
|
|
2361
|
+
break
|
|
2362
|
+
end
|
|
2362
2363
|
end
|
|
2363
|
-
|
|
2364
|
-
@message = "Presentation mode enabled
|
|
2364
|
+
|
|
2365
|
+
@message = "Presentation mode enabled"
|
|
2365
2366
|
end
|
|
2366
2367
|
end
|
|
2367
2368
|
|
|
2368
2369
|
def update_presentation_focus
|
|
2369
|
-
#
|
|
2370
|
-
#
|
|
2370
|
+
# Presentation mode: fold everything, then reveal path to current item
|
|
2371
|
+
# Like vim's: fold to level 0, then zv (reveal current line)
|
|
2371
2372
|
return unless @presentation_mode
|
|
2372
|
-
|
|
2373
|
+
|
|
2373
2374
|
visible_items = get_visible_items
|
|
2374
2375
|
return if visible_items.empty? || @current >= visible_items.length
|
|
2375
|
-
|
|
2376
|
-
#
|
|
2376
|
+
|
|
2377
|
+
# Get the current item before we change anything
|
|
2377
2378
|
current_item = visible_items[@current]
|
|
2378
|
-
current_level = current_item["level"]
|
|
2379
2379
|
current_real_idx = get_real_index(current_item)
|
|
2380
|
-
|
|
2381
|
-
|
|
2380
|
+
return unless current_real_idx
|
|
2381
|
+
|
|
2382
|
+
current_level = current_item["level"]
|
|
2383
|
+
|
|
2384
|
+
# Step 1: Fold everything that has children
|
|
2382
2385
|
@items.each_with_index do |item, idx|
|
|
2383
2386
|
item["fold"] = has_children?(idx, @items)
|
|
2384
2387
|
item["presentation_focus"] = false
|
|
2385
2388
|
end
|
|
2386
|
-
|
|
2387
|
-
#
|
|
2388
|
-
if current_real_idx && current_real_idx < @items.length
|
|
2389
|
-
@items[current_real_idx]["presentation_focus"] = true
|
|
2390
|
-
@items[current_real_idx]["fold"] = false
|
|
2391
|
-
end
|
|
2392
|
-
|
|
2393
|
-
# Unfold all ancestors of current item
|
|
2394
|
-
ancestor_indices = []
|
|
2389
|
+
|
|
2390
|
+
# Step 2: Unfold all ancestors (path from root to current item)
|
|
2395
2391
|
search_level = current_level - 1
|
|
2396
2392
|
idx = current_real_idx - 1
|
|
2397
|
-
|
|
2398
2393
|
while idx >= 0 && search_level >= 0
|
|
2399
2394
|
if @items[idx]["level"] == search_level
|
|
2400
|
-
@items[idx]["fold"] = false
|
|
2401
|
-
@items[idx]["presentation_focus"] = false # Ancestors visible but not focused
|
|
2402
|
-
ancestor_indices << idx
|
|
2395
|
+
@items[idx]["fold"] = false # Unfold this ancestor
|
|
2403
2396
|
search_level -= 1
|
|
2404
2397
|
end
|
|
2405
2398
|
idx -= 1
|
|
2406
2399
|
end
|
|
2407
|
-
|
|
2408
|
-
#
|
|
2400
|
+
|
|
2401
|
+
# Step 3: Unfold the current item to show its direct children
|
|
2402
|
+
@items[current_real_idx]["fold"] = false
|
|
2403
|
+
@items[current_real_idx]["presentation_focus"] = true
|
|
2404
|
+
|
|
2405
|
+
# Step 4: Mark direct children as in focus (for visual highlighting)
|
|
2409
2406
|
idx = current_real_idx + 1
|
|
2410
2407
|
while idx < @items.length && @items[idx]["level"] > current_level
|
|
2411
2408
|
if @items[idx]["level"] == current_level + 1
|
|
2412
2409
|
@items[idx]["presentation_focus"] = true
|
|
2413
|
-
# Don't unfold children - let them stay folded unless user explicitly unfolds
|
|
2414
2410
|
end
|
|
2415
2411
|
idx += 1
|
|
2416
2412
|
end
|
|
2417
|
-
|
|
2418
|
-
#
|
|
2413
|
+
|
|
2414
|
+
# Step 5: Recalculate cursor position after fold changes
|
|
2419
2415
|
new_visible_items = get_visible_items
|
|
2420
2416
|
new_position = new_visible_items.index(current_item)
|
|
2421
|
-
if new_position
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
# Clear cache to force re-rendering with new focus
|
|
2417
|
+
@current = new_position if new_position
|
|
2418
|
+
|
|
2419
|
+
# Clear cache to force re-rendering
|
|
2426
2420
|
@processed_cache.clear
|
|
2427
2421
|
end
|
|
2428
2422
|
|
data/hyperlist.gemspec
CHANGED