ruby-shell 3.4.1 → 3.4.3

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 +34 -4
  3. data/bin/rsh +255 -22
  4. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8c171961f69d09b023cc69bc4cb66b615ec861e940e5369c265ccdf053004764
4
- data.tar.gz: ab185ee8de6daecf91a910f417de02916d259dc315d19c84fe64a2dd4f779123
3
+ metadata.gz: aa582c1417712c47e836881c478b375ec93f4def3b7f75b4ad9c486c3bfc36d3
4
+ data.tar.gz: e6c40f3e4eb1277bdd72ec20413a3bee631abb102a818e71d7e18716b665ebf0
5
5
  SHA512:
6
- metadata.gz: 6c8c2343b5cd84bb9508dc6bbe25ce6a7ee7741adc34f77e063628445dc76d28edd5d9774a986066ca46ac551c03dab7290083eaaca59889a525383ca6ff15c0
7
- data.tar.gz: 28c264420c010f966fcfb9cf200ea25b152a3ec2190700132f2a8185a9b34ff1783f786b36afb93e23c8eae3d36a13c68de5ff02d31106d1dd45c31a08cfca2d
6
+ metadata.gz: 2c9adb770a67ec3c7ac67c42bf7a963b2cedd3c7a4aec8f1d0460210f3fb965286ec528df049426598ca1890df2e00cd174ec96d078e93796acde6ff7ff857e1
7
+ data.tar.gz: ec2dc6f60a5daf6394d3fc57ad0a977b7e1c9e2e0b4e231c8967cc20052d007b68f2c3e85f226885d26da4f706ff86b6976827b1455bf35fcbbfa1b59fed0ac6
data/README.md CHANGED
@@ -112,7 +112,7 @@ gp branch=main
112
112
  * **Define Ruby functions as shell commands**: `:defun 'weather(*args) = system("curl -s wttr.in/#{args[0] || \"oslo\"}")'`
113
113
  * **Call like any shell command**: `weather london`
114
114
  * **Full Ruby power**: Access to Ruby stdlib, file operations, JSON parsing, web requests, etc.
115
- * **Function management**: `:defun?` to list, `:defun '-name'` to remove
115
+ * **Function management**: `:defun` to list, `:defun -name` to remove
116
116
  * **Syntax highlighting**: Ruby functions highlighted in bold
117
117
 
118
118
  ## Advanced Shell Features
@@ -138,7 +138,7 @@ Special commands:
138
138
  * `:history` will list the command history, while `:rmhistory` will delete the history
139
139
  * `:jobs` will list background jobs, `:fg [job_id]` brings jobs to foreground, `:bg [job_id]` resumes stopped jobs
140
140
  * `:defun func(args) = code` defines Ruby functions callable as shell commands (persistent!)
141
- * `:defun?` lists all user-defined functions, `:defun -func` removes functions
141
+ * `:defun` lists all user-defined functions, `:defun -func` removes functions
142
142
  * `:stats` shows command execution statistics, `:stats --graph` for visual charts, `:stats --clear` to reset
143
143
  * `:bm name` or `:bookmark name` bookmark current directory, `:bm name path #tags` with tags
144
144
  * `:bm` lists all bookmarks, just type bookmark name to jump (e.g., `work`)
@@ -309,8 +309,8 @@ weather london
309
309
 
310
310
  ### Function Management
311
311
  ```bash
312
- :defun? # List all defined functions
313
- :defun '-myls' # Remove a function
312
+ :defun # List all defined functions
313
+ :defun -myls # Remove a function
314
314
  ```
315
315
 
316
316
  Ruby functions have access to:
@@ -359,6 +359,36 @@ Create safety rules to block, confirm, warn, or log specific command patterns:
359
359
 
360
360
  ---
361
361
 
362
+ ## Environment Variables
363
+
364
+ **Note:** rsh uses `:env` commands for environment management, not the standard `export` syntax.
365
+
366
+ ```bash
367
+ # List all environment variables (shows first 20)
368
+ :env
369
+
370
+ # View specific variable
371
+ :env PATH
372
+
373
+ # Set environment variable
374
+ :env set PATH /opt/local/bin:/usr/bin:/bin
375
+
376
+ # Unset environment variable
377
+ :env unset MY_VAR
378
+
379
+ # Export all variables to shell script
380
+ :env export my_env.sh
381
+ ```
382
+
383
+ **Why not `export`?**
384
+ - rsh uses colon commands (`:cmd`) for shell operations
385
+ - Standard `export VAR=value` syntax spawns a subprocess that doesn't affect parent shell
386
+ - Use `:env set VAR value` instead for persistent environment changes
387
+
388
+ **Tip:** Add `:env set` commands to your `~/.rshrc` for variables you need on every startup.
389
+
390
+ ---
391
+
362
392
  ## Plugin System (v3.2.0+)
363
393
 
364
394
  rsh supports a powerful plugin system for extending functionality. Plugins are Ruby classes placed in `~/.rsh/plugins/` that can:
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.1" # Performance optimizations: 50-60% faster startup, optimized .rshrc reload, persistent cache
11
+ @version = "3.4.3" # Enhanced tab completion: LS_COLORS, visual indicators, smart context, auto-complete ..
12
12
 
13
13
  # MODULES, CLASSES AND EXTENSIONS
14
14
  class String # Add coloring to strings (with escaping for Readline)
@@ -97,6 +97,12 @@ begin # Initialization
97
97
  @c_tabselect = 5 # Color for selected tabcompleted item
98
98
  @c_taboption = 244 # Color for unselected tabcompleted item
99
99
  @c_stamp = 244 # Color for time stamp/command
100
+ # File type colors for tab completion
101
+ @c_dir = 33 # Color for directories (blue)
102
+ @c_exec = 2 # Color for executables (green)
103
+ @c_image = 13 # Color for images (magenta)
104
+ @c_archive = 11 # Color for archives (yellow)
105
+ @c_file = 7 # Color for regular files (white/default)
100
106
  # Prompt
101
107
  @prompt = "rsh > ".c(@c_prompt).b # Very basic prompt if not defined in .rshrc
102
108
  # Hash & array initializations
@@ -153,6 +159,7 @@ begin # Initialization
153
159
  @validation_rules = [] # Custom validation rules
154
160
  @completion_weights = {} # Completion learning weights
155
161
  @completion_learning = true # Enable completion learning (default: on)
162
+ @completion_show_metadata = false # Show file metadata in completions (default: off)
156
163
  @recording = {active: false, name: nil, commands: []} # Command recording state
157
164
  @recordings = {} # Saved recordings
158
165
  @command_cache = {} # Cache for expensive shell command outputs
@@ -599,11 +606,27 @@ def tab(type)
599
606
  if @cmd_completions.key?(last_cmd) && cmd_parts.length == 1
600
607
  type = "cmd_subcommands"
601
608
  @current_cmd = last_cmd
609
+ # If we're completing after a command (not at start of line), show only files
610
+ elsif last_cmd
611
+ type = "files_dirs_only"
602
612
  end
603
613
  end
604
614
  end
605
615
  end
606
616
 
617
+ # Auto-complete . and .. for directory navigation commands
618
+ if type == "dirs_only" && (@tabstr == ".." || @tabstr == ".")
619
+ completed = @tabstr + "/"
620
+ @history[0] = @pretab + completed + @postab
621
+ @pos = @pretab.length + completed.length
622
+ @c_col = @pos0 + @pos
623
+ @c.clear_line
624
+ line_display = cmd_check(@history[0]).to_s
625
+ print @prompt + line_display
626
+ @c.col(@c_col)
627
+ return
628
+ end
629
+
607
630
  while chr != "ENTER"
608
631
  case type
609
632
  when "hist" # Handle history completions ('UP' key)
@@ -663,6 +686,24 @@ def tab(type)
663
686
  fdir = @tabstr + "*"
664
687
  files = Dir.glob(fdir).reject { |f| Dir.exist?(f) }
665
688
  @tabarray = files
689
+ when "files_dirs_only" # Show files and directories, but not commands
690
+ fdir = @tabstr + "*"
691
+ files = Dir.glob(fdir)
692
+ # Only show hidden files if tabstr starts with .
693
+ unless @tabstr.start_with?('.')
694
+ files.reject! { |f| File.basename(f).start_with?('.') }
695
+ end
696
+ files.map! do |e|
697
+ if e =~ /(?<!\\) /
698
+ e = e.sub(/(.*\/|^)(.*)/, '\1\'\2\'') unless e =~ /'/
699
+ end
700
+ Dir.exist?(e) ? e + "/" : e
701
+ end
702
+ # Separate directories and files for better ordering
703
+ dirs = files.select { |f| f.end_with?('/') }
704
+ files_only = files.reject { |f| f.end_with?('/') }
705
+ # Order: directories first, then files
706
+ @tabarray = dirs + files_only
666
707
  when "commands_only" # Only show executable commands
667
708
  ex = @exe.dup
668
709
  ex.prepend(*@nick.keys, *@gnick.keys)
@@ -788,33 +829,91 @@ def tab(type)
788
829
  @newhist0 = @pretab + tabchoice + @postab # Remember now the new value to be given to @history[0]
789
830
  line1 = cmd_check(@pretab).to_s # Syntax highlight before @tabstr
790
831
  line2 = cmd_check(@postab).to_s # Syntax highlight after @tabstr
791
- # Color and underline the current tabchoice on the commandline:
792
- tabline = tabchoice.sub(/(.*)#{@tabstr}(.*)/, '\1'.c(@c_tabselect) + @tabstr.u.c(@c_tabselect) + '\2'.c(@c_tabselect))
832
+ # Color and underline the current tabchoice on the commandline with file type color:
833
+ display_choice = tabchoice.dup
834
+ clean_choice = tabchoice.gsub(/['"]/, '').chomp('/')
835
+ if !tabchoice.end_with?('/') && File.exist?(clean_choice) && File.executable?(clean_choice) && !File.directory?(clean_choice)
836
+ display_choice += '*'
837
+ end
838
+ choice_color = get_file_color(tabchoice)
839
+ # Escape regex special characters in @tabstr for pattern matching
840
+ escaped_tabstr = Regexp.escape(@tabstr)
841
+ tabline = display_choice.sub(/(.*)#{escaped_tabstr}(.*)/, '\1'.c(choice_color) + @tabstr.u.c(choice_color) + '\2'.c(choice_color))
793
842
  print @prompt + line1 + tabline + line2 # Print the commandline
794
843
  @pos = @pretab.length.to_i + tabchoice.length.to_i # Set the position on that commandline
795
844
  @c_col = @pos0 + @pos # The cursor position must include the prompt as well
796
845
  @c.col(@c_col) # Set the cursor position
797
846
  nextline # Then start showing the completion items
798
847
  tabline = @tabarray[i] # Get the next matching tabline
848
+ # Add executable indicator
849
+ display_item = tabline.dup
850
+ clean_item = tabline.gsub(/['"]/, '').chomp('/')
851
+ if !tabline.end_with?('/') && File.exist?(clean_item) && File.executable?(clean_item) && !File.directory?(clean_item)
852
+ display_item += '*'
853
+ end
854
+ # Get file type color, but make selected item bold for distinction
855
+ file_color = get_file_color(tabline)
799
856
  # Can't nest ANSI codes, they must each complete/conclude or they will mess eachother up
800
- if tabline.include?(@tabstr)
801
- tabline1 = tabline.sub(/(.*?)#{@tabstr}.*/, '\1').c(@c_tabselect) # Color the part before the @tabstr
802
- tabline2 = tabline.sub(/.*?#{@tabstr}(.*)/, '\1').c(@c_tabselect) # Color the part after the @tabstr
803
- print " " + tabline1 + @tabstr.c(@c_tabselect).u + tabline2 # Color & underline @tabstr
857
+ escaped_tabstr = Regexp.escape(@tabstr)
858
+ if display_item.include?(@tabstr)
859
+ tabline1 = display_item.sub(/(.*?)#{escaped_tabstr}.*/, '\1').c(file_color).b # Bold + color for selected
860
+ tabline2 = display_item.sub(/.*?#{escaped_tabstr}(.*)/, '\1').c(file_color).b
861
+ print " " + tabline1 + @tabstr.c(file_color).u.b + tabline2 # Bold, color & underline @tabstr
804
862
  else
805
863
  # For fuzzy matches, just show the whole word highlighted
806
- print " " + tabline.c(@c_tabselect)
864
+ print " " + display_item.c(file_color).b
865
+ end
866
+ # Add metadata if enabled
867
+ if @completion_show_metadata && File.exist?(clean_item)
868
+ if File.directory?(clean_item)
869
+ begin
870
+ count = Dir.entries(clean_item).length - 2
871
+ print " [#{count}]".c(244)
872
+ rescue
873
+ end
874
+ else
875
+ size = File.size(clean_item)
876
+ size_str = size < 1024 ? "#{size}B" :
877
+ size < 1024*1024 ? "#{(size/1024.0).round(1)}K" :
878
+ "#{(size/(1024.0*1024)).round(1)}M"
879
+ print " [#{size_str}]".c(244)
880
+ end
807
881
  end
808
882
  else
809
883
  begin
810
884
  tabline = @tabarray[i+x] # Next tabline, and next, etc (usually 4 times here)
811
- if tabline.include?(@tabstr)
812
- tabline1 = tabline.sub(/(.*?)#{@tabstr}.*/, '\1').c(@c_taboption) # Color before @tabstr
813
- tabline2 = tabline.sub(/.*?#{@tabstr}(.*)/, '\1').c(@c_taboption) # Color after @tabstr
814
- print " " + tabline1 + @tabstr.c(@c_taboption).u + tabline2 # Print the whole line
885
+ # Add executable indicator
886
+ display_item = tabline.dup
887
+ clean_item = tabline.gsub(/['"]/, '').chomp('/')
888
+ if !tabline.end_with?('/') && File.exist?(clean_item) && File.executable?(clean_item) && !File.directory?(clean_item)
889
+ display_item += '*'
890
+ end
891
+ # Get file type color for unselected items (no bold)
892
+ file_color = get_file_color(tabline)
893
+ escaped_tabstr = Regexp.escape(@tabstr)
894
+ if display_item.include?(@tabstr)
895
+ tabline1 = display_item.sub(/(.*?)#{escaped_tabstr}.*/, '\1').c(file_color) # Color before @tabstr
896
+ tabline2 = display_item.sub(/.*?#{escaped_tabstr}(.*)/, '\1').c(file_color) # Color after @tabstr
897
+ print " " + tabline1 + @tabstr.c(file_color).u + tabline2 # Print the whole line
815
898
  else
816
899
  # For fuzzy matches, just show the whole word
817
- print " " + tabline.c(@c_taboption)
900
+ print " " + display_item.c(file_color)
901
+ end
902
+ # Add metadata if enabled
903
+ if @completion_show_metadata && File.exist?(clean_item)
904
+ if File.directory?(clean_item)
905
+ begin
906
+ count = Dir.entries(clean_item).length - 2
907
+ print " [#{count}]".c(244)
908
+ rescue
909
+ end
910
+ else
911
+ size = File.size(clean_item)
912
+ size_str = size < 1024 ? "#{size}B" :
913
+ size < 1024*1024 ? "#{(size/1024.0).round(1)}K" :
914
+ "#{(size/(1024.0*1024)).round(1)}M"
915
+ print " [#{size_str}]".c(244)
916
+ end
818
917
  end
819
918
  rescue => e
820
919
  # Log completion errors if debugging enabled
@@ -839,7 +938,7 @@ def tab(type)
839
938
  if @tabstr == ""
840
939
  @history[0] = @pretab + @postab
841
940
  tabend
842
- return
941
+ return
843
942
  end
844
943
  @tabstr.chop!
845
944
  when 'WBACK' # Delete one word to the left (Ctrl-W)
@@ -1032,9 +1131,13 @@ def config(*args) # Configure rsh settings
1032
1131
  @completion_limit = value.to_i
1033
1132
  puts "Completion limit set to #{value}"
1034
1133
  rshrc
1134
+ when 'completion_show_metadata'
1135
+ @completion_show_metadata = %w[on true yes 1].include?(value.to_s.downcase)
1136
+ puts "Completion metadata display #{@completion_show_metadata ? 'enabled' : 'disabled'}"
1137
+ rshrc
1035
1138
  else
1036
1139
  puts "Unknown setting '#{setting}'"
1037
- puts "Available: history_dedup, session_autosave, auto_correct, slow_command_threshold, completion_learning, completion_limit"
1140
+ puts "Available: history_dedup, session_autosave, auto_correct, slow_command_threshold, completion_learning, completion_limit, completion_show_metadata"
1038
1141
  end
1039
1142
  end
1040
1143
  def env(*args) # Environment variable management
@@ -1075,6 +1178,119 @@ def env(*args) # Environment variable management
1075
1178
  end
1076
1179
  end
1077
1180
  end
1181
+ def parse_ls_colors # Parse LS_COLORS into a hash for file type coloring
1182
+ @ls_colors = {}
1183
+
1184
+ # Map ANSI basic color codes (30-37, 90-97) to 256-color equivalents
1185
+ ansi_to_256 = {
1186
+ 30 => 0, # black
1187
+ 31 => 196, # red -> bright red
1188
+ 32 => 2, # green
1189
+ 33 => 11, # yellow -> bright yellow
1190
+ 34 => 33, # blue -> nice blue
1191
+ 35 => 13, # magenta -> nice magenta
1192
+ 36 => 14, # cyan -> bright cyan
1193
+ 37 => 7, # white
1194
+ 90 => 8, # bright black (gray)
1195
+ 91 => 9, # bright red
1196
+ 92 => 10, # bright green
1197
+ 93 => 11, # bright yellow
1198
+ 94 => 12, # bright blue
1199
+ 95 => 13, # bright magenta
1200
+ 96 => 14, # bright cyan
1201
+ 97 => 15 # bright white
1202
+ }
1203
+
1204
+ if ENV['LS_COLORS']
1205
+ ENV['LS_COLORS'].split(':').each do |entry|
1206
+ next if entry.empty?
1207
+ key, value = entry.split('=')
1208
+ next unless key && value
1209
+
1210
+ # LS_COLORS can use multiple formats:
1211
+ # - "38;5;111" or "38;5;111;1" = 256-color format (use color 111 directly)
1212
+ # - "01;34" = ANSI format (bold + basic color 34, needs conversion)
1213
+ # - "34" = simple ANSI basic color (needs conversion)
1214
+
1215
+ if value =~ /38;5;(\d+)/ # 256-color format (check this first!)
1216
+ @ls_colors[key] = $1.to_i
1217
+ elsif value =~ /(\d+);(\d+)/ # ANSI with attributes (e.g., "01;34")
1218
+ ansi_code = $2.to_i
1219
+ @ls_colors[key] = ansi_to_256[ansi_code] || ansi_code
1220
+ elsif value =~ /^(\d+)$/ # Simple ANSI color
1221
+ ansi_code = $1.to_i
1222
+ @ls_colors[key] = ansi_to_256[ansi_code] || ansi_code
1223
+ end
1224
+ end
1225
+ end
1226
+
1227
+ # Always set defaults (even if LS_COLORS isn't available)
1228
+ @ls_colors['di'] ||= 33 # directories = blue
1229
+ @ls_colors['ex'] ||= 2 # executables = green
1230
+ @ls_colors['ln'] ||= 14 # symlinks = cyan
1231
+ @ls_colors['fi'] ||= 7 # regular files = white
1232
+ end
1233
+ def get_file_color(filename) # Get color for a file based on LS_COLORS
1234
+ return 7 unless @ls_colors # Default to white if not initialized
1235
+
1236
+ # Check if it's a directory
1237
+ if filename.end_with?('/')
1238
+ return @ls_colors['di'] || 33
1239
+ end
1240
+
1241
+ # Remove quotes and trailing slash for checking
1242
+ clean_name = filename.gsub(/['"]/, '').chomp('/')
1243
+
1244
+ # Check if file exists and is executable
1245
+ if File.exist?(clean_name) && File.executable?(clean_name) && !File.directory?(clean_name)
1246
+ return @ls_colors['ex'] || 2
1247
+ end
1248
+
1249
+ # Check extension patterns (*.jpg, *.tar, etc.)
1250
+ ext = File.extname(clean_name)
1251
+ if ext && !ext.empty? && @ls_colors["*#{ext}"]
1252
+ return @ls_colors["*#{ext}"]
1253
+ end
1254
+
1255
+ # Default to regular file color (if 0, use 7/white as 0 means "default" in LS_COLORS)
1256
+ file_color = @ls_colors['fi'] || 7
1257
+ file_color = 7 if file_color == 0 # 0 means "reset to default" in LS_COLORS
1258
+ file_color
1259
+ end
1260
+ def format_tab_item(item, show_metadata: false) # Format tab item with color and optional metadata
1261
+ color = get_file_color(item)
1262
+ formatted = item
1263
+
1264
+ # Add executable indicator
1265
+ clean_name = item.gsub(/['"]/, '')
1266
+ if !item.end_with?('/') && File.exist?(clean_name) && File.executable?(clean_name)
1267
+ formatted += '*'
1268
+ end
1269
+
1270
+ # Add metadata if requested
1271
+ if show_metadata && @completion_show_metadata
1272
+ clean_name = clean_name.chomp('/')
1273
+ if File.exist?(clean_name)
1274
+ if File.directory?(clean_name)
1275
+ begin
1276
+ count = Dir.entries(clean_name).length - 2 # Exclude . and ..
1277
+ meta = "[dir, #{count} items]"
1278
+ rescue
1279
+ meta = "[dir]"
1280
+ end
1281
+ else
1282
+ size = File.size(clean_name)
1283
+ size_str = size < 1024 ? "#{size}B" :
1284
+ size < 1024*1024 ? "#{(size/1024.0).round(1)}K" :
1285
+ "#{(size/(1024.0*1024)).round(1)}M"
1286
+ meta = "[#{size_str}]"
1287
+ end
1288
+ formatted = formatted.ljust(30) + " #{meta}".c(244)
1289
+ end
1290
+ end
1291
+
1292
+ formatted.c(color)
1293
+ end
1078
1294
  def cmd_check(str) # Check if each element on the readline matches commands, nicks, paths; color them
1079
1295
  return if str.nil?
1080
1296
 
@@ -1210,10 +1426,13 @@ def help
1210
1426
  col1 << "Shift-TAB History search"
1211
1427
  col1 << ""
1212
1428
  col1 << "CORE COMMANDS:".c(@c_prompt).b
1213
- col1 << ":nick a = b Alias"
1214
- col1 << ":nick gp={{br}} Parametrized"
1429
+ col1 << ":nick a = b Create alias"
1430
+ col1 << ":nick List all"
1431
+ col1 << ":nick -a Delete"
1432
+ col1 << ":defun f()=x Create function"
1433
+ col1 << ":defun List all"
1434
+ col1 << ":defun -f Delete"
1215
1435
  col1 << ":bm name Bookmark"
1216
- col1 << ":defun f()=x Function"
1217
1436
  col1 << ":stats Analytics"
1218
1437
  col1 << ":validate p=a Safety rules"
1219
1438
  col1 << ":calc expr Calculator"
@@ -1415,10 +1634,23 @@ def bg(job_id = nil)
1415
1634
  puts "Job #{job_id} no longer exists"
1416
1635
  end
1417
1636
  end
1418
- def defun(func_def) # Define a Ruby function like: `:defun "myls(*args) = Dir.glob('*').each {|f| puts f}"`
1419
- if func_def.match(/^\s*-/)
1637
+ def defun(func_def = nil) # Define a Ruby function like: `:defun myls(*args) = Dir.glob('*').each {|f| puts f}`
1638
+ if func_def.nil? || func_def.strip.empty?
1639
+ # List all defined functions
1640
+ puts "User-defined Ruby functions:"
1641
+ all_methods = singleton_class.instance_methods(false)
1642
+ excluded = [:defun, :defun?, :execute_conditional, :expand_braces]
1643
+ methods = all_methods - excluded
1644
+ if methods.empty?
1645
+ puts " (none defined)"
1646
+ else
1647
+ methods.each do |method|
1648
+ puts " #{method}"
1649
+ end
1650
+ end
1651
+ elsif func_def.match(/^\s*-/)
1420
1652
  # Remove function
1421
- func_name = func_def.sub(/^\s*-/, '')
1653
+ func_name = func_def.sub(/^\s*-/, '').strip
1422
1654
  if self.respond_to?(func_name)
1423
1655
  singleton_class.remove_method(func_name.to_sym)
1424
1656
  @defuns.delete(func_name)
@@ -2960,11 +3192,12 @@ begin # Load .rshrc and populate @history
2960
3192
  ENV["PATH"] ? ENV["PATH"] += ":" : ENV["PATH"] = ""
2961
3193
  ENV["PATH"] += "/home/#{@user}/bin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
2962
3194
  if @lscolors and File.exist?(@lscolors)
2963
- ls = File.read(@lscolors)
3195
+ ls = File.read(@lscolors)
2964
3196
  ls.sub!(/export.*/, '')
2965
3197
  ls.sub!(/^LS_COLORS=/, 'ENV["LS_COLORS"]=')
2966
3198
  eval(ls)
2967
3199
  end
3200
+ parse_ls_colors # Parse LS_COLORS for tab completion coloring
2968
3201
  @c = Cursor # Initiate @c as Cursor
2969
3202
  @c.save # Get max row & col
2970
3203
  @c.row(8000)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-shell
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.4.1
4
+ version: 3.4.3
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-23 00:00:00.000000000 Z
11
+ date: 2025-10-25 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