hyperlist 1.2.0 → 1.2.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.
Files changed (5) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +17 -0
  3. data/hyperlist +72 -14
  4. data/hyperlist.gemspec +1 -1
  5. metadata +1 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: aef5338683dfa697e59042f093e0db9a748ef53515952a295b1c9eb972519ac5
4
- data.tar.gz: fbad5a0f6022d40cfd147846d3de81b317b41fff39036c9085a0230fc0a144c4
3
+ metadata.gz: e1c9c82471f26ff3363e0d2f801b674798a0ed546f2677c78cb7a72c16e204ba
4
+ data.tar.gz: e92235369181f6a47ceeba5b01feb6815d4a747df38726a8dc3dcd9f3079b009
5
5
  SHA512:
6
- metadata.gz: fd23aaaaa0ffbb7b1d73fdc99a46d3fb08d265000e1e10651e747857a4ab5d78dbf523d967e87d4ca82a1f0f8ff46d3fc563cec4441c3a86de7a3651f0cb41e6
7
- data.tar.gz: 98ae50b53b8a9b4578ed50c81b8dcd763af2273f44bca200f27627cdc808f61b620baa0d76c09a9a776107de3de637e50c1daf660c7c77903debb8ee1868909d
6
+ metadata.gz: b8c282ad98e05174eb963429a36eca1a430b75f2be77d04bd07bb0ed7abf5b68a372c4b84697ae69bcc7f25f4236763ed72909983b9bb8819ec331d3518050bf
7
+ data.tar.gz: e8ad2e4f881b4082dfe593df2cd23c4ee7a54a9f277b143d013112b0f5c79386a8581812453ce700959a642c689fd2c057e9739f5f3e9578b95ff743a0bb058e
data/CHANGELOG.md CHANGED
@@ -2,6 +2,23 @@
2
2
 
3
3
  All notable changes to the HyperList Ruby TUI will be documented in this file.
4
4
 
5
+ ## [1.2.2] - 2025-08-20
6
+
7
+ ### Fixed
8
+ - Fixed encoding compatibility error when decrypting files (UTF-8 vs ASCII-8BIT)
9
+ - Force UTF-8 encoding on decrypted content and text processing
10
+
11
+ ### Added
12
+ - Auto-fold encrypted files on open for privacy (fold level 0)
13
+ - Display "folded for privacy" message when opening encrypted files
14
+
15
+ ## [1.2.1] - 2025-08-20
16
+
17
+ ### Fixed
18
+ - Fixed crash when opening encrypted dot files (footer not initialized)
19
+ - Added password confirmation when encrypting files for the first time
20
+ - Improved initialization order to ensure UI components are ready before file loading
21
+
5
22
  ## [1.2.0] - 2025-08-20
6
23
 
7
24
  ### Added
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.2.0 - Terminal User Interface for HyperList files
10
+ HyperList v1.2.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.2.0"
55
+ puts "HyperList v1.2.2"
56
56
  exit 0
57
57
  end
58
58
 
@@ -72,7 +72,7 @@ class HyperListApp
72
72
  include Rcurses::Input
73
73
  include Rcurses::Cursor
74
74
 
75
- VERSION = "1.2.0"
75
+ VERSION = "1.2.2"
76
76
 
77
77
  def initialize(filename = nil)
78
78
  @filename = filename ? File.expand_path(filename) : nil
@@ -128,15 +128,16 @@ class HyperListApp
128
128
  # Debug: uncomment to see terminal size
129
129
  # puts "Terminal size: #{@rows}x#{@cols}"
130
130
 
131
- # Load file if provided
131
+ # Setup UI first (to initialize @footer) before loading file
132
+ setup_ui
133
+
134
+ # Load file if provided (after UI is set up)
132
135
  if @filename && File.exist?(@filename)
133
136
  load_file(@filename)
134
137
  else
135
138
  # Start with empty list
136
139
  @items = [{"text" => "New HyperList", "level" => 0, "fold" => false}]
137
140
  end
138
-
139
- setup_ui
140
141
  end
141
142
 
142
143
  def setup_ui
@@ -197,6 +198,7 @@ class HyperListApp
197
198
  @redo_position = []
198
199
 
199
200
  # Check if file is encrypted (dot file or encrypted content)
201
+ is_encrypted = false
200
202
  if is_encrypted_file?(file)
201
203
  if content.start_with?("ENC:")
202
204
  # Whole file is encrypted
@@ -207,7 +209,8 @@ class HyperListApp
207
209
  return
208
210
  end
209
211
  lines = decrypted_content.split("\n")
210
- @message = "File decrypted successfully"
212
+ @message = "File decrypted successfully (folded for privacy)"
213
+ is_encrypted = true
211
214
  else
212
215
  # Dot file but not encrypted yet - just load normally
213
216
  lines = content.split("\n")
@@ -247,6 +250,17 @@ class HyperListApp
247
250
 
248
251
  @items = [{"text" => "Empty file", "level" => 0, "fold" => false}] if @items.empty?
249
252
 
253
+ # Auto-fold for privacy/security on encrypted files
254
+ if is_encrypted
255
+ @fold_level = 0 # Set fold level to 0 (everything folded)
256
+ # Fold all items that have children
257
+ @items.each_with_index do |item, idx|
258
+ if has_children?(idx, @items)
259
+ item["fold"] = true
260
+ end
261
+ end
262
+ end
263
+
250
264
  # Auto-fold deep levels for large files
251
265
  if large_file
252
266
  auto_fold_deep_levels(3) # Auto-fold everything deeper than level 3
@@ -845,6 +859,9 @@ class HyperListApp
845
859
 
846
860
  # Helper method to safely apply regexes without corrupting ANSI sequences
847
861
  def safe_regex_replace(text, pattern, &block)
862
+ # Ensure text is UTF-8 encoded
863
+ text = text.to_s.force_encoding('UTF-8')
864
+
848
865
  # Find all ANSI sequences and replace with placeholders
849
866
  ansi_sequences = []
850
867
  placeholder_text = text.gsub(/\e\[[0-9;]*m/) do |match|
@@ -3107,8 +3124,24 @@ class HyperListApp
3107
3124
  end
3108
3125
 
3109
3126
  def encrypt_string(text, password = nil)
3110
- password ||= @encryption_key || prompt_password("Enter encryption password: ")
3111
- return nil unless password
3127
+ if password.nil? && @encryption_key.nil?
3128
+ # First time encrypting - ask for password twice
3129
+ password = prompt_password("Enter encryption password: ")
3130
+ return nil unless password
3131
+
3132
+ confirm = prompt_password("Confirm encryption password: ")
3133
+ return nil unless confirm
3134
+
3135
+ if password != confirm
3136
+ @message = "Passwords do not match - encryption cancelled"
3137
+ return nil
3138
+ end
3139
+
3140
+ @encryption_key = password
3141
+ else
3142
+ password ||= @encryption_key || prompt_password("Enter encryption password: ")
3143
+ return nil unless password
3144
+ end
3112
3145
 
3113
3146
  # Store key for session if not already stored
3114
3147
  @encryption_key ||= password
@@ -3151,7 +3184,10 @@ class HyperListApp
3151
3184
  cipher.key = key
3152
3185
  cipher.iv = iv
3153
3186
 
3154
- cipher.update(encrypted) + cipher.final
3187
+ decrypted = cipher.update(encrypted) + cipher.final
3188
+ # Force UTF-8 encoding on decrypted content
3189
+ decrypted.force_encoding('UTF-8')
3190
+ decrypted
3155
3191
  rescue => e
3156
3192
  @message = "Decryption failed. Wrong password?"
3157
3193
  nil
@@ -3174,8 +3210,24 @@ class HyperListApp
3174
3210
  end
3175
3211
 
3176
3212
  def encrypt_file(content, password = nil)
3177
- password ||= @encryption_key || prompt_password("Enter file encryption password: ")
3178
- return nil unless password
3213
+ if password.nil? && @encryption_key.nil?
3214
+ # First time encrypting - ask for password twice
3215
+ password = prompt_password("Enter encryption password: ")
3216
+ return nil unless password
3217
+
3218
+ confirm = prompt_password("Confirm encryption password: ")
3219
+ return nil unless confirm
3220
+
3221
+ if password != confirm
3222
+ @message = "Passwords do not match - encryption cancelled"
3223
+ return nil
3224
+ end
3225
+
3226
+ @encryption_key = password
3227
+ else
3228
+ password ||= @encryption_key || prompt_password("Enter file encryption password: ")
3229
+ return nil unless password
3230
+ end
3179
3231
 
3180
3232
  encrypt_string(content, password)
3181
3233
  end
@@ -3184,6 +3236,9 @@ class HyperListApp
3184
3236
  password ||= @encryption_key || prompt_password("Enter file decryption password: ")
3185
3237
  return nil unless password
3186
3238
 
3239
+ # Store the key for the session so line encryption can use it
3240
+ @encryption_key = password
3241
+
3187
3242
  decrypt_string(encrypted_content, password)
3188
3243
  end
3189
3244
 
@@ -3208,13 +3263,16 @@ class HyperListApp
3208
3263
  end
3209
3264
  else
3210
3265
  # Encrypt the line
3211
- encrypted = encrypt_string(current_text)
3266
+ # Use the existing encryption key if available (from file decryption)
3267
+ encrypted = encrypt_string(current_text, @encryption_key)
3212
3268
  if encrypted
3213
3269
  save_undo_state
3214
3270
  item["text"] = encrypted
3215
3271
  @encrypted_lines[@current] = true
3216
3272
  @modified = true
3217
- @message = "Line encrypted"
3273
+ @message = "Line encrypted (🔒 indicator shown)"
3274
+ # Clear the processed cache to force re-rendering
3275
+ @processed_cache = {}
3218
3276
  else
3219
3277
  @message = "Encryption cancelled"
3220
3278
  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.2.0"
3
+ spec.version = "1.2.2"
4
4
  spec.authors = ["Geir Isene"]
5
5
  spec.email = ["g@isene.com"]
6
6
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hyperlist
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 1.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Geir Isene