ruby-shell 3.4.3 → 3.4.5

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 (4) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +21 -0
  3. data/bin/rsh +100 -36
  4. metadata +6 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: aa582c1417712c47e836881c478b375ec93f4def3b7f75b4ad9c486c3bfc36d3
4
- data.tar.gz: e6c40f3e4eb1277bdd72ec20413a3bee631abb102a818e71d7e18716b665ebf0
3
+ metadata.gz: 1a0c1e45454167bc454071a1419673d2ca195980970208c54b2745870709e024
4
+ data.tar.gz: 4981d0f400409d059e703df8d6daa9eab3be19e6a4e0da3f96de7533aac66c6c
5
5
  SHA512:
6
- metadata.gz: 2c9adb770a67ec3c7ac67c42bf7a963b2cedd3c7a4aec8f1d0460210f3fb965286ec528df049426598ca1890df2e00cd174ec96d078e93796acde6ff7ff857e1
7
- data.tar.gz: ec2dc6f60a5daf6394d3fc57ad0a977b7e1c9e2e0b4e231c8967cc20052d007b68f2c3e85f226885d26da4f706ff86b6976827b1455bf35fcbbfa1b59fed0ac6
6
+ metadata.gz: 6632764744a12eb79fda32cf92677e44e0ded8cab07e9b41cad11cfb911df0f678c63d9f8448390c8556fca89d11bb83a37864050f75c716c9589e05c88d4e67
7
+ data.tar.gz: fe1dee534ac7e91a7ad925ba6845acc49e9ca897763486973589d5f8997a6b78771ae1155f20ef8bf42d982a3fe4f37255a33a8a1499223cec77fa3b7319b935
data/README.md CHANGED
@@ -476,6 +476,27 @@ Also, a special variable for better LS_COLOR setup:
476
476
  ```
477
477
  Point `@lscolors` to a file that sets your LS_COLORS variable. Use [my extended LS_COLORS setup](https://github.com/isene/LS_COLORS) to make this really fancy.
478
478
 
479
+ ### Directory Colors in Prompt
480
+
481
+ **rsh is fully LS_COLORS compliant** - both tab completion and prompt paths use LS_COLORS for consistent theming.
482
+
483
+ You can override directory colors in the prompt using pattern matching (like RTFM's @topmatch):
484
+ ```ruby
485
+ @dir_colors = [
486
+ ["PassionFruit", 171], # Paths containing "PassionFruit" -> magenta
487
+ ["Dualog", 72], # Paths containing "Dualog" -> cyan
488
+ ["/G", 172], # Paths containing "/G" -> orange
489
+ ]
490
+ ```
491
+
492
+ How it works:
493
+ - Array of `[pattern, color]` pairs
494
+ - First matching pattern wins (uses Ruby's `include?` method)
495
+ - If no pattern matches, uses LS_COLORS 'di' value (your configured directory color)
496
+ - Pattern matching is simple substring matching: "/G" matches "/home/user/Main/G/..."
497
+
498
+ This lets you visually distinguish different project directories at a glance in your prompt.
499
+
479
500
  You can add any Ruby code to your .rshrc.
480
501
 
481
502
  # Enter the world of Ruby
data/bin/rsh CHANGED
@@ -8,7 +8,7 @@
8
8
  # Web_site: http://isene.com/
9
9
  # Github: https://github.com/isene/rsh
10
10
  # License: Public domain
11
- @version = "3.4.3" # Enhanced tab completion: LS_COLORS, visual indicators, smart context, auto-complete ..
11
+ @version = "3.4.5" # Dynamic directory colors in prompt via LS_COLORS integration
12
12
 
13
13
  # MODULES, CLASSES AND EXTENSIONS
14
14
  class String # Add coloring to strings (with escaping for Readline)
@@ -1233,14 +1233,19 @@ end
1233
1233
  def get_file_color(filename) # Get color for a file based on LS_COLORS
1234
1234
  return 7 unless @ls_colors # Default to white if not initialized
1235
1235
 
1236
+ # Remove quotes and trailing slash for checking
1237
+ clean_name = filename.gsub(/['"]/, '').chomp('/')
1238
+
1239
+ # Check if it's a symlink (before directory check!)
1240
+ if File.symlink?(clean_name)
1241
+ return @ls_colors['ln'] || 14 # Symlinks get special color
1242
+ end
1243
+
1236
1244
  # Check if it's a directory
1237
1245
  if filename.end_with?('/')
1238
1246
  return @ls_colors['di'] || 33
1239
1247
  end
1240
1248
 
1241
- # Remove quotes and trailing slash for checking
1242
- clean_name = filename.gsub(/['"]/, '').chomp('/')
1243
-
1244
1249
  # Check if file exists and is executable
1245
1250
  if File.exist?(clean_name) && File.executable?(clean_name) && !File.directory?(clean_name)
1246
1251
  return @ls_colors['ex'] || 2
@@ -1257,6 +1262,18 @@ def get_file_color(filename) # Get color for a file based on LS_COLORS
1257
1262
  file_color = 7 if file_color == 0 # 0 means "reset to default" in LS_COLORS
1258
1263
  file_color
1259
1264
  end
1265
+ def get_dir_color(path) # Get color for directory path in prompt
1266
+ # Check pattern matches first (like RTFM's @topmatch)
1267
+ # Set @dir_colors in .rshrc as array of [pattern, color] pairs
1268
+ # Example: @dir_colors = [["PassionFruit", 171], ["Dualog", 72], ["/G", 172], ["", 33]]
1269
+ if @dir_colors && @dir_colors.is_a?(Array)
1270
+ match = @dir_colors.find { |pattern, _| pattern.empty? || path.include?(pattern) }
1271
+ return match.last if match
1272
+ end
1273
+
1274
+ # Fall back to LS_COLORS directory color
1275
+ @ls_colors['di'] || 33
1276
+ end
1260
1277
  def format_tab_item(item, show_metadata: false) # Format tab item with color and optional metadata
1261
1278
  color = get_file_color(item)
1262
1279
  formatted = item
@@ -1330,7 +1347,12 @@ def cmd_check(str) # Check if each element on the readline matches commands, nic
1330
1347
  # Color bookmarks (after commands and nicks)
1331
1348
  el.c(@c_bookmark)
1332
1349
  elsif File.exist?(clean_el)
1333
- el.c(@c_path)
1350
+ # Use directory color matching for directories, @c_path for files
1351
+ if File.directory?(clean_el)
1352
+ el.c(get_dir_color(File.expand_path(clean_el)))
1353
+ else
1354
+ el.c(@c_path)
1355
+ end
1334
1356
  elsif el[0] == "-"
1335
1357
  el.c(@c_switch)
1336
1358
  else
@@ -1338,21 +1360,19 @@ def cmd_check(str) # Check if each element on the readline matches commands, nic
1338
1360
  end
1339
1361
  end
1340
1362
  end
1341
- def rshrc # Write updates to .rshrc
1342
- hist_clean
1363
+ def rshrc # Write user configuration to .rshrc (portable between machines)
1364
+ hist_clean # Clean history before saving
1343
1365
  if File.exist?(Dir.home+'/.rshrc')
1344
1366
  conf = File.read(Dir.home+'/.rshrc')
1345
1367
  else
1346
1368
  conf = ""
1347
1369
  end
1370
+
1371
+ # Only update user-editable items in .rshrc
1348
1372
  conf.sub!(/^@nick.*(\n|$)/, "")
1349
1373
  conf += "@nick = #{@nick}\n"
1350
1374
  conf.sub!(/^@gnick.*(\n|$)/, "")
1351
1375
  conf += "@gnick = #{@gnick}\n"
1352
- conf.sub!(/^@cmd_frequency.*(\n|$)/, "")
1353
- conf += "@cmd_frequency = #{@cmd_frequency}\n"
1354
- conf.sub!(/^@cmd_stats.*(\n|$)/, "")
1355
- conf += "@cmd_stats = #{@cmd_stats}\n" unless @cmd_stats.empty?
1356
1376
  conf.sub!(/^@bookmarks.*(\n|$)/, "")
1357
1377
  conf += "@bookmarks = #{@bookmarks}\n" unless @bookmarks.empty?
1358
1378
  conf.sub!(/^@defuns.*(\n|$)/, "")
@@ -1365,40 +1385,71 @@ def rshrc # Write updates to .rshrc
1365
1385
  conf += "@auto_correct = #{@auto_correct}\n" if @auto_correct
1366
1386
  conf.sub!(/^@slow_command_threshold.*(\n|$)/, "")
1367
1387
  conf += "@slow_command_threshold = #{@slow_command_threshold}\n" if @slow_command_threshold && @slow_command_threshold > 0
1388
+ conf.sub!(/^@completion_learning.*(\n|$)/, "")
1389
+ conf += "@completion_learning = #{@completion_learning}\n" unless @completion_learning
1390
+ conf.sub!(/^@completion_show_metadata.*(\n|$)/, "")
1391
+ conf += "@completion_show_metadata = #{@completion_show_metadata}\n" if @completion_show_metadata
1368
1392
  conf.sub!(/^@plugin_disabled.*(\n|$)/, "")
1369
1393
  conf += "@plugin_disabled = #{@plugin_disabled}\n" unless @plugin_disabled.empty?
1370
1394
  conf.sub!(/^@validation_rules.*(\n|$)/, "")
1371
1395
  conf += "@validation_rules = #{@validation_rules}\n" unless @validation_rules.empty?
1372
- conf.sub!(/^@completion_weights.*(\n|$)/, "")
1373
- conf += "@completion_weights = #{@completion_weights}\n" unless @completion_weights.empty?
1374
- conf.sub!(/^@completion_learning.*(\n|$)/, "")
1375
- conf += "@completion_learning = #{@completion_learning}\n" unless @completion_learning
1376
- conf.sub!(/^@recordings.*(\n|$)/, "")
1377
- conf += "@recordings = #{@recordings}\n" unless @recordings.empty?
1396
+
1397
+ File.write(Dir.home+'/.rshrc', conf)
1398
+ rshstate # Also save runtime state
1399
+ end
1400
+ def rshstate # Write runtime state to .rshstate (auto-managed, machine-specific)
1401
+ state = ""
1402
+
1403
+ # Runtime data that changes frequently
1404
+ state += "@cmd_frequency = #{@cmd_frequency}\n" unless @cmd_frequency.empty?
1405
+ state += "@cmd_stats = #{@cmd_stats}\n" unless @cmd_stats.empty?
1406
+ state += "@completion_weights = #{@completion_weights}\n" unless @completion_weights.empty?
1407
+ state += "@recordings = #{@recordings}\n" unless @recordings.empty?
1408
+
1378
1409
  # Persist executable cache for faster startup
1379
1410
  if @exe && @exe.length > 100
1380
- conf.sub!(/^@exe_cache.*(\n|$)/, "")
1381
- conf += "@exe_cache = #{@exe.inspect}\n"
1382
- conf.sub!(/^@exe_cache_path.*(\n|$)/, "")
1383
- conf += "@exe_cache_path = #{ENV['PATH'].inspect}\n"
1384
- conf.sub!(/^@exe_cache_time.*(\n|$)/, "")
1385
- conf += "@exe_cache_time = #{Time.now.to_i}\n"
1386
- end
1387
- # Only write @cmd_completions if user has customized it
1388
- unless conf =~ /^@cmd_completions\s*=/
1389
- # Don't write default completions to avoid cluttering .rshrc
1390
- end
1391
- conf.sub!(/^@history.*(\n|$)/, "")
1411
+ state += "@exe_cache = #{@exe.inspect}\n"
1412
+ state += "@exe_cache_path = #{ENV['PATH'].inspect}\n"
1413
+ state += "@exe_cache_time = #{Time.now.to_i}\n"
1414
+ end
1415
+
1392
1416
  # Ensure history is properly formatted as valid Ruby array
1393
1417
  begin
1394
1418
  history_str = @history.last(@histsize).inspect
1395
- conf += "@history = #{history_str}\n"
1419
+ state += "@history = #{history_str}\n"
1396
1420
  rescue => e
1397
- conf += "@history = []\n"
1398
- puts "Warning: Error saving history: #{e.message}"
1421
+ state += "@history = []\n"
1422
+ puts "Warning: Error saving history: #{e.message}" if ENV['RSH_DEBUG']
1399
1423
  end
1424
+
1425
+ File.write(Dir.home+'/.rshstate', state)
1426
+ end
1427
+ def migrate_to_split_config # Migrate from old single .rshrc to split .rshrc + .rshstate
1428
+ return if File.exist?(Dir.home+'/.rshstate') # Already migrated
1429
+ return unless File.exist?(Dir.home+'/.rshrc') # Nothing to migrate
1430
+
1431
+ puts "\nMigrating to split configuration (.rshrc + .rshstate)..."
1432
+
1433
+ # Runtime data will already be loaded from .rshrc by load_rshrc_safe
1434
+ # Just need to save it to .rshstate and clean .rshrc
1435
+
1436
+ # Create .rshstate with current runtime data
1437
+ rshstate
1438
+
1439
+ # Clean runtime data from .rshrc
1440
+ conf = File.read(Dir.home+'/.rshrc')
1441
+ conf.sub!(/^@cmd_frequency.*(\n|$)/, "")
1442
+ conf.sub!(/^@cmd_stats.*(\n|$)/, "")
1443
+ conf.sub!(/^@exe_cache.*(\n|$)/, "")
1444
+ conf.sub!(/^@exe_cache_path.*(\n|$)/, "")
1445
+ conf.sub!(/^@exe_cache_time.*(\n|$)/, "")
1446
+ conf.sub!(/^@completion_weights.*(\n|$)/, "")
1447
+ conf.sub!(/^@history =.*(\n|$)/, "")
1400
1448
  File.write(Dir.home+'/.rshrc', conf)
1401
- puts ".rshrc updated"
1449
+
1450
+ puts "Migration complete!"
1451
+ puts " .rshrc -> User config (portable)"
1452
+ puts " .rshstate -> Runtime data (auto-managed)\n"
1402
1453
  end
1403
1454
 
1404
1455
  # RSH FUNCTIONS
@@ -2973,6 +3024,15 @@ def load_rshrc_safe
2973
3024
  end
2974
3025
  end
2975
3026
 
3027
+ # Load runtime state from .rshstate (separate file)
3028
+ if File.exist?(Dir.home+'/.rshstate')
3029
+ begin
3030
+ load(Dir.home+'/.rshstate')
3031
+ rescue => e
3032
+ puts "Warning: Could not load .rshstate: #{e.message}" if ENV['RSH_DEBUG']
3033
+ end
3034
+ end
3035
+
2976
3036
  rescue SyntaxError => e
2977
3037
  puts "\n\033[31mERROR: Syntax error in .rshrc:\033[0m"
2978
3038
  puts e.message
@@ -3168,7 +3228,10 @@ begin # Load .rshrc and populate @history
3168
3228
  exit
3169
3229
  end
3170
3230
  firstrun unless File.exist?(Dir.home+'/.rshrc') # Initial loading - to get history
3231
+ # Initialize @ls_colors with defaults so get_dir_color() works in .rshrc prompt
3232
+ @ls_colors = { 'di' => 33, 'ex' => 2, 'ln' => 14, 'fi' => 7 }
3171
3233
  load_rshrc_safe
3234
+ migrate_to_split_config # Migrate from old format if needed (v3.4.3+)
3172
3235
  # Load login shell files if rsh is running as login shell
3173
3236
  if ENV['LOGIN_SHELL'] or $0 == "-rsh" or ARGV.include?('-l') or ARGV.include?('--login')
3174
3237
  ['/etc/profile', Dir.home+'/.profile', Dir.home+'/.bash_profile', Dir.home+'/.bashrc'].each do |f|
@@ -3191,6 +3254,7 @@ begin # Load .rshrc and populate @history
3191
3254
  ENV["TERM"] = "rxvt-unicode-256color"
3192
3255
  ENV["PATH"] ? ENV["PATH"] += ":" : ENV["PATH"] = ""
3193
3256
  ENV["PATH"] += "/home/#{@user}/bin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
3257
+ # Load actual LS_COLORS from file (now that @lscolors is set from .rshrc)
3194
3258
  if @lscolors and File.exist?(@lscolors)
3195
3259
  ls = File.read(@lscolors)
3196
3260
  ls.sub!(/export.*/, '')
@@ -3212,8 +3276,8 @@ end
3212
3276
  # MAIN PART
3213
3277
  loop do
3214
3278
  begin
3215
- @user = Etc.getpwuid(Process.euid).name # For use in @prompt
3216
- @node = Etc.uname[:nodename] # For use in @prompt
3279
+ @user ||= Etc.getpwuid(Process.euid).name # Cached for performance
3280
+ @node ||= Etc.uname[:nodename] # Cached for performance
3217
3281
  # Only reload .rshrc if directory changed (optimization)
3218
3282
  current_dir = Dir.pwd
3219
3283
  if @last_prompt_dir != current_dir
@@ -3221,7 +3285,7 @@ loop do
3221
3285
  @last_prompt_dir = current_dir
3222
3286
  end
3223
3287
  @prompt.gsub!(/#{Dir.home}/, '~') # Simplify path in prompt
3224
- system("printf \"\033]0;rsh: #{Dir.pwd}\007\"") # Set Window title to path
3288
+ print "\033]0;rsh: #{current_dir}\007" # Set window title (no spawn)
3225
3289
  @history[0] = "" unless @history[0]
3226
3290
  cache_executables # Use cached executable lookup
3227
3291
  # Load plugins on first command (lazy loading)
metadata CHANGED
@@ -1,21 +1,21 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-shell
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.4.3
4
+ version: 3.4.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Geir Isene
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-10-25 00:00:00.000000000 Z
11
+ date: 2025-10-26 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: 'A shell written in Ruby with extensive tab completions, aliases/nicks,
14
14
  history, syntax highlighting, theming, auto-cd, auto-opening files and more. UPDATE
15
- v3.4.0: COMPLETION LEARNING - Shell learns which TAB completions you use most and
16
- intelligently ranks them higher. Context-aware learning per command. :completion_stats
17
- shows patterns. Persistent across sessions. Plus all v3.3 features: quote-less syntax,
18
- parametrized nicks, Ctrl-G editing, validation rules, shell scripts!'
15
+ v3.4.5: FULL LS_COLORS COMPLIANCE - Prompt and command line now use LS_COLORS with
16
+ pattern-based directory coloring. Configure @dir_colors like RTFM''s @topmatch for
17
+ visual project distinction. Plus v3.4.0: Completion learning, context-aware ranking,
18
+ persistent patterns across sessions!'
19
19
  email: g@isene.com
20
20
  executables:
21
21
  - rsh