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.
- checksums.yaml +4 -4
- data/README.md +21 -0
- data/bin/rsh +100 -36
- metadata +6 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1a0c1e45454167bc454071a1419673d2ca195980970208c54b2745870709e024
|
|
4
|
+
data.tar.gz: 4981d0f400409d059e703df8d6daa9eab3be19e6a4e0da3f96de7533aac66c6c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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.
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
1373
|
-
conf
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
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
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
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
|
-
|
|
1419
|
+
state += "@history = #{history_str}\n"
|
|
1396
1420
|
rescue => e
|
|
1397
|
-
|
|
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
|
-
|
|
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
|
|
3216
|
-
@node
|
|
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
|
-
|
|
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.
|
|
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-
|
|
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.
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
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
|