hyperlist 1.9.0 → 1.9.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.
Files changed (6) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +43 -0
  3. data/README.md +23 -11
  4. data/hyperlist +64 -13
  5. data/hyperlist.gemspec +1 -1
  6. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1f638bfa971829555f7f078ed1c2e5a498a3e0d4026dea67fd547bc881fdec61
4
- data.tar.gz: 3cbb6c08d664e5ed7111384ef275293c9616c8c213f3cc189beaf1e3054fbfac
3
+ metadata.gz: 485f51c3f998ca45514979e831f928a2ca907674483ba1ceef644ce6db22423e
4
+ data.tar.gz: ca21fe8db31f2b1ac1a1e8059c92f94dbc17a8d42790247238f8073c77ef973d
5
5
  SHA512:
6
- metadata.gz: a71a5cfa04c8e52652f990d970f6fc7a1e65a5a89a9869b558937a016ae7c8e2aa0017910a23941158abbbfb6c8d92a2f0b8d50075cb3cb303d06c04f62c876d
7
- data.tar.gz: cccf1614ea64a35296d0de28b35d3ca3098fc31d68296cb271ef93ca5e085ffc2801fac04b98df96c72340b00adb39003fbcb55651f5561fe7e3a36ecf63a9e6
6
+ metadata.gz: d40e130fbff4cb2564f8a9c541257cd084072f1917067d529a86427c63b0e3716b7a6704f584cf64dc3e204fd0c63a71a20443f3bcef99bc5377bb43c657b7f3
7
+ data.tar.gz: 5e6a7cdf9f8b2fb7e93382e41ba8d6e2e39d0403a0e64480d763d8385f5e4d7320684ea4b1fd7503d5a4ed08fe515d5176a04d8ab8723f9e43b7ab9d04a9e2b8
data/CHANGELOG.md CHANGED
@@ -2,6 +2,49 @@
2
2
 
3
3
  All notable changes to the HyperList Ruby TUI will be documented in this file.
4
4
 
5
+ ## [1.9.1] - 2025-12-02
6
+
7
+ ### Added
8
+ - **External file change detection**
9
+ - Automatically detects when the file is modified by other processes (vim, another Claude Code session, etc.)
10
+ - Prompts user to reload with "File changed externally. Reload? (y/n)"
11
+ - Preserves cursor position after reload
12
+ - Option to ignore external changes (updates internal timestamp to avoid repeated prompts)
13
+
14
+ ### Fixed
15
+ - **Quote coloring inside parentheses (comments)**
16
+ - Fixed issue where quotes inside parentheses like `(this is a "comment" in here)` would break the cyan coloring
17
+ - The closing quote would terminate coloring, leaving the rest of the comment white
18
+ - Now the entire parentheses content stays cyan as intended
19
+
20
+ ## [1.9.0] - 2025-10-24
21
+
22
+ ### Added
23
+ - **Item Tagging & Batch Operations**
24
+ - Tag items with 't' key for batch operations (auto-advance cursor)
25
+ - Visual feedback: dark blue background for tagged items, lighter blue for tagged+selected
26
+ - Status bar shows [T:N] count of tagged items
27
+ - Clear all tags with 'u' key
28
+ - Regex tagging with 'C-T' - tag all items matching a pattern
29
+ - Batch operations: D/C-D (delete), y/Y (yank), Tab/S-Tab (indent) work on all tagged items
30
+
31
+ - **External Editor Support**
32
+ - Press 'E' to spawn $EDITOR (vim, nano, etc.)
33
+ - Automatic save/reload workflow
34
+ - Proper terminal state management
35
+ - Full screen refresh on return
36
+
37
+ - **Enhanced Paste & Navigation**
38
+ - 'P' to paste above current item (vim-style)
39
+ - Presentation mode moved to 'C-P'
40
+ - Templates moved to 'T' key
41
+ - Undo moved to 'U' key (RTFM-consistent)
42
+
43
+ ### Enhanced
44
+ - **Smart Modified Flag**
45
+ - [+] indicator removed when undoing back to original file state
46
+ - Tracks original state to detect true modifications
47
+
5
48
  ## [1.8.0] - 2025-09-22
6
49
 
7
50
  ### Enhanced
data/README.md CHANGED
@@ -29,9 +29,21 @@ For historical context and the original VIM implementation, see: [hyperlist.vim]
29
29
  ### Help Screen
30
30
  ![HyperList Help](img/screenshot_help.png)
31
31
 
32
- ## What's New in v1.9.0
32
+ ## What's New in v1.9.1
33
33
 
34
- ### 🏷️ Item Tagging & Batch Operations
34
+ ### External File Change Detection
35
+ - **Auto-detect external changes**: HyperList now monitors when the file is modified by other processes (vim, another Claude Code session, etc.)
36
+ - **Reload prompt**: Shows "File changed externally. Reload? (y/n)" when changes are detected
37
+ - **Cursor preservation**: Your cursor position is preserved after reload
38
+ - **Skip option**: Press 'n' to ignore external changes and continue editing
39
+
40
+ ### Bug Fix: Quote Coloring in Comments
41
+ - Fixed an issue where quotes inside parentheses (comments) like `(this is a "comment" in here)` would break the cyan coloring
42
+ - The entire parentheses content now stays cyan as intended
43
+
44
+ ## Previous Release: v1.9.0
45
+
46
+ ### Item Tagging & Batch Operations
35
47
  - **Tag items**: Press 't' to tag/untag items for batch operations
36
48
  - **Auto-advance**: Cursor automatically moves to next item after tagging for fast consecutive tagging
37
49
  - **Visual feedback**: Tagged items show dark blue background, lighter blue when selected
@@ -41,47 +53,47 @@ For historical context and the original VIM implementation, see: [hyperlist.vim]
41
53
  - **Batch operations**: Delete (D/C-D), yank (y/Y), and indent (Tab/S-Tab) work on all tagged items
42
54
  - Tag consecutive or non-consecutive items, then perform operations on the entire set
43
55
 
44
- ### ✏️ External Editor Support
56
+ ### External Editor Support
45
57
  - **Edit in $EDITOR**: Press 'E' to spawn your preferred editor (vim, nano, emacs, etc.)
46
58
  - **Seamless workflow**: File saved automatically, editor launched, changes reloaded on exit
47
59
  - **Terminal management**: Terminal state properly saved and restored
48
60
  - Uses `$EDITOR` environment variable (defaults to vi if not set)
49
61
 
50
- ### 📋 Enhanced Paste & Navigation
62
+ ### Enhanced Paste & Navigation
51
63
  - **Paste above**: Press 'P' to paste above current item (vim-style)
52
64
  - **Paste below**: Press 'p' to paste below current item (existing)
53
65
  - **Presentation mode**: Moved to 'C-P' (was 'P') for consistency
54
66
  - **Templates**: Moved to 'T' key (was 't')
55
67
  - **Undo**: Moved to 'U' key (was 'u') - consistent with RTFM
56
68
 
57
- ### 🎯 Smart Modified Flag
69
+ ### Smart Modified Flag
58
70
  - **Intelligent tracking**: `[+]` indicator automatically removed when undoing back to original file state
59
71
  - **Clean status**: No false "modified" indicator after complete undo to original
60
72
 
61
73
  ## Previous Release: v1.8.0
62
74
 
63
- ### 📋 Multi-Line Paste Support
75
+ ### Multi-Line Paste Support
64
76
  - **Paste multiple lines**: When pasting multi-line content into item insertion prompts ('o', 'O', 'a', 'A'), each line becomes a separate item
65
77
  - **Visual feedback**: Shows `[+N lines]` indicator during multi-line paste
66
78
  - **Smart insertion**: All pasted lines inserted as siblings at the same level
67
79
  - Great for importing bullet lists from PDFs, emails, or other documents
68
80
  - Requires rcurses 6.1.5+
69
81
 
70
- ### 📄 PDF/LaTeX Export
82
+ ### PDF/LaTeX Export
71
83
  - **Export to PDF**: `:export pdf filename.pdf` - Full LaTeX-based PDF generation
72
84
  - **Export to LaTeX**: `:export latex filename.tex` - Get the LaTeX source
73
85
  - **Professional output**: Color-coded elements, table of contents, headers
74
86
  - **Complete HyperList support**: All syntax elements rendered beautifully
75
87
  - Requires: texlive-latex-base and texlive-latex-extra packages
76
88
 
77
- ### 📋 System Clipboard Integration
89
+ ### System Clipboard Integration
78
90
  - **Yank to clipboard**: 'y' and 'Y' now copy to system clipboard
79
91
  - **Middle-click paste**: Yanked items can be pasted into other terminals
80
92
  - **Preserves indentation**: Copied text maintains proper structure
81
93
 
82
94
  ## Previous Version Features (v1.4.0)
83
95
 
84
- ### 🎨 Configuration Lines & Theming
96
+ ### Configuration Lines & Theming
85
97
  - **Configuration Lines**: Add settings at the bottom of HyperList files using `((option=value, option2=value))`
86
98
  - **Theme Support**: Three color themes - `light` (bright colors), `normal` (standard), `dark` (for light terminals)
87
99
  - **Line Wrapping**: Enable with `wrap=yes` - wrapped lines use `+` prefix per HyperList spec
@@ -142,13 +154,13 @@ All `:set` commands automatically update the file's configuration line.
142
154
  - Secure AES-256-CBC encryption with PBKDF2 key derivation
143
155
  - Password caching for the session
144
156
 
145
- ### 🎯 Enhanced Presentation Mode
157
+ ### Enhanced Presentation Mode
146
158
  - **Auto-collapse** everything outside the current context
147
159
  - **Smart focus**: Shows only current item, ancestors, and immediate children
148
160
  - **Visual hierarchy**: Focused items in full color, others greyed out
149
161
  - Improved navigation with proper cursor tracking
150
162
 
151
- ### 🎨 Better Visual Experience
163
+ ### Better Visual Experience
152
164
  - **Improved highlighting**: Dark gray background preserves syntax colors
153
165
  - **Subtle selection**: No more harsh reverse video
154
166
  - **Preserved colors**: All HyperList elements maintain their colors when selected
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.0 - Terminal User Interface for HyperList files
10
+ HyperList v1.9.1 - 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.0"
55
+ puts "HyperList v1.9.1"
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.0"
76
+ VERSION = "1.9.1"
77
77
 
78
78
  def initialize(filename = nil)
79
79
  @filename = filename ? File.expand_path(filename) : nil
@@ -124,7 +124,8 @@ class HyperListApp
124
124
  @split_offset = 0 # Second view scroll offset
125
125
  @active_pane = :main # :main or :split
126
126
  @message_timeout = nil # For timed message display
127
-
127
+ @file_mtime = nil # Track file modification time for external change detection
128
+
128
129
  # Global configuration
129
130
  @config_file = File.expand_path("~/.hyperlist/config.yml")
130
131
  @indent_size = 2 # Default indentation (2-5 spaces)
@@ -228,6 +229,9 @@ class HyperListApp
228
229
  @config_line = nil # Reset config line before loading
229
230
  @tagged_items = [] # Clear tags when loading new file
230
231
 
232
+ # Track file modification time for external change detection
233
+ @file_mtime = File.mtime(file) rescue nil
234
+
231
235
  # Read file content
232
236
  content = File.read(file) rescue ""
233
237
 
@@ -527,12 +531,48 @@ class HyperListApp
527
531
  def load_command_history
528
532
  history_file = File.expand_path("~/.hyperlist_command_history")
529
533
  return [] unless File.exist?(history_file)
530
-
534
+
531
535
  File.readlines(history_file).map(&:strip).reject(&:empty?).last(100)
532
536
  rescue
533
537
  []
534
538
  end
535
-
539
+
540
+ # Check if file was modified externally and prompt for reload
541
+ def check_file_changed
542
+ return unless @filename && File.exist?(@filename) && @file_mtime
543
+
544
+ current_mtime = File.mtime(@filename) rescue nil
545
+ return unless current_mtime && current_mtime > @file_mtime
546
+
547
+ # File changed externally - prompt user
548
+ @footer.text = "File changed externally. Reload? (y/n): "
549
+ @footer.refresh
550
+
551
+ response = getchr
552
+ if response&.downcase == 'y'
553
+ # Save cursor position
554
+ saved_current = @current
555
+ saved_offset = @offset
556
+
557
+ load_file(@filename)
558
+
559
+ # Restore cursor position (clamped to new file size)
560
+ visible = get_visible_items
561
+ @current = [saved_current, visible.length - 1, 0].max
562
+ @current = [@current, visible.length - 1].min if visible.length > 0
563
+ @offset = saved_offset
564
+
565
+ @message = "File reloaded"
566
+ @modified = false
567
+ clear_cache
568
+ render
569
+ else
570
+ # Update mtime to avoid repeated prompts
571
+ @file_mtime = current_mtime
572
+ @message = "External changes ignored"
573
+ end
574
+ end
575
+
536
576
  def save_command_history
537
577
  history_file = File.expand_path("~/.hyperlist_command_history")
538
578
  File.open(history_file, 'w') do |f|
@@ -712,6 +752,7 @@ class HyperListApp
712
752
  @modified = false
713
753
  @original_items = @items.map { |item| item.dup } # Save state after save
714
754
  @last_auto_save = Time.now if @auto_save_enabled
755
+ @file_mtime = File.mtime(@filename) rescue nil # Update mtime after save
715
756
  end
716
757
 
717
758
  def check_auto_save
@@ -1606,9 +1647,10 @@ class HyperListApp
1606
1647
 
1607
1648
  # Handle parentheses content (moved here to avoid conflicts with properties)
1608
1649
  # Based on hyperlist.vim: '(.\{-})'
1650
+ # Color entire parentheses content as cyan - quotes inside are also cyan
1609
1651
  result = safe_regex_replace(result, /\(([^)]*)\)/) do |match|
1610
- content = match[1..-2] # Extract content between parentheses
1611
- "(".fg(colors["cyan"]) + content.fg(colors["cyan"]) + ")".fg(colors["cyan"])
1652
+ # Just color the whole thing cyan - no special handling for quotes inside
1653
+ match.fg(colors["cyan"])
1612
1654
  end
1613
1655
 
1614
1656
  # Handle semicolons as separators (they separate items on the same line)
@@ -1624,11 +1666,17 @@ class HyperListApp
1624
1666
 
1625
1667
  # Handle quoted strings (only double quotes are special in HyperList)
1626
1668
  # Based on hyperlist.vim: '".\{-}"'
1627
- result.gsub!(/"([^"]*)"/) do
1628
- content = $1
1669
+ # Use safe_regex_replace to avoid processing quotes inside already-colored parentheses
1670
+ result = safe_regex_replace(result, /"([^"]*)"/) do |match|
1671
+ content = match[1..-2] # Extract content between quotes
1629
1672
  # Color any ## sequences inside the quotes as red
1630
- content.gsub!(/(##[<>-]+)/) { $1.fg(colors["red"]) }
1631
- '"'.fg(colors["cyan"]) + content.fg(colors["cyan"]) + '"'.fg(colors["cyan"]) # Cyan for quoted strings
1673
+ colored_content = content.gsub(/(##[<>-]+)/) { $1.fg(colors["red"]) }
1674
+ # If no ## sequences were found, just color the whole thing cyan
1675
+ if colored_content == content
1676
+ match.fg(colors["cyan"]) # Color entire quoted string cyan
1677
+ else
1678
+ '"'.fg(colors["cyan"]) + colored_content + '"'.fg(colors["cyan"])
1679
+ end
1632
1680
  end
1633
1681
 
1634
1682
  # Handle change markup - all double-hashes should be red
@@ -6397,7 +6445,10 @@ class HyperListApp
6397
6445
  loop do
6398
6446
  # Check for auto-save
6399
6447
  check_auto_save if @auto_save_enabled
6400
-
6448
+
6449
+ # Check for external file changes
6450
+ check_file_changed
6451
+
6401
6452
  c = getchr
6402
6453
 
6403
6454
  # Skip nil input (shouldn't happen normally)
data/hyperlist.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |spec|
2
2
  spec.name = "hyperlist"
3
- spec.version = "1.9.0"
3
+ spec.version = "1.9.1"
4
4
  spec.authors = ["Geir Isene"]
5
5
  spec.email = ["g@isene.com"]
6
6
 
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.9.0
4
+ version: 1.9.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Geir Isene
8
8
  autorequire:
9
9
  bindir: "."
10
10
  cert_chain: []
11
- date: 2025-10-24 00:00:00.000000000 Z
11
+ date: 2025-12-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rcurses