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.
- checksums.yaml +4 -4
- data/README.md +34 -4
- data/bin/rsh +255 -22
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: aa582c1417712c47e836881c478b375ec93f4def3b7f75b4ad9c486c3bfc36d3
|
|
4
|
+
data.tar.gz: e6c40f3e4eb1277bdd72ec20413a3bee631abb102a818e71d7e18716b665ebf0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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
|
|
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
|
|
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
|
|
313
|
-
:defun
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
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 " " +
|
|
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
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
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 " " +
|
|
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
|
|
1214
|
-
col1 << ":nick
|
|
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
|
|
1419
|
-
if func_def.
|
|
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.
|
|
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-
|
|
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
|