ruby-shell 2.9.0 → 2.10.0
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/bin/rsh +157 -19
- 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: 5f20098ee7a4e00745916fb1830834273a00dbc5e92bea6b5f1cbd0f66b48639
|
4
|
+
data.tar.gz: 135135d2f788b75eb9e51cebd3dd3d680c4f07717819bf6fc9232bf8b4a32943
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c3494e59f58963262f8142850dbda9a76c50e6367a681389cd921a8db1bc47d2e68a6490799696c8b8e3437234934070364194f3aa81568a1f8bfdcfc61d9c0d
|
7
|
+
data.tar.gz: 8586e7cda13c597863e1d93cb978f0e5815b554a177b6977e41e0f2bc0f1d5a6017e0c04dbf32e45369a2a16180eface4bd67831f8be74b6dc7129f5664e63ed
|
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 = "2.9.
|
11
|
+
@version = "2.9.1" # Bug fix: Improved command coloring for local executables and after ENTER
|
12
12
|
|
13
13
|
# MODULES, CLASSES AND EXTENSIONS
|
14
14
|
class String # Add coloring to strings (with escaping for Readline)
|
@@ -32,15 +32,20 @@ module Cursor # Terminal cursor movement ANSI codes (thanks to https://github.co
|
|
32
32
|
end
|
33
33
|
def pos # Query cursor current position
|
34
34
|
res = ''
|
35
|
-
|
36
|
-
$
|
37
|
-
|
38
|
-
|
39
|
-
|
35
|
+
begin
|
36
|
+
$stdin.raw do |stdin|
|
37
|
+
$stdout << CSI + '6n' # Tha actual ANSI get-position
|
38
|
+
$stdout.flush
|
39
|
+
while (c = stdin.getc) != 'R'
|
40
|
+
res << c if c
|
41
|
+
end
|
40
42
|
end
|
43
|
+
rescue Errno::ENOTTY
|
44
|
+
# Not a TTY, return default values
|
45
|
+
return 25, 80
|
41
46
|
end
|
42
47
|
m = res.match /(?<row>\d+);(?<col>\d+)/
|
43
|
-
return m[:row].to_i, m[:col].to_i
|
48
|
+
return m ? [m[:row].to_i, m[:col].to_i] : [25, 80]
|
44
49
|
end
|
45
50
|
def rowget
|
46
51
|
row, col = self.pos
|
@@ -555,20 +560,24 @@ def hist_clean # Clean up @history
|
|
555
560
|
end
|
556
561
|
def cmd_check(str) # Check if each element on the readline matches commands, nicks, paths; color them
|
557
562
|
return if str.nil?
|
558
|
-
|
563
|
+
|
559
564
|
# Special handling for @ and @@ commands
|
560
565
|
if str =~ /^(@@?)\s+(.*)$/
|
561
566
|
prefix = $1
|
562
567
|
rest = $2
|
563
568
|
return prefix.c(4) + " " + rest # Color @ or @@ in blue (4), rest uncolored
|
564
569
|
end
|
565
|
-
|
570
|
+
|
566
571
|
str.gsub(/(?:\S'[^']*'|[^ '])+/) do |el|
|
572
|
+
clean_el = el.gsub("'", "")
|
567
573
|
if @exe.include?(el)
|
568
574
|
el.c(@c_cmd)
|
569
575
|
elsif el == "cd"
|
570
576
|
el.c(@c_cmd)
|
571
|
-
elsif File.exist?(
|
577
|
+
elsif clean_el =~ /^\.\/(.+)/ && File.exist?(clean_el) && File.executable?(clean_el)
|
578
|
+
# Color local executables starting with ./
|
579
|
+
el.c(@c_cmd)
|
580
|
+
elsif File.exist?(clean_el)
|
572
581
|
el.c(@c_path)
|
573
582
|
elsif @nick.include?(el)
|
574
583
|
el.c(@c_nick)
|
@@ -592,12 +601,19 @@ def rshrc # Write updates to .rshrc
|
|
592
601
|
else
|
593
602
|
conf = ""
|
594
603
|
end
|
595
|
-
conf.sub!(/^@nick.*\n/, "")
|
604
|
+
conf.sub!(/^@nick.*\n/, "")
|
596
605
|
conf += "@nick = #{@nick}\n"
|
597
|
-
conf.sub!(/^@gnick.*\n/, "")
|
606
|
+
conf.sub!(/^@gnick.*\n/, "")
|
598
607
|
conf += "@gnick = #{@gnick}\n"
|
599
|
-
conf.sub!(/^@history.*\n/, "")
|
600
|
-
|
608
|
+
conf.sub!(/^@history.*\n/, "")
|
609
|
+
# Ensure history is properly formatted as valid Ruby array
|
610
|
+
begin
|
611
|
+
history_str = @history.last(@histsize).inspect
|
612
|
+
conf += "@history = #{history_str}\n"
|
613
|
+
rescue => e
|
614
|
+
conf += "@history = []\n"
|
615
|
+
puts "Warning: Error saving history: #{e.message}"
|
616
|
+
end
|
601
617
|
File.write(Dir.home+'/.rshrc', conf)
|
602
618
|
puts "\n.rshrc updated"
|
603
619
|
end
|
@@ -1100,18 +1116,140 @@ def ai_setup_help
|
|
1100
1116
|
end
|
1101
1117
|
|
1102
1118
|
# INITIAL SETUP
|
1119
|
+
def load_rshrc_safe
|
1120
|
+
return unless File.exist?(Dir.home+'/.rshrc')
|
1121
|
+
|
1122
|
+
begin
|
1123
|
+
# Try to load the .rshrc file
|
1124
|
+
load(Dir.home+'/.rshrc')
|
1125
|
+
|
1126
|
+
# Validate critical variables
|
1127
|
+
@history = [] unless @history.is_a?(Array)
|
1128
|
+
@nick = {} unless @nick.is_a?(Hash)
|
1129
|
+
@gnick = {} unless @gnick.is_a?(Hash)
|
1130
|
+
|
1131
|
+
rescue SyntaxError => e
|
1132
|
+
puts "\n\033[31mERROR: Syntax error in .rshrc:\033[0m"
|
1133
|
+
puts e.message
|
1134
|
+
puts "\n\033[33mAttempting to auto-heal .rshrc...\033[0m\n"
|
1135
|
+
|
1136
|
+
if auto_heal_rshrc
|
1137
|
+
puts "\033[32m.rshrc has been healed! Retrying...\033[0m\n"
|
1138
|
+
begin
|
1139
|
+
load(Dir.home+'/.rshrc')
|
1140
|
+
rescue => e2
|
1141
|
+
puts "\033[31mAuto-heal failed. Loading with defaults.\033[0m"
|
1142
|
+
load_defaults
|
1143
|
+
end
|
1144
|
+
else
|
1145
|
+
puts "\033[31mAuto-heal failed. Loading with defaults.\033[0m"
|
1146
|
+
load_defaults
|
1147
|
+
end
|
1148
|
+
|
1149
|
+
rescue => e
|
1150
|
+
puts "\n\033[31mERROR loading .rshrc: #{e.message}\033[0m"
|
1151
|
+
puts "\033[33mLoading with defaults...\033[0m\n"
|
1152
|
+
load_defaults
|
1153
|
+
end
|
1154
|
+
end
|
1155
|
+
|
1156
|
+
def auto_heal_rshrc
|
1157
|
+
begin
|
1158
|
+
rshrc_path = Dir.home + '/.rshrc'
|
1159
|
+
return false unless File.exist?(rshrc_path)
|
1160
|
+
|
1161
|
+
# Backup the corrupted file
|
1162
|
+
backup_path = rshrc_path + '.backup.' + Time.now.strftime('%Y%m%d_%H%M%S')
|
1163
|
+
File.write(backup_path, File.read(rshrc_path))
|
1164
|
+
puts "Backed up corrupted .rshrc to #{backup_path}"
|
1165
|
+
|
1166
|
+
content = File.read(rshrc_path)
|
1167
|
+
original_content = content.dup
|
1168
|
+
healed = false
|
1169
|
+
|
1170
|
+
# Fix common history array issues
|
1171
|
+
if content =~ /^@history\s*=\s*\[.*\]\s*\n\s*,/m
|
1172
|
+
# Fix case where array ends with ] followed by comma on next line
|
1173
|
+
content.gsub!(/^(@history\s*=\s*\[.*\])\s*\n\s*,(.*)$/m) do |match|
|
1174
|
+
# Remove the extra closing bracket and merge the lines
|
1175
|
+
history_line = $1
|
1176
|
+
continuation = $2
|
1177
|
+
# Remove trailing ] from first part
|
1178
|
+
history_line = history_line.sub(/\]\s*$/, '')
|
1179
|
+
# Combine and close properly
|
1180
|
+
"#{history_line}, #{continuation}]"
|
1181
|
+
end
|
1182
|
+
healed = true
|
1183
|
+
end
|
1184
|
+
|
1185
|
+
# Fix unclosed arrays
|
1186
|
+
['@history', '@nick', '@gnick'].each do |var|
|
1187
|
+
if content =~ /^#{var}\s*=\s*[[{](?!.*[}\]]\s*$)/m
|
1188
|
+
content.sub!(/^(#{var}\s*=\s*)(\[.*?)$/m) { "#{$1}#{$2}]" }
|
1189
|
+
content.sub!(/^(#{var}\s*=\s*)({.*?)$/m) { "#{$1}#{$2}}" }
|
1190
|
+
healed = true
|
1191
|
+
end
|
1192
|
+
end
|
1193
|
+
|
1194
|
+
# Validate Ruby syntax of the healed content
|
1195
|
+
begin
|
1196
|
+
# Try to parse the content
|
1197
|
+
eval("BEGIN {return true}\n" + content)
|
1198
|
+
rescue SyntaxError => e
|
1199
|
+
# If still has syntax errors, extract only valid parts
|
1200
|
+
new_content = ""
|
1201
|
+
|
1202
|
+
# Extract valid variable assignments
|
1203
|
+
content.each_line do |line|
|
1204
|
+
if line =~ /^(@\w+|\w+)\s*=\s*.+$/
|
1205
|
+
begin
|
1206
|
+
eval(line)
|
1207
|
+
new_content += line
|
1208
|
+
rescue
|
1209
|
+
# Skip invalid lines
|
1210
|
+
end
|
1211
|
+
elsif line =~ /^(def|class|module|end|if|else|elsif|when|case|begin|rescue)/
|
1212
|
+
new_content += line
|
1213
|
+
elsif line.strip.start_with?('#') || line.strip.empty?
|
1214
|
+
new_content += line
|
1215
|
+
end
|
1216
|
+
end
|
1217
|
+
|
1218
|
+
content = new_content
|
1219
|
+
healed = true
|
1220
|
+
end
|
1221
|
+
|
1222
|
+
if healed && content != original_content
|
1223
|
+
File.write(rshrc_path, content)
|
1224
|
+
return true
|
1225
|
+
end
|
1226
|
+
|
1227
|
+
false
|
1228
|
+
rescue => e
|
1229
|
+
puts "Error during auto-heal: #{e.message}"
|
1230
|
+
false
|
1231
|
+
end
|
1232
|
+
end
|
1233
|
+
|
1234
|
+
def load_defaults
|
1235
|
+
@history ||= []
|
1236
|
+
@nick ||= {"ls" => "ls --color -F"}
|
1237
|
+
@gnick ||= {}
|
1238
|
+
puts "Loaded with default configuration."
|
1239
|
+
end
|
1240
|
+
|
1103
1241
|
begin # Load .rshrc and populate @history
|
1104
1242
|
trap "SIGINT" do end
|
1105
|
-
trap "SIGHUP" do
|
1243
|
+
trap "SIGHUP" do
|
1106
1244
|
rshrc
|
1107
1245
|
exit
|
1108
1246
|
end
|
1109
|
-
trap "SIGTERM" do
|
1247
|
+
trap "SIGTERM" do
|
1110
1248
|
rshrc
|
1111
1249
|
exit
|
1112
1250
|
end
|
1113
1251
|
firstrun unless File.exist?(Dir.home+'/.rshrc') # Initial loading - to get history
|
1114
|
-
|
1252
|
+
load_rshrc_safe
|
1115
1253
|
# Load login shell files if rsh is running as login shell
|
1116
1254
|
if ENV['LOGIN_SHELL'] or $0 == "-rsh" or ARGV.include?('-l') or ARGV.include?('--login')
|
1117
1255
|
['/etc/profile', Dir.home+'/.profile', Dir.home+'/.bash_profile', Dir.home+'/.bashrc'].each do |f|
|
@@ -1155,7 +1293,7 @@ loop do
|
|
1155
1293
|
begin
|
1156
1294
|
@user = Etc.getpwuid(Process.euid).name # For use in @prompt
|
1157
1295
|
@node = Etc.uname[:nodename] # For use in @prompt
|
1158
|
-
h = @history;
|
1296
|
+
h = @history; load_rshrc_safe; @history = h # reload prompt but not history safely
|
1159
1297
|
@prompt.gsub!(/#{Dir.home}/, '~') # Simplify path in prompt
|
1160
1298
|
system("printf \"\033]0;rsh: #{Dir.pwd}\007\"") # Set Window title to path
|
1161
1299
|
@history[0] = "" unless @history[0]
|
@@ -1178,7 +1316,7 @@ loop do
|
|
1178
1316
|
# Move cursor to end of line and print the full command before clearing
|
1179
1317
|
@c.row(@row0)
|
1180
1318
|
@c.clear_line
|
1181
|
-
print @prompt + @cmd
|
1319
|
+
print @prompt + cmd_check(@cmd)
|
1182
1320
|
print "\n"; @c.clear_screen_down
|
1183
1321
|
if @cmd == "r" # Integration with rtfm (https://github.com/isene/RTFM)
|
1184
1322
|
t = Time.now
|
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: 2.
|
4
|
+
version: 2.10.0
|
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-
|
11
|
+
date: 2025-09-16 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
|
-
v2.
|
16
|
-
|
17
|
-
|
18
|
-
command
|
15
|
+
v2.10.0: Auto-healing for corrupted .rshrc files and robust error handling. v2.9.0:
|
16
|
+
AI integration! Use @ for AI text responses and @@ for AI command suggestions. Works
|
17
|
+
with local Ollama or external providers like OpenAI. v2.8.0: Enhanced help system,
|
18
|
+
:info command, and easier nick management.'
|
19
19
|
email: g@isene.com
|
20
20
|
executables:
|
21
21
|
- rsh
|