hyperlist 1.1.6 → 1.2.0
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 +24 -0
- data/README.md +22 -5
- data/hyperlist +303 -48
- data/hyperlist.gemspec +2 -2
- metadata +7 -13
- data/debug_instructions.md +0 -112
- data/diagnose.rb +0 -115
- data/diagnose_ruby34.rb +0 -145
- data/diagnose_safe.rb +0 -198
- data/fix_terminal.sh +0 -33
- data/hyperlist_ruby34_wrapper.rb +0 -57
- /data/{hyperlist_logo.svg → img/hyperlist_logo.svg} +0 -0
- /data/{screenshot_help.png → img/screenshot_help.png} +0 -0
- /data/{screenshot_sample.png → img/screenshot_sample.png} +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: aef5338683dfa697e59042f093e0db9a748ef53515952a295b1c9eb972519ac5
|
4
|
+
data.tar.gz: fbad5a0f6022d40cfd147846d3de81b317b41fff39036c9085a0230fc0a144c4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fd23aaaaa0ffbb7b1d73fdc99a46d3fb08d265000e1e10651e747857a4ab5d78dbf523d967e87d4ca82a1f0f8ff46d3fc563cec4441c3a86de7a3651f0cb41e6
|
7
|
+
data.tar.gz: 98ae50b53b8a9b4578ed50c81b8dcd763af2273f44bca200f27627cdc808f61b620baa0d76c09a9a776107de3de637e50c1daf660c7c77903debb8ee1868909d
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,30 @@
|
|
2
2
|
|
3
3
|
All notable changes to the HyperList Ruby TUI will be documented in this file.
|
4
4
|
|
5
|
+
## [1.2.0] - 2025-08-20
|
6
|
+
|
7
|
+
### Added
|
8
|
+
- **User-Defined Templates**
|
9
|
+
- Save any HyperList document as a reusable template (`:st` or `:save-template`)
|
10
|
+
- Template manager for listing and deleting custom templates (`:lt`, `:dt`)
|
11
|
+
- Enhanced template browser showing both built-in and user templates
|
12
|
+
- Template metadata including description and creation date
|
13
|
+
- Templates stored in `~/.hyperlist/templates/` for easy backup and sharing
|
14
|
+
- JSON format for template storage with full hierarchy preservation
|
15
|
+
|
16
|
+
### Changed
|
17
|
+
- Template system now supports both built-in and user-created templates
|
18
|
+
- Template browser UI improved with separate sections for built-in vs user templates
|
19
|
+
- Help documentation updated with new template commands
|
20
|
+
|
21
|
+
## [1.1.7] - 2025-08-15
|
22
|
+
|
23
|
+
### Fixed
|
24
|
+
- **Updated rcurses dependency to 5.1.6**
|
25
|
+
- Fixes Ruby 3.4.5 hanging issue during terminal initialization
|
26
|
+
- rcurses now handles stdin.raw! blocking with timeout and stty fallback
|
27
|
+
- Fully backward compatible
|
28
|
+
|
5
29
|
## [1.1.6] - 2025-08-14
|
6
30
|
|
7
31
|
### Fixed
|
data/README.md
CHANGED
@@ -6,7 +6,8 @@
|
|
6
6
|
[](https://github.com/isene/HyperList/stargazers)
|
7
7
|
[](https://isene.org)
|
8
8
|
|
9
|
-
<img src="hyperlist_logo.svg" align="left" width="150" height="150">
|
9
|
+
<img src="img/hyperlist_logo.svg" align="left" width="150" height="150">
|
10
|
+
<br clear="left"/>
|
10
11
|
|
11
12
|
A powerful Terminal User Interface (TUI) application for creating, editing, and managing HyperLists - a methodology for describing anything in a hierarchical, structured format.
|
12
13
|
|
@@ -23,12 +24,21 @@ For historical context and the original VIM implementation, see: [hyperlist.vim]
|
|
23
24
|
## Screenshots
|
24
25
|
|
25
26
|
### Main Interface
|
26
|
-

|
27
|
+

|
27
28
|
|
28
29
|
### Help Screen
|
29
|
-

|
30
|
+

|
31
|
+
|
32
|
+
## What's New in v1.2.0
|
30
33
|
|
31
|
-
|
34
|
+
### 📝 User-Defined Templates
|
35
|
+
- **Save as Template**: Save any HyperList document as a reusable template (`:st`)
|
36
|
+
- **Template Manager**: List and delete your custom templates (`:lt`, `:dt`)
|
37
|
+
- **Enhanced Template Browser**: Shows both built-in and user templates
|
38
|
+
- **Template Metadata**: Includes description and creation date
|
39
|
+
- Templates stored in `~/.hyperlist/templates/` for easy backup and sharing
|
40
|
+
|
41
|
+
## Previous Updates (v1.1.0)
|
32
42
|
|
33
43
|
### 🔐 Encryption Support
|
34
44
|
- **File-level encryption** for sensitive files (dot files like `.passwords.hl`)
|
@@ -62,7 +72,7 @@ For historical context and the original VIM implementation, see: [hyperlist.vim]
|
|
62
72
|
- **Powerful Navigation**: Jump between items, references, and markers
|
63
73
|
- **Full Editing Capabilities**: Create, edit, delete, move, and reorganize items
|
64
74
|
- **Checkbox Support**: Multiple checkbox types with completion tracking
|
65
|
-
- **Template System**:
|
75
|
+
- **Template System**: Built-in templates plus save/load custom templates
|
66
76
|
- **Presentation Mode**: Focus on current item with auto-collapse
|
67
77
|
|
68
78
|
### Security Features
|
@@ -158,6 +168,7 @@ hyperlist file.txt # Open any text file
|
|
158
168
|
- `R` - Go to reference
|
159
169
|
- `F` - Open file reference
|
160
170
|
- `P` - Presentation mode (with auto-collapse)
|
171
|
+
- `t` - Insert template (built-in or custom)
|
161
172
|
- `?` - Help screen
|
162
173
|
|
163
174
|
#### File Commands
|
@@ -169,6 +180,12 @@ hyperlist file.txt # Open any text file
|
|
169
180
|
- `:export md` - Export to Markdown
|
170
181
|
- `:graph` - Export to PNG
|
171
182
|
|
183
|
+
#### Template Commands
|
184
|
+
- `:st` - Save current document as template
|
185
|
+
- `:dt` - Delete a user template
|
186
|
+
- `:lt` - List all user templates
|
187
|
+
- `t` - Browse and insert templates
|
188
|
+
|
172
189
|
## Examples
|
173
190
|
|
174
191
|
### Simple Todo List
|
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.
|
10
|
+
HyperList v1.2.0 - 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.
|
55
|
+
puts "HyperList v1.2.0"
|
56
56
|
exit 0
|
57
57
|
end
|
58
58
|
|
@@ -64,13 +64,15 @@ require 'cgi'
|
|
64
64
|
require 'openssl'
|
65
65
|
require 'digest'
|
66
66
|
require 'base64'
|
67
|
+
require 'fileutils'
|
68
|
+
require 'json'
|
67
69
|
|
68
70
|
class HyperListApp
|
69
71
|
include Rcurses
|
70
72
|
include Rcurses::Input
|
71
73
|
include Rcurses::Cursor
|
72
74
|
|
73
|
-
VERSION = "1.
|
75
|
+
VERSION = "1.2.0"
|
74
76
|
|
75
77
|
def initialize(filename = nil)
|
76
78
|
@filename = filename ? File.expand_path(filename) : nil
|
@@ -98,6 +100,8 @@ class HyperListApp
|
|
98
100
|
@auto_save_enabled = false
|
99
101
|
@auto_save_interval = 60 # seconds
|
100
102
|
@last_auto_save = Time.now
|
103
|
+
@templates_dir = File.expand_path("~/.hyperlist/templates")
|
104
|
+
ensure_templates_dir
|
101
105
|
@templates = load_templates
|
102
106
|
@macro_recording = false
|
103
107
|
@macro_register = {} # Store macros by key
|
@@ -136,8 +140,11 @@ class HyperListApp
|
|
136
140
|
end
|
137
141
|
|
138
142
|
def setup_ui
|
139
|
-
|
140
|
-
|
143
|
+
# Only do rcurses operations if initialized
|
144
|
+
if defined?(Rcurses.instance_variable_get) && Rcurses.instance_variable_get(:@initialized)
|
145
|
+
Rcurses.clear_screen
|
146
|
+
Cursor.hide
|
147
|
+
end
|
141
148
|
|
142
149
|
# Ensure we have the latest terminal size
|
143
150
|
if IO.console
|
@@ -2169,7 +2176,7 @@ class HyperListApp
|
|
2169
2176
|
help_lines << help_line("#{"C-E".fg("10")}", "Encrypt/decrypt line", "#{"C-U".fg("10")}", "Toggle State/Trans underline")
|
2170
2177
|
help_lines << help_line("#{"R".fg("10")}", "Go to reference", "#{"F".fg("10")}", "Open file")
|
2171
2178
|
help_lines << help_line("#{"N".fg("10")}", "Next = marker", "#{"P".fg("10")}", "Presentation mode")
|
2172
|
-
help_lines << help_line("#{"t".fg("10")}", "Insert template", "#{":
|
2179
|
+
help_lines << help_line("#{"t".fg("10")}", "Insert template", "#{":st".fg("10")}", "Save as template")
|
2173
2180
|
help_lines << help_line("#{"Ma".fg("10")}", "Record macro 'a'", "#{"@a".fg("10")}", "Play macro 'a'")
|
2174
2181
|
help_lines << help_line("#{":vsplit".fg("10")}", "Split view vertically", "#{"w".fg("10")}", "Switch panes")
|
2175
2182
|
help_lines << ""
|
@@ -2180,6 +2187,11 @@ class HyperListApp
|
|
2180
2187
|
help_lines << help_line("#{":graph :g".fg("10")}", "Export to PNG graph", "#{":vsplit :vs".fg("10")}", "Split view")
|
2181
2188
|
help_lines << help_line("#{":as on".fg("10")}", "Enable autosave", "#{":as off".fg("10")}", "Disable autosave")
|
2182
2189
|
help_lines << help_line("#{":as N".fg("10")}", "Set interval (secs)", "#{":as".fg("10")}", "Show autosave status")
|
2190
|
+
help_lines << ""
|
2191
|
+
help_lines << "#{"TEMPLATES".fg("14")}"
|
2192
|
+
help_lines << help_line("#{":st".fg("10")}", "Save as template", "#{":dt".fg("10")}", "Delete template")
|
2193
|
+
help_lines << help_line("#{":lt".fg("10")}", "List user templates", "#{"t".fg("10")}", "Insert template")
|
2194
|
+
help_lines << ""
|
2183
2195
|
help_lines << help_line("#{"q".fg("10")}", "Quit (asks to save)", "#{"Q".fg("10")}", "Force quit")
|
2184
2196
|
help_lines << ""
|
2185
2197
|
help_lines << "#{"COLOR SCHEME".fg("14")}"
|
@@ -2853,8 +2865,18 @@ class HyperListApp
|
|
2853
2865
|
when "autosave", "as"
|
2854
2866
|
status = @auto_save_enabled ? "enabled" : "disabled"
|
2855
2867
|
@message = "Auto-save is #{status} (interval: #{@auto_save_interval}s)"
|
2856
|
-
when "t"
|
2868
|
+
when "t", "template", "templates"
|
2857
2869
|
show_templates
|
2870
|
+
when "save-template", "savetemplate", "st"
|
2871
|
+
save_as_template
|
2872
|
+
when /^save-template\s+(.+)/, /^savetemplate\s+(.+)/, /^st\s+(.+)/
|
2873
|
+
save_as_template($1.strip)
|
2874
|
+
when "delete-template", "deletetemplate", "dt"
|
2875
|
+
delete_template
|
2876
|
+
when /^delete-template\s+(.+)/, /^deletetemplate\s+(.+)/, /^dt\s+(.+)/
|
2877
|
+
delete_template($1.strip)
|
2878
|
+
when "list-templates", "listtemplates", "lt"
|
2879
|
+
show_template_manager(:list)
|
2858
2880
|
when "foldlevel"
|
2859
2881
|
level = @footer.ask("Fold to level (0-9): ", "")
|
2860
2882
|
if level =~ /^[0-9]$/
|
@@ -3202,8 +3224,13 @@ class HyperListApp
|
|
3202
3224
|
end
|
3203
3225
|
end
|
3204
3226
|
|
3227
|
+
def ensure_templates_dir
|
3228
|
+
FileUtils.mkdir_p(@templates_dir) unless File.exist?(@templates_dir)
|
3229
|
+
end
|
3230
|
+
|
3205
3231
|
def load_templates
|
3206
|
-
|
3232
|
+
# Start with built-in templates
|
3233
|
+
templates = {
|
3207
3234
|
"project" => [
|
3208
3235
|
{"text" => "Project: =Project Name=", "level" => 0},
|
3209
3236
|
{"text" => "[_] Define project scope", "level" => 1},
|
@@ -3306,6 +3333,214 @@ class HyperListApp
|
|
3306
3333
|
{"text" => "=Tips, variations, serving suggestions=", "level" => 2}
|
3307
3334
|
]
|
3308
3335
|
}
|
3336
|
+
|
3337
|
+
# Load user templates from templates directory
|
3338
|
+
if File.directory?(@templates_dir)
|
3339
|
+
Dir.glob(File.join(@templates_dir, "*.hlt")).each do |template_file|
|
3340
|
+
template_name = File.basename(template_file, ".hlt")
|
3341
|
+
begin
|
3342
|
+
template_data = JSON.parse(File.read(template_file))
|
3343
|
+
# Convert template data to the expected format
|
3344
|
+
if template_data.is_a?(Hash) && template_data["items"]
|
3345
|
+
templates[template_name] = template_data["items"].map do |item|
|
3346
|
+
{"text" => item["text"], "level" => item["level"]}
|
3347
|
+
end
|
3348
|
+
end
|
3349
|
+
rescue => e
|
3350
|
+
# Skip invalid template files
|
3351
|
+
end
|
3352
|
+
end
|
3353
|
+
end
|
3354
|
+
|
3355
|
+
templates
|
3356
|
+
end
|
3357
|
+
|
3358
|
+
def save_as_template(name = nil)
|
3359
|
+
# Ask for template name if not provided
|
3360
|
+
if name.nil? || name.empty?
|
3361
|
+
name = @footer.ask("Template name: ", "")
|
3362
|
+
return if name.nil? || name.empty?
|
3363
|
+
end
|
3364
|
+
|
3365
|
+
# Sanitize template name
|
3366
|
+
name = name.gsub(/[^a-zA-Z0-9_-]/, '_')
|
3367
|
+
|
3368
|
+
# Ask for description
|
3369
|
+
description = @footer.ask("Template description (optional): ", "")
|
3370
|
+
|
3371
|
+
# Prepare template data
|
3372
|
+
template_data = {
|
3373
|
+
"name" => name,
|
3374
|
+
"description" => description,
|
3375
|
+
"created" => Time.now.strftime("%Y-%m-%dT%H:%M:%S"),
|
3376
|
+
"items" => @items.map do |item|
|
3377
|
+
{
|
3378
|
+
"text" => item["text"],
|
3379
|
+
"level" => item["level"]
|
3380
|
+
}
|
3381
|
+
end
|
3382
|
+
}
|
3383
|
+
|
3384
|
+
# Save template file
|
3385
|
+
template_path = File.join(@templates_dir, "#{name}.hlt")
|
3386
|
+
|
3387
|
+
# Check if template already exists
|
3388
|
+
if File.exist?(template_path)
|
3389
|
+
response = @footer.ask("Template '#{name}' already exists. Overwrite? (y/n): ", "")
|
3390
|
+
return unless response.downcase == 'y'
|
3391
|
+
end
|
3392
|
+
|
3393
|
+
File.write(template_path, JSON.pretty_generate(template_data))
|
3394
|
+
@message = "Template '#{name}' saved successfully"
|
3395
|
+
end
|
3396
|
+
|
3397
|
+
def delete_template(name = nil)
|
3398
|
+
# Get list of user templates
|
3399
|
+
user_templates = get_user_templates
|
3400
|
+
|
3401
|
+
if user_templates.empty?
|
3402
|
+
@message = "No user templates found"
|
3403
|
+
return
|
3404
|
+
end
|
3405
|
+
|
3406
|
+
# Show template list if name not provided
|
3407
|
+
if name.nil? || name.empty?
|
3408
|
+
show_template_manager(:delete)
|
3409
|
+
return
|
3410
|
+
end
|
3411
|
+
|
3412
|
+
template_path = File.join(@templates_dir, "#{name}.hlt")
|
3413
|
+
|
3414
|
+
if File.exist?(template_path)
|
3415
|
+
response = @footer.ask("Delete template '#{name}'? (y/n): ", "")
|
3416
|
+
if response.downcase == 'y'
|
3417
|
+
File.delete(template_path)
|
3418
|
+
@message = "Template '#{name}' deleted"
|
3419
|
+
# Reload templates
|
3420
|
+
@templates = load_templates
|
3421
|
+
end
|
3422
|
+
else
|
3423
|
+
@message = "Template '#{name}' not found"
|
3424
|
+
end
|
3425
|
+
end
|
3426
|
+
|
3427
|
+
def get_user_templates
|
3428
|
+
templates = []
|
3429
|
+
if File.directory?(@templates_dir)
|
3430
|
+
Dir.glob(File.join(@templates_dir, "*.hlt")).each do |template_file|
|
3431
|
+
template_name = File.basename(template_file, ".hlt")
|
3432
|
+
begin
|
3433
|
+
template_data = JSON.parse(File.read(template_file))
|
3434
|
+
templates << {
|
3435
|
+
"name" => template_name,
|
3436
|
+
"description" => template_data["description"] || "",
|
3437
|
+
"created" => template_data["created"] || "",
|
3438
|
+
"path" => template_file
|
3439
|
+
}
|
3440
|
+
rescue => e
|
3441
|
+
# Skip invalid template files
|
3442
|
+
end
|
3443
|
+
end
|
3444
|
+
end
|
3445
|
+
templates.sort_by { |t| t["name"] }
|
3446
|
+
end
|
3447
|
+
|
3448
|
+
def show_template_manager(action = :list)
|
3449
|
+
# Store original state
|
3450
|
+
original_state = {
|
3451
|
+
items: @items.dup,
|
3452
|
+
current: @current,
|
3453
|
+
offset: @offset,
|
3454
|
+
filename: @filename,
|
3455
|
+
modified: @modified
|
3456
|
+
}
|
3457
|
+
|
3458
|
+
user_templates = get_user_templates
|
3459
|
+
|
3460
|
+
# Build template manager view
|
3461
|
+
@items = []
|
3462
|
+
case action
|
3463
|
+
when :delete
|
3464
|
+
@items << {"text" => "DELETE TEMPLATE (press Enter to delete, q to cancel)", "level" => 0, "fold" => false, "raw" => true}
|
3465
|
+
else
|
3466
|
+
@items << {"text" => "USER TEMPLATES (press Enter to select, q to cancel)", "level" => 0, "fold" => false, "raw" => true}
|
3467
|
+
end
|
3468
|
+
@items << {"text" => "="*50, "level" => 0, "fold" => false, "raw" => true}
|
3469
|
+
|
3470
|
+
if user_templates.empty?
|
3471
|
+
@items << {"text" => "No user templates found", "level" => 0, "fold" => false, "raw" => true}
|
3472
|
+
else
|
3473
|
+
user_templates.each_with_index do |template, idx|
|
3474
|
+
desc = template["description"].empty? ? "No description" : template["description"]
|
3475
|
+
created = template["created"].empty? ? "" : " (#{Time.parse(template["created"]).strftime('%Y-%m-%d')})"
|
3476
|
+
@items << {
|
3477
|
+
"text" => "#{idx+1}. #{template["name"]}: #{desc}#{created}",
|
3478
|
+
"level" => 0,
|
3479
|
+
"fold" => false,
|
3480
|
+
"raw" => true,
|
3481
|
+
"template_name" => template["name"],
|
3482
|
+
"template_action" => action
|
3483
|
+
}
|
3484
|
+
end
|
3485
|
+
end
|
3486
|
+
|
3487
|
+
@current = 2 # Start at first template
|
3488
|
+
@offset = 0
|
3489
|
+
|
3490
|
+
selected_template = nil
|
3491
|
+
exit_loop = false
|
3492
|
+
|
3493
|
+
# Template manager loop
|
3494
|
+
while !exit_loop
|
3495
|
+
begin
|
3496
|
+
render_main
|
3497
|
+
footer_text = case action
|
3498
|
+
when :delete
|
3499
|
+
"Delete Template | Enter: delete | q: cancel | j/k: navigate"
|
3500
|
+
else
|
3501
|
+
"User Templates | Enter: select | q: cancel | j/k: navigate"
|
3502
|
+
end
|
3503
|
+
@footer.text = footer_text
|
3504
|
+
@footer.refresh
|
3505
|
+
|
3506
|
+
c = getchr
|
3507
|
+
next if c.nil?
|
3508
|
+
|
3509
|
+
case c
|
3510
|
+
when "q", "ESC", "C-c", "Q"
|
3511
|
+
exit_loop = true
|
3512
|
+
when "j", "DOWN"
|
3513
|
+
@current = [@current + 1, @items.length - 1].min
|
3514
|
+
when "k", "UP"
|
3515
|
+
@current = [@current - 1, 2].max
|
3516
|
+
when "ENTER", "RETURN", "\n", "\r"
|
3517
|
+
if @current >= 2 && @current < @items.length
|
3518
|
+
item = @items[@current]
|
3519
|
+
if item && item.is_a?(Hash) && item["template_name"]
|
3520
|
+
selected_template = item["template_name"]
|
3521
|
+
exit_loop = true
|
3522
|
+
end
|
3523
|
+
end
|
3524
|
+
end
|
3525
|
+
rescue => e
|
3526
|
+
@message = "Error in template manager: #{e.message}"
|
3527
|
+
exit_loop = true
|
3528
|
+
end
|
3529
|
+
end
|
3530
|
+
|
3531
|
+
# Restore original state
|
3532
|
+
@items = original_state[:items]
|
3533
|
+
@current = original_state[:current]
|
3534
|
+
@offset = original_state[:offset]
|
3535
|
+
@filename = original_state[:filename]
|
3536
|
+
@modified = original_state[:modified]
|
3537
|
+
|
3538
|
+
# Process selected template
|
3539
|
+
if selected_template && action == :delete
|
3540
|
+
delete_template(selected_template)
|
3541
|
+
end
|
3542
|
+
|
3543
|
+
selected_template
|
3309
3544
|
end
|
3310
3545
|
|
3311
3546
|
def show_templates
|
@@ -3318,24 +3553,33 @@ class HyperListApp
|
|
3318
3553
|
modified: @modified
|
3319
3554
|
}
|
3320
3555
|
|
3321
|
-
# Create template selection view
|
3556
|
+
# Create template selection view combining built-in and user templates
|
3322
3557
|
template_list = [
|
3323
|
-
["project", "Project Plan - Complete project management template"],
|
3324
|
-
["meeting", "Meeting Agenda - Structure for meeting notes"],
|
3325
|
-
["daily", "Daily Planner - Daily task and schedule template"],
|
3326
|
-
["checklist", "Simple Checklist - Basic checkbox list"],
|
3327
|
-
["brainstorm", "Brainstorming Session - Idea generation template"],
|
3328
|
-
["recipe", "Recipe - Cooking recipe structure"]
|
3558
|
+
["project", "Project Plan - Complete project management template", "built-in"],
|
3559
|
+
["meeting", "Meeting Agenda - Structure for meeting notes", "built-in"],
|
3560
|
+
["daily", "Daily Planner - Daily task and schedule template", "built-in"],
|
3561
|
+
["checklist", "Simple Checklist - Basic checkbox list", "built-in"],
|
3562
|
+
["brainstorm", "Brainstorming Session - Idea generation template", "built-in"],
|
3563
|
+
["recipe", "Recipe - Cooking recipe structure", "built-in"]
|
3329
3564
|
]
|
3330
3565
|
|
3566
|
+
# Add user templates to the list
|
3567
|
+
user_templates = get_user_templates
|
3568
|
+
user_templates.each do |template|
|
3569
|
+
desc = template["description"].empty? ? "User template" : template["description"]
|
3570
|
+
template_list << [template["name"], desc, "user"]
|
3571
|
+
end
|
3572
|
+
|
3331
3573
|
# Build template selection items
|
3332
3574
|
@items = []
|
3333
3575
|
@items << {"text" => "TEMPLATES (press Enter to insert, q to cancel)", "level" => 0, "fold" => false, "raw" => true}
|
3334
3576
|
@items << {"text" => "="*50, "level" => 0, "fold" => false, "raw" => true}
|
3335
3577
|
|
3336
|
-
|
3578
|
+
# Add built-in templates section
|
3579
|
+
@items << {"text" => "BUILT-IN TEMPLATES:", "level" => 0, "fold" => false, "raw" => true}
|
3580
|
+
template_list.select { |t| t[2] == "built-in" }.each_with_index do |(key, desc, type), idx|
|
3337
3581
|
@items << {
|
3338
|
-
"text" => "#{idx+1}. #{key.capitalize}: #{desc}",
|
3582
|
+
"text" => " #{idx+1}. #{key.capitalize}: #{desc}",
|
3339
3583
|
"level" => 0,
|
3340
3584
|
"fold" => false,
|
3341
3585
|
"raw" => true,
|
@@ -3343,6 +3587,21 @@ class HyperListApp
|
|
3343
3587
|
}
|
3344
3588
|
end
|
3345
3589
|
|
3590
|
+
# Add user templates section if any exist
|
3591
|
+
if user_templates.any?
|
3592
|
+
@items << {"text" => "", "level" => 0, "fold" => false, "raw" => true}
|
3593
|
+
@items << {"text" => "USER TEMPLATES:", "level" => 0, "fold" => false, "raw" => true}
|
3594
|
+
template_list.select { |t| t[2] == "user" }.each_with_index do |(key, desc, type), idx|
|
3595
|
+
@items << {
|
3596
|
+
"text" => " #{key}: #{desc}",
|
3597
|
+
"level" => 0,
|
3598
|
+
"fold" => false,
|
3599
|
+
"raw" => true,
|
3600
|
+
"template_key" => key
|
3601
|
+
}
|
3602
|
+
end
|
3603
|
+
end
|
3604
|
+
|
3346
3605
|
@current = 2 # Start at first template
|
3347
3606
|
@offset = 0
|
3348
3607
|
|
@@ -4252,6 +4511,19 @@ class HyperListApp
|
|
4252
4511
|
end
|
4253
4512
|
|
4254
4513
|
def run
|
4514
|
+
# Initialize rcurses explicitly (no longer auto-initialized)
|
4515
|
+
Rcurses.init!
|
4516
|
+
|
4517
|
+
# Flush any buffered input (like the Enter key from running the command)
|
4518
|
+
while IO.select([$stdin], nil, nil, 0)
|
4519
|
+
$stdin.read_nonblock(1024) rescue break
|
4520
|
+
end
|
4521
|
+
|
4522
|
+
# Now that rcurses is initialized, set up the UI properly
|
4523
|
+
Rcurses.clear_screen
|
4524
|
+
Cursor.hide
|
4525
|
+
setup_ui
|
4526
|
+
|
4255
4527
|
render
|
4256
4528
|
|
4257
4529
|
loop do
|
@@ -4260,6 +4532,14 @@ class HyperListApp
|
|
4260
4532
|
|
4261
4533
|
c = getchr
|
4262
4534
|
|
4535
|
+
# Skip nil input (shouldn't happen normally)
|
4536
|
+
next if c.nil?
|
4537
|
+
|
4538
|
+
# Skip newline at the very start (buffered from command execution)
|
4539
|
+
if c == "\n" && @last_key.nil?
|
4540
|
+
next
|
4541
|
+
end
|
4542
|
+
|
4263
4543
|
# Track last key for double-key combinations
|
4264
4544
|
prev_key = @last_key
|
4265
4545
|
@last_key = c
|
@@ -4550,40 +4830,15 @@ class HyperListApp
|
|
4550
4830
|
quit
|
4551
4831
|
ensure
|
4552
4832
|
Cursor.show
|
4553
|
-
|
4833
|
+
# Screen clearing disabled for debugging
|
4834
|
+
# Rcurses.clear_screen
|
4554
4835
|
end
|
4555
4836
|
end
|
4556
4837
|
|
4557
4838
|
# Main
|
4558
|
-
|
4559
|
-
|
4560
|
-
|
4561
|
-
# For Ruby 3.4+, explicitly initialize rcurses if needed
|
4562
|
-
if RUBY_VERSION >= "3.4.0"
|
4563
|
-
begin
|
4564
|
-
Rcurses.init! unless Rcurses.respond_to?(:initialized?) && Rcurses.initialized?
|
4565
|
-
rescue => e
|
4566
|
-
# If initialization fails, try to provide helpful error
|
4567
|
-
puts "Failed to initialize terminal interface: #{e.message}"
|
4568
|
-
puts "Try running with: ruby #{__FILE__} #{ARGV.join(' ')}"
|
4569
|
-
exit 1
|
4570
|
-
end
|
4571
|
-
end
|
4572
|
-
|
4839
|
+
# When installed as a gem executable, this file is loaded (not executed directly)
|
4840
|
+
# so we can't use __FILE__ == $0. Just run unless we already handled help/version.
|
4841
|
+
unless ARGV[0] == '-h' || ARGV[0] == '--help' || ARGV[0] == '-v' || ARGV[0] == '--version'
|
4573
4842
|
app = HyperListApp.new(ARGV[0])
|
4574
|
-
|
4575
|
-
begin
|
4576
|
-
app.run
|
4577
|
-
ensure
|
4578
|
-
# Ensure proper cleanup for Ruby 3.4+
|
4579
|
-
if RUBY_VERSION >= "3.4.0"
|
4580
|
-
begin
|
4581
|
-
Rcurses.done! if defined?(Rcurses.done!)
|
4582
|
-
rescue
|
4583
|
-
# Fallback cleanup
|
4584
|
-
print "\e[?25h" # Show cursor
|
4585
|
-
system("stty sane 2>/dev/null")
|
4586
|
-
end
|
4587
|
-
end
|
4588
|
-
end
|
4843
|
+
app.run
|
4589
4844
|
end
|
data/hyperlist.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |spec|
|
2
2
|
spec.name = "hyperlist"
|
3
|
-
spec.version = "1.
|
3
|
+
spec.version = "1.2.0"
|
4
4
|
spec.authors = ["Geir Isene"]
|
5
5
|
spec.email = ["g@isene.com"]
|
6
6
|
|
@@ -28,7 +28,7 @@ Gem::Specification.new do |spec|
|
|
28
28
|
spec.require_paths = ["."]
|
29
29
|
|
30
30
|
# Runtime dependencies
|
31
|
-
spec.add_runtime_dependency "rcurses", "~> 5.1", ">= 5.1.
|
31
|
+
spec.add_runtime_dependency "rcurses", "~> 5.1", ">= 5.1.6"
|
32
32
|
|
33
33
|
# Development dependencies
|
34
34
|
spec.add_development_dependency "minitest", "~> 5.0"
|
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
|
+
version: 1.2.0
|
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-
|
11
|
+
date: 2025-08-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rcurses
|
@@ -19,7 +19,7 @@ dependencies:
|
|
19
19
|
version: '5.1'
|
20
20
|
- - ">="
|
21
21
|
- !ruby/object:Gem::Version
|
22
|
-
version: 5.1.
|
22
|
+
version: 5.1.6
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -29,7 +29,7 @@ dependencies:
|
|
29
29
|
version: '5.1'
|
30
30
|
- - ">="
|
31
31
|
- !ruby/object:Gem::Version
|
32
|
-
version: 5.1.
|
32
|
+
version: 5.1.6
|
33
33
|
- !ruby/object:Gem::Dependency
|
34
34
|
name: minitest
|
35
35
|
requirement: !ruby/object:Gem::Requirement
|
@@ -73,18 +73,12 @@ files:
|
|
73
73
|
- CHANGELOG.md
|
74
74
|
- LICENSE
|
75
75
|
- README.md
|
76
|
-
- debug_instructions.md
|
77
|
-
- diagnose.rb
|
78
|
-
- diagnose_ruby34.rb
|
79
|
-
- diagnose_safe.rb
|
80
|
-
- fix_terminal.sh
|
81
76
|
- hyperlist
|
82
77
|
- hyperlist.gemspec
|
83
|
-
- hyperlist_logo.svg
|
84
|
-
-
|
78
|
+
- img/hyperlist_logo.svg
|
79
|
+
- img/screenshot_help.png
|
80
|
+
- img/screenshot_sample.png
|
85
81
|
- sample.hl
|
86
|
-
- screenshot_help.png
|
87
|
-
- screenshot_sample.png
|
88
82
|
- test.hl
|
89
83
|
homepage: https://github.com/isene/HyperList
|
90
84
|
licenses:
|
data/debug_instructions.md
DELETED
@@ -1,112 +0,0 @@
|
|
1
|
-
# Debugging HyperList Issues
|
2
|
-
|
3
|
-
## For the user experiencing startup crashes:
|
4
|
-
|
5
|
-
### 1. First, verify you have the latest versions:
|
6
|
-
|
7
|
-
```bash
|
8
|
-
gem list hyperlist
|
9
|
-
# Should show: hyperlist (1.1.3)
|
10
|
-
|
11
|
-
gem list rcurses
|
12
|
-
# Should show: rcurses (5.1.4) or higher
|
13
|
-
```
|
14
|
-
|
15
|
-
### 2. If not, update to the latest:
|
16
|
-
|
17
|
-
```bash
|
18
|
-
gem update hyperlist
|
19
|
-
gem update rcurses
|
20
|
-
```
|
21
|
-
|
22
|
-
### 3. Run with debug mode to see errors:
|
23
|
-
|
24
|
-
```bash
|
25
|
-
# Set debug environment variable
|
26
|
-
export RCURSES_DEBUG=1
|
27
|
-
export DEBUG=1
|
28
|
-
|
29
|
-
# Then run hyperlist
|
30
|
-
hyperlist
|
31
|
-
|
32
|
-
# Or run in one line:
|
33
|
-
DEBUG=1 RCURSES_DEBUG=1 hyperlist
|
34
|
-
```
|
35
|
-
|
36
|
-
### 4. Alternative: Run with Ruby directly to see errors:
|
37
|
-
|
38
|
-
```bash
|
39
|
-
# Find where hyperlist is installed
|
40
|
-
which hyperlist
|
41
|
-
|
42
|
-
# Run it directly with Ruby to see any errors
|
43
|
-
ruby $(which hyperlist)
|
44
|
-
```
|
45
|
-
|
46
|
-
### 5. Check Ruby version compatibility:
|
47
|
-
|
48
|
-
```bash
|
49
|
-
ruby --version
|
50
|
-
# HyperList requires Ruby 3.0.0 or higher
|
51
|
-
```
|
52
|
-
|
53
|
-
### 6. Try running with verbose Ruby output:
|
54
|
-
|
55
|
-
```bash
|
56
|
-
ruby -w $(which hyperlist)
|
57
|
-
```
|
58
|
-
|
59
|
-
### 7. Check for missing dependencies:
|
60
|
-
|
61
|
-
```bash
|
62
|
-
# This will show if rcurses is properly installed
|
63
|
-
ruby -e "require 'rcurses'; puts 'rcurses loaded successfully'"
|
64
|
-
```
|
65
|
-
|
66
|
-
### 8. Create a simple test file to isolate the issue:
|
67
|
-
|
68
|
-
Create a file called `test_hyperlist.rb`:
|
69
|
-
|
70
|
-
```ruby
|
71
|
-
#!/usr/bin/env ruby
|
72
|
-
|
73
|
-
puts "Ruby version: #{RUBY_VERSION}"
|
74
|
-
puts "Testing rcurses..."
|
75
|
-
|
76
|
-
begin
|
77
|
-
require 'rcurses'
|
78
|
-
puts "✓ rcurses loaded successfully (version from gem)"
|
79
|
-
rescue LoadError => e
|
80
|
-
puts "✗ Failed to load rcurses: #{e.message}"
|
81
|
-
exit 1
|
82
|
-
end
|
83
|
-
|
84
|
-
puts "\nTesting basic rcurses functionality..."
|
85
|
-
begin
|
86
|
-
include Rcurses
|
87
|
-
puts "✓ Rcurses module included"
|
88
|
-
puts "✓ All basic checks passed!"
|
89
|
-
rescue => e
|
90
|
-
puts "✗ Error: #{e.message}"
|
91
|
-
exit 1
|
92
|
-
end
|
93
|
-
```
|
94
|
-
|
95
|
-
Run it with:
|
96
|
-
```bash
|
97
|
-
ruby test_hyperlist.rb
|
98
|
-
```
|
99
|
-
|
100
|
-
### 9. If all else fails, capture output:
|
101
|
-
|
102
|
-
```bash
|
103
|
-
# Run with script to capture all output
|
104
|
-
script -c "hyperlist" hyperlist_output.txt
|
105
|
-
|
106
|
-
# Then send us the hyperlist_output.txt file
|
107
|
-
```
|
108
|
-
|
109
|
-
## Notes:
|
110
|
-
- GDB won't work with Ruby scripts (it's for compiled binaries)
|
111
|
-
- The new error handling in rcurses 5.1.4+ should show errors after terminal cleanup
|
112
|
-
- Setting DEBUG=1 or RCURSES_DEBUG=1 will show full stack traces
|
data/diagnose.rb
DELETED
@@ -1,115 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
# HyperList Diagnostic Script
|
3
|
-
# Run this to help diagnose installation/startup issues
|
4
|
-
|
5
|
-
puts "=" * 60
|
6
|
-
puts "HyperList Diagnostic Report"
|
7
|
-
puts "=" * 60
|
8
|
-
|
9
|
-
# Check Ruby version
|
10
|
-
puts "\n1. Ruby Version:"
|
11
|
-
puts " #{RUBY_VERSION} (#{RUBY_PLATFORM})"
|
12
|
-
if RUBY_VERSION < "3.0.0"
|
13
|
-
puts " ⚠️ WARNING: HyperList requires Ruby 3.0.0 or higher"
|
14
|
-
else
|
15
|
-
puts " ✓ Ruby version OK"
|
16
|
-
end
|
17
|
-
|
18
|
-
# Check gem versions
|
19
|
-
puts "\n2. Gem Versions:"
|
20
|
-
begin
|
21
|
-
hyperlist_version = `gem list hyperlist --local`.match(/hyperlist \(([\d.]+)\)/)[1] rescue "not found"
|
22
|
-
rcurses_version = `gem list rcurses --local`.match(/rcurses \(([\d.]+(?:,\s*[\d.]+)*)\)/)[1] rescue "not found"
|
23
|
-
|
24
|
-
puts " hyperlist: #{hyperlist_version}"
|
25
|
-
if hyperlist_version >= "1.1.3"
|
26
|
-
puts " ✓ HyperList version OK"
|
27
|
-
else
|
28
|
-
puts " ⚠️ Please update: gem update hyperlist"
|
29
|
-
end
|
30
|
-
|
31
|
-
puts " rcurses: #{rcurses_version}"
|
32
|
-
if rcurses_version.include?("5.1.4") || rcurses_version >= "5.1.4"
|
33
|
-
puts " ✓ rcurses version OK"
|
34
|
-
else
|
35
|
-
puts " ⚠️ Please update: gem update rcurses"
|
36
|
-
end
|
37
|
-
rescue => e
|
38
|
-
puts " Error checking gems: #{e.message}"
|
39
|
-
end
|
40
|
-
|
41
|
-
# Test loading rcurses
|
42
|
-
puts "\n3. Testing rcurses load:"
|
43
|
-
begin
|
44
|
-
require 'rcurses'
|
45
|
-
puts " ✓ rcurses loaded successfully"
|
46
|
-
|
47
|
-
# Check if we can access rcurses modules
|
48
|
-
include Rcurses
|
49
|
-
puts " ✓ Rcurses modules accessible"
|
50
|
-
rescue LoadError => e
|
51
|
-
puts " ✗ Failed to load rcurses: #{e.message}"
|
52
|
-
puts " Try: gem install rcurses"
|
53
|
-
rescue => e
|
54
|
-
puts " ✗ Error with rcurses: #{e.message}"
|
55
|
-
end
|
56
|
-
|
57
|
-
# Test terminal capabilities
|
58
|
-
puts "\n4. Terminal Check:"
|
59
|
-
puts " TERM: #{ENV['TERM'] || 'not set'}"
|
60
|
-
puts " TTY: #{$stdin.tty? ? 'Yes' : 'No'}"
|
61
|
-
puts " Encoding: #{Encoding.default_external}"
|
62
|
-
|
63
|
-
# Check for HyperList executable
|
64
|
-
puts "\n5. HyperList Installation:"
|
65
|
-
hyperlist_path = `which hyperlist`.strip
|
66
|
-
if hyperlist_path.empty?
|
67
|
-
puts " ✗ hyperlist command not found in PATH"
|
68
|
-
puts " Try: gem install hyperlist"
|
69
|
-
else
|
70
|
-
puts " ✓ Found at: #{hyperlist_path}"
|
71
|
-
|
72
|
-
# Check if it's executable
|
73
|
-
if File.executable?(hyperlist_path)
|
74
|
-
puts " ✓ File is executable"
|
75
|
-
else
|
76
|
-
puts " ⚠️ File is not executable"
|
77
|
-
puts " Try: chmod +x #{hyperlist_path}"
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
# Try to load core dependencies
|
82
|
-
puts "\n6. Core Dependencies:"
|
83
|
-
deps = ['io/console', 'date', 'cgi', 'openssl', 'digest', 'base64']
|
84
|
-
deps.each do |dep|
|
85
|
-
begin
|
86
|
-
require dep
|
87
|
-
puts " ✓ #{dep}"
|
88
|
-
rescue LoadError => e
|
89
|
-
puts " ✗ #{dep}: #{e.message}"
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
# Test creating a basic rcurses pane (without initializing terminal)
|
94
|
-
puts "\n7. Testing Rcurses Pane Creation (simulation):"
|
95
|
-
begin
|
96
|
-
# Don't actually initialize the terminal, just test the class exists
|
97
|
-
if defined?(Rcurses::Pane)
|
98
|
-
puts " ✓ Rcurses::Pane class exists"
|
99
|
-
else
|
100
|
-
puts " ✗ Rcurses::Pane class not found"
|
101
|
-
end
|
102
|
-
rescue => e
|
103
|
-
puts " ✗ Error: #{e.message}"
|
104
|
-
end
|
105
|
-
|
106
|
-
puts "\n" + "=" * 60
|
107
|
-
puts "Diagnostic complete!"
|
108
|
-
puts "=" * 60
|
109
|
-
|
110
|
-
puts "\nIf everything shows ✓ but hyperlist still crashes:"
|
111
|
-
puts "1. Run with debug mode: DEBUG=1 RCURSES_DEBUG=1 hyperlist"
|
112
|
-
puts "2. Check for error log: cat ~/.hyperlist_error.log"
|
113
|
-
puts "3. Try running directly: ruby #{hyperlist_path}"
|
114
|
-
|
115
|
-
puts "\nPlease share this diagnostic output when reporting issues."
|
data/diagnose_ruby34.rb
DELETED
@@ -1,145 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
# Diagnostic script for Ruby 3.4.5 compatibility issues
|
3
|
-
|
4
|
-
puts "Ruby Compatibility Diagnostic for HyperList"
|
5
|
-
puts "=" * 50
|
6
|
-
puts "Ruby version: #{RUBY_VERSION}"
|
7
|
-
puts "Ruby platform: #{RUBY_PLATFORM}"
|
8
|
-
puts
|
9
|
-
|
10
|
-
# Test 1: Basic rcurses functionality
|
11
|
-
puts "Test 1: Basic rcurses require and init..."
|
12
|
-
begin
|
13
|
-
require 'rcurses'
|
14
|
-
puts " ✓ rcurses loaded successfully"
|
15
|
-
puts " Rcurses version: #{Rcurses::VERSION}" if defined?(Rcurses::VERSION)
|
16
|
-
rescue LoadError => e
|
17
|
-
puts " ✗ Failed to load rcurses: #{e.message}"
|
18
|
-
exit 1
|
19
|
-
end
|
20
|
-
|
21
|
-
# Test 2: Rcurses initialization with error capture
|
22
|
-
puts "\nTest 2: Rcurses initialization..."
|
23
|
-
begin
|
24
|
-
# Capture any output during init
|
25
|
-
original_stdout = $stdout
|
26
|
-
original_stderr = $stderr
|
27
|
-
|
28
|
-
# Create StringIO to capture output
|
29
|
-
require 'stringio'
|
30
|
-
captured_out = StringIO.new
|
31
|
-
captured_err = StringIO.new
|
32
|
-
|
33
|
-
$stdout = captured_out
|
34
|
-
$stderr = captured_err
|
35
|
-
|
36
|
-
# Try to initialize
|
37
|
-
Rcurses.init!
|
38
|
-
|
39
|
-
# Restore output
|
40
|
-
$stdout = original_stdout
|
41
|
-
$stderr = original_stderr
|
42
|
-
|
43
|
-
# Check if anything was captured
|
44
|
-
out_content = captured_out.string
|
45
|
-
err_content = captured_err.string
|
46
|
-
|
47
|
-
if !out_content.empty?
|
48
|
-
puts " Captured stdout during init: #{out_content.inspect}"
|
49
|
-
end
|
50
|
-
if !err_content.empty?
|
51
|
-
puts " Captured stderr during init: #{err_content.inspect}"
|
52
|
-
end
|
53
|
-
|
54
|
-
puts " ✓ Rcurses initialized"
|
55
|
-
|
56
|
-
# Test basic functionality
|
57
|
-
puts " Testing basic screen operations..."
|
58
|
-
print "\e[2J\e[H" # Clear screen
|
59
|
-
print "Test"
|
60
|
-
sleep 0.1
|
61
|
-
print "\e[2J\e[H" # Clear again
|
62
|
-
|
63
|
-
puts " ✓ Basic operations work"
|
64
|
-
|
65
|
-
rescue => e
|
66
|
-
puts " ✗ Failed during initialization: #{e.message}"
|
67
|
-
puts " Backtrace:"
|
68
|
-
e.backtrace.first(5).each { |line| puts " #{line}" }
|
69
|
-
ensure
|
70
|
-
# Try to restore terminal
|
71
|
-
begin
|
72
|
-
Rcurses.done! if defined?(Rcurses.done!)
|
73
|
-
rescue
|
74
|
-
# Fallback terminal restore
|
75
|
-
print "\e[?25h" # Show cursor
|
76
|
-
system("stty sane 2>/dev/null")
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
# Test 3: Check for method availability issues in Ruby 3.4
|
81
|
-
puts "\nTest 3: Ruby 3.4 specific checks..."
|
82
|
-
|
83
|
-
# Check IO methods that might have changed
|
84
|
-
if IO.respond_to?(:console)
|
85
|
-
puts " ✓ IO.console available"
|
86
|
-
else
|
87
|
-
puts " ✗ IO.console not available"
|
88
|
-
end
|
89
|
-
|
90
|
-
begin
|
91
|
-
require 'io/console'
|
92
|
-
$stdin.raw { }
|
93
|
-
puts " ✓ IO#raw method works"
|
94
|
-
rescue => e
|
95
|
-
puts " ✗ IO#raw failed: #{e.message}"
|
96
|
-
end
|
97
|
-
|
98
|
-
# Test 4: Check encoding
|
99
|
-
puts "\nTest 4: Encoding checks..."
|
100
|
-
puts " Default external: #{Encoding.default_external}"
|
101
|
-
puts " Default internal: #{Encoding.default_internal}"
|
102
|
-
puts " Console encoding: #{$stdout.external_encoding}" if $stdout.respond_to?(:external_encoding)
|
103
|
-
|
104
|
-
# Test 5: Simple hyperlist initialization test
|
105
|
-
puts "\nTest 5: HyperList class initialization..."
|
106
|
-
begin
|
107
|
-
# Load just the class definition part
|
108
|
-
hyperlist_code = File.read(File.join(File.dirname(__FILE__), 'hyperlist'))
|
109
|
-
|
110
|
-
# Extract just the class without running main
|
111
|
-
class_only = hyperlist_code.split(/^if __FILE__ == \$0/)[0]
|
112
|
-
|
113
|
-
# Try to evaluate it
|
114
|
-
eval(class_only)
|
115
|
-
|
116
|
-
puts " ✓ HyperList class loaded"
|
117
|
-
|
118
|
-
# Try to create instance (without running)
|
119
|
-
app = HyperListApp.new
|
120
|
-
puts " ✓ HyperListApp instance created"
|
121
|
-
|
122
|
-
rescue => e
|
123
|
-
puts " ✗ Failed to load HyperList: #{e.message}"
|
124
|
-
puts " Error at: #{e.backtrace.first}"
|
125
|
-
end
|
126
|
-
|
127
|
-
# Test 6: Terminal capability check
|
128
|
-
puts "\nTest 6: Terminal capabilities..."
|
129
|
-
puts " TERM: #{ENV['TERM']}"
|
130
|
-
puts " Columns: #{`tput cols`.strip}" rescue nil
|
131
|
-
puts " Lines: #{`tput lines`.strip}" rescue nil
|
132
|
-
|
133
|
-
# Test 7: Check for signal handling changes
|
134
|
-
puts "\nTest 7: Signal handling..."
|
135
|
-
begin
|
136
|
-
old_handler = Signal.trap("WINCH") { }
|
137
|
-
Signal.trap("WINCH", old_handler)
|
138
|
-
puts " ✓ SIGWINCH trap works"
|
139
|
-
rescue => e
|
140
|
-
puts " ✗ SIGWINCH trap failed: #{e.message}"
|
141
|
-
end
|
142
|
-
|
143
|
-
puts "\n" + "=" * 50
|
144
|
-
puts "Diagnostic complete!"
|
145
|
-
puts "\nPlease share this output to help identify the Ruby 3.4.5 compatibility issue."
|
data/diagnose_safe.rb
DELETED
@@ -1,198 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
# HyperList Safe Diagnostic Script
|
3
|
-
# This version ensures terminal remains in a sane state
|
4
|
-
|
5
|
-
# First, ensure terminal is in sane state
|
6
|
-
system("stty sane 2>/dev/null")
|
7
|
-
|
8
|
-
# Ensure we're not in raw mode and output is flushed properly
|
9
|
-
$stdout.sync = true
|
10
|
-
$stderr.sync = true
|
11
|
-
|
12
|
-
# Don't load rcurses until we explicitly test it
|
13
|
-
puts "=" * 60
|
14
|
-
puts "HyperList Safe Diagnostic Report"
|
15
|
-
puts "=" * 60
|
16
|
-
|
17
|
-
# Check Ruby version
|
18
|
-
puts "\n1. Ruby Version:"
|
19
|
-
puts " #{RUBY_VERSION} (#{RUBY_PLATFORM})"
|
20
|
-
if RUBY_VERSION < "3.0.0"
|
21
|
-
puts " WARNING: HyperList requires Ruby 3.0.0 or higher"
|
22
|
-
elsif RUBY_VERSION >= "3.4.0"
|
23
|
-
puts " WARNING: Ruby 3.4+ is a development version and may have compatibility issues"
|
24
|
-
puts " RECOMMENDED: Use Ruby 3.3.x for stability"
|
25
|
-
else
|
26
|
-
puts " OK: Ruby version supported"
|
27
|
-
end
|
28
|
-
|
29
|
-
# Check gem versions WITHOUT loading them
|
30
|
-
puts "\n2. Installed Gem Versions:"
|
31
|
-
begin
|
32
|
-
hyperlist_output = `gem list hyperlist --local 2>&1`
|
33
|
-
rcurses_output = `gem list rcurses --local 2>&1`
|
34
|
-
|
35
|
-
if hyperlist_output.include?("hyperlist")
|
36
|
-
version = hyperlist_output.match(/hyperlist \(([\d.]+)/)[1] rescue "unknown"
|
37
|
-
puts " hyperlist: #{version}"
|
38
|
-
if version >= "1.1.3"
|
39
|
-
puts " OK: HyperList version is current"
|
40
|
-
else
|
41
|
-
puts " UPDATE NEEDED: gem update hyperlist"
|
42
|
-
end
|
43
|
-
else
|
44
|
-
puts " hyperlist: NOT INSTALLED"
|
45
|
-
puts " Run: gem install hyperlist"
|
46
|
-
end
|
47
|
-
|
48
|
-
if rcurses_output.include?("rcurses")
|
49
|
-
# Extract just the first/latest version
|
50
|
-
version = rcurses_output.match(/rcurses \(([\d.]+)/)[1] rescue "unknown"
|
51
|
-
puts " rcurses: #{version}"
|
52
|
-
if version >= "5.1.4"
|
53
|
-
puts " OK: rcurses version is current"
|
54
|
-
else
|
55
|
-
puts " UPDATE NEEDED: gem update rcurses"
|
56
|
-
end
|
57
|
-
else
|
58
|
-
puts " rcurses: NOT INSTALLED"
|
59
|
-
puts " Run: gem install rcurses"
|
60
|
-
end
|
61
|
-
rescue => e
|
62
|
-
puts " Error checking gems: #{e.message}"
|
63
|
-
end
|
64
|
-
|
65
|
-
# Check terminal environment
|
66
|
-
puts "\n3. Terminal Environment:"
|
67
|
-
puts " TERM: #{ENV['TERM'] || 'not set'}"
|
68
|
-
puts " LANG: #{ENV['LANG'] || 'not set'}"
|
69
|
-
puts " TTY: #{$stdin.tty? ? 'Yes' : 'No'}"
|
70
|
-
puts " Terminal columns: #{`tput cols`.strip rescue 'unknown'}"
|
71
|
-
puts " Terminal rows: #{`tput lines`.strip rescue 'unknown'}"
|
72
|
-
|
73
|
-
# Check for HyperList executable
|
74
|
-
puts "\n4. HyperList Executable:"
|
75
|
-
hyperlist_path = `which hyperlist 2>/dev/null`.strip
|
76
|
-
if hyperlist_path.empty?
|
77
|
-
puts " NOT FOUND in PATH"
|
78
|
-
|
79
|
-
# Check common gem bin paths
|
80
|
-
gem_paths = [
|
81
|
-
"#{ENV['HOME']}/.local/share/gem/ruby/*/bin/hyperlist",
|
82
|
-
"#{ENV['HOME']}/.gem/ruby/*/bin/hyperlist",
|
83
|
-
"/usr/local/bin/hyperlist",
|
84
|
-
"/usr/bin/hyperlist"
|
85
|
-
]
|
86
|
-
|
87
|
-
found = false
|
88
|
-
gem_paths.each do |pattern|
|
89
|
-
Dir.glob(pattern).each do |path|
|
90
|
-
if File.exist?(path)
|
91
|
-
puts " Found at: #{path}"
|
92
|
-
puts " Add to PATH: export PATH=\"#{File.dirname(path)}:$PATH\""
|
93
|
-
found = true
|
94
|
-
break
|
95
|
-
end
|
96
|
-
end
|
97
|
-
break if found
|
98
|
-
end
|
99
|
-
else
|
100
|
-
puts " Found at: #{hyperlist_path}"
|
101
|
-
if File.executable?(hyperlist_path)
|
102
|
-
puts " OK: File is executable"
|
103
|
-
else
|
104
|
-
puts " ERROR: File is not executable"
|
105
|
-
puts " Fix: chmod +x #{hyperlist_path}"
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
# Test basic dependencies WITHOUT loading rcurses
|
110
|
-
puts "\n5. Core Ruby Dependencies:"
|
111
|
-
deps = ['io/console', 'date', 'cgi', 'openssl', 'digest', 'base64']
|
112
|
-
deps.each do |dep|
|
113
|
-
begin
|
114
|
-
require dep
|
115
|
-
puts " OK: #{dep}"
|
116
|
-
rescue LoadError => e
|
117
|
-
puts " MISSING: #{dep} - #{e.message}"
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
# Separate rcurses test with isolation
|
122
|
-
puts "\n6. Testing rcurses (isolated):"
|
123
|
-
puts " Running isolated test..."
|
124
|
-
|
125
|
-
# Create a separate test script to isolate rcurses
|
126
|
-
test_script = <<~RUBY
|
127
|
-
begin
|
128
|
-
require 'rcurses'
|
129
|
-
puts "RCURSES_LOAD:OK"
|
130
|
-
|
131
|
-
# Check if main classes exist without initializing
|
132
|
-
if defined?(Rcurses::Pane)
|
133
|
-
puts "RCURSES_PANE:OK"
|
134
|
-
else
|
135
|
-
puts "RCURSES_PANE:FAIL"
|
136
|
-
end
|
137
|
-
rescue LoadError => e
|
138
|
-
puts "RCURSES_LOAD:FAIL:\#{e.message}"
|
139
|
-
rescue => e
|
140
|
-
puts "RCURSES_ERROR:\#{e.class}:\#{e.message}"
|
141
|
-
end
|
142
|
-
RUBY
|
143
|
-
|
144
|
-
# Run test in subprocess to avoid terminal corruption
|
145
|
-
result = `ruby -e "#{test_script}" 2>&1`
|
146
|
-
|
147
|
-
if result.include?("RCURSES_LOAD:OK")
|
148
|
-
puts " OK: rcurses loads successfully"
|
149
|
-
else
|
150
|
-
puts " ERROR: rcurses failed to load"
|
151
|
-
error = result.match(/RCURSES_LOAD:FAIL:(.+)/)
|
152
|
-
puts " Details: #{error[1]}" if error
|
153
|
-
end
|
154
|
-
|
155
|
-
if result.include?("RCURSES_PANE:OK")
|
156
|
-
puts " OK: Rcurses::Pane class available"
|
157
|
-
else
|
158
|
-
puts " ERROR: Rcurses::Pane class not found"
|
159
|
-
end
|
160
|
-
|
161
|
-
if result.include?("RCURSES_ERROR")
|
162
|
-
error = result.match(/RCURSES_ERROR:(.+):(.+)/)
|
163
|
-
puts " ERROR: #{error[1]} - #{error[2]}" if error
|
164
|
-
end
|
165
|
-
|
166
|
-
# Test terminal sanity
|
167
|
-
puts "\n7. Terminal State Check:"
|
168
|
-
system("stty -a > /dev/null 2>&1")
|
169
|
-
if $?.success?
|
170
|
-
puts " OK: Terminal responds to stty"
|
171
|
-
else
|
172
|
-
puts " ERROR: Terminal not responding properly"
|
173
|
-
end
|
174
|
-
|
175
|
-
# Try to restore terminal just in case
|
176
|
-
system("stty sane 2>/dev/null")
|
177
|
-
system("tput reset 2>/dev/null")
|
178
|
-
|
179
|
-
puts "\n" + "=" * 60
|
180
|
-
puts "Diagnostic complete!"
|
181
|
-
puts "=" * 60
|
182
|
-
|
183
|
-
puts "\nRECOMMENDATIONS:"
|
184
|
-
if RUBY_VERSION >= "3.4.0"
|
185
|
-
puts "1. IMPORTANT: You're using Ruby #{RUBY_VERSION} (development version)"
|
186
|
-
puts " Install Ruby 3.3.x for stability:"
|
187
|
-
puts " - Arch Linux: sudo pacman -S ruby"
|
188
|
-
puts " - Or use: rbenv install 3.3.4"
|
189
|
-
end
|
190
|
-
|
191
|
-
puts "\nTo test rcurses isolation:"
|
192
|
-
puts " ruby -e \"require 'rcurses'; puts 'Loaded OK'\""
|
193
|
-
|
194
|
-
puts "\nTo restore terminal if corrupted:"
|
195
|
-
puts " stty sane"
|
196
|
-
puts " reset"
|
197
|
-
|
198
|
-
puts "\nPlease share this diagnostic output when reporting issues."
|
data/fix_terminal.sh
DELETED
@@ -1,33 +0,0 @@
|
|
1
|
-
#!/bin/bash
|
2
|
-
# Terminal restoration script for when things go wrong
|
3
|
-
|
4
|
-
echo "Restoring terminal to sane state..."
|
5
|
-
|
6
|
-
# Reset terminal to sane defaults
|
7
|
-
stty sane 2>/dev/null
|
8
|
-
|
9
|
-
# Clear any raw mode settings
|
10
|
-
stty echo 2>/dev/null
|
11
|
-
stty icanon 2>/dev/null
|
12
|
-
stty icrnl 2>/dev/null
|
13
|
-
|
14
|
-
# Reset terminal completely
|
15
|
-
tput reset 2>/dev/null
|
16
|
-
reset 2>/dev/null
|
17
|
-
|
18
|
-
# Clear screen
|
19
|
-
clear
|
20
|
-
|
21
|
-
# Show cursor
|
22
|
-
tput cnorm 2>/dev/null
|
23
|
-
echo -e "\033[?25h" # ANSI escape to show cursor
|
24
|
-
|
25
|
-
echo "Terminal restored!"
|
26
|
-
echo ""
|
27
|
-
echo "If your terminal is still broken, try:"
|
28
|
-
echo " 1. Close and reopen your terminal"
|
29
|
-
echo " 2. Run: reset"
|
30
|
-
echo " 3. Run: stty sane"
|
31
|
-
echo ""
|
32
|
-
echo "To check terminal state:"
|
33
|
-
echo " stty -a"
|
data/hyperlist_ruby34_wrapper.rb
DELETED
@@ -1,57 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
# encoding: utf-8
|
3
|
-
|
4
|
-
# Wrapper for Ruby 3.4+ compatibility
|
5
|
-
# This ensures proper initialization of rcurses
|
6
|
-
|
7
|
-
# Handle help/version before loading libraries
|
8
|
-
if ARGV[0] == '-h' || ARGV[0] == '--help' || ARGV[0] == '-v' || ARGV[0] == '--version'
|
9
|
-
# Pass through to main hyperlist
|
10
|
-
load File.join(File.dirname(__FILE__), 'hyperlist')
|
11
|
-
exit 0
|
12
|
-
end
|
13
|
-
|
14
|
-
# Explicitly initialize rcurses before loading the main app
|
15
|
-
require 'rcurses'
|
16
|
-
|
17
|
-
begin
|
18
|
-
# Initialize rcurses with proper error handling
|
19
|
-
Rcurses.init!
|
20
|
-
|
21
|
-
# Now load and run the main hyperlist app
|
22
|
-
# We need to prevent the main file from running automatically
|
23
|
-
$hyperlist_wrapper_mode = true
|
24
|
-
|
25
|
-
# Load the hyperlist file
|
26
|
-
load File.join(File.dirname(__FILE__), 'hyperlist')
|
27
|
-
|
28
|
-
# Create and run the app
|
29
|
-
app = HyperListApp.new(ARGV[0])
|
30
|
-
app.run
|
31
|
-
|
32
|
-
rescue Interrupt
|
33
|
-
# Handle Ctrl+C gracefully
|
34
|
-
Rcurses.done! if defined?(Rcurses.done!)
|
35
|
-
puts "\nInterrupted"
|
36
|
-
exit 0
|
37
|
-
rescue => e
|
38
|
-
# Ensure terminal is restored on error
|
39
|
-
Rcurses.done! if defined?(Rcurses.done!)
|
40
|
-
|
41
|
-
# Fallback terminal restoration
|
42
|
-
print "\e[?25h" # Show cursor
|
43
|
-
system("stty sane 2>/dev/null")
|
44
|
-
|
45
|
-
puts "Error: #{e.message}"
|
46
|
-
puts "Backtrace:" if ENV['DEBUG']
|
47
|
-
e.backtrace.first(10).each { |line| puts " #{line}" } if ENV['DEBUG']
|
48
|
-
exit 1
|
49
|
-
ensure
|
50
|
-
# Always try to restore terminal
|
51
|
-
begin
|
52
|
-
Rcurses.done! if defined?(Rcurses.done!)
|
53
|
-
rescue
|
54
|
-
print "\e[?25h"
|
55
|
-
system("stty sane 2>/dev/null")
|
56
|
-
end
|
57
|
-
end
|
File without changes
|
File without changes
|
File without changes
|