ruby-shell 2.9.1 → 2.10.1
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 +175 -29
- 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: ee2ef357d1196f43811ad6974313bbdb057f61cf90219146936f70a2ec6f16bb
|
4
|
+
data.tar.gz: 85540ca12677d88d6b2fb6999f17ce871b7c5142f20a0fa14e03685f82f41853
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f7a35b051b9d768cb2065e6308eecc030f3b153a31881b31e25813a377de06ea98b5e76f55233dbc0ae1ec30920091ee62817352f43fc5645c3a3d69db746c78
|
7
|
+
data.tar.gz: f8aeb41fa3870b02d96b111126c1770fb74e235a01847947937461c1a697195e3fc6152eb5a45a147c1703278e12a1b8dc5c279e1c1e4b51d81fbeb0672ed27f
|
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.
|
11
|
+
@version = "2.10.1" # Bug fix: Improved && operator logic for proper conditional execution
|
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
|
@@ -596,12 +601,19 @@ def rshrc # Write updates to .rshrc
|
|
596
601
|
else
|
597
602
|
conf = ""
|
598
603
|
end
|
599
|
-
conf.sub!(/^@nick.*\n/, "")
|
604
|
+
conf.sub!(/^@nick.*\n/, "")
|
600
605
|
conf += "@nick = #{@nick}\n"
|
601
|
-
conf.sub!(/^@gnick.*\n/, "")
|
606
|
+
conf.sub!(/^@gnick.*\n/, "")
|
602
607
|
conf += "@gnick = #{@gnick}\n"
|
603
|
-
conf.sub!(/^@history.*\n/, "")
|
604
|
-
|
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
|
605
617
|
File.write(Dir.home+'/.rshrc', conf)
|
606
618
|
puts "\n.rshrc updated"
|
607
619
|
end
|
@@ -853,27 +865,39 @@ end
|
|
853
865
|
def execute_conditional(cmd_line)
|
854
866
|
# Split on && and || while preserving the operators
|
855
867
|
parts = cmd_line.split(/(\s*&&\s*|\s*\|\|\s*)/)
|
856
|
-
|
857
|
-
result =
|
868
|
+
|
869
|
+
result = nil # Start with nil to handle first command
|
858
870
|
i = 0
|
871
|
+
|
859
872
|
while i < parts.length
|
860
|
-
|
861
|
-
|
862
|
-
|
863
|
-
|
864
|
-
|
865
|
-
|
866
|
-
|
867
|
-
|
868
|
-
|
873
|
+
part = parts[i].strip
|
874
|
+
i += 1
|
875
|
+
next if part.empty?
|
876
|
+
|
877
|
+
if part == '&&'
|
878
|
+
# If previous command failed, skip the rest until we find || or end
|
879
|
+
unless result
|
880
|
+
while i < parts.length && parts[i].strip != '||'
|
881
|
+
i += 1
|
882
|
+
end
|
883
|
+
end
|
884
|
+
elsif part == '||'
|
885
|
+
# If previous command succeeded, skip the rest until we find && or end
|
886
|
+
if result
|
887
|
+
while i < parts.length && parts[i].strip != '&&'
|
888
|
+
i += 1
|
889
|
+
end
|
890
|
+
end
|
869
891
|
else
|
870
892
|
# Execute the command
|
871
|
-
success = system(
|
893
|
+
success = system(part)
|
872
894
|
result = success
|
873
|
-
|
895
|
+
@last_exit = $?.exitstatus
|
896
|
+
puts " Command failed: #{part} (exit #{@last_exit})" unless success
|
874
897
|
end
|
875
|
-
i += 1
|
876
898
|
end
|
899
|
+
|
900
|
+
result
|
877
901
|
end
|
878
902
|
def expand_braces(str)
|
879
903
|
# Simple brace expansion: {a,b,c} -> a b c
|
@@ -1104,18 +1128,140 @@ def ai_setup_help
|
|
1104
1128
|
end
|
1105
1129
|
|
1106
1130
|
# INITIAL SETUP
|
1131
|
+
def load_rshrc_safe
|
1132
|
+
return unless File.exist?(Dir.home+'/.rshrc')
|
1133
|
+
|
1134
|
+
begin
|
1135
|
+
# Try to load the .rshrc file
|
1136
|
+
load(Dir.home+'/.rshrc')
|
1137
|
+
|
1138
|
+
# Validate critical variables
|
1139
|
+
@history = [] unless @history.is_a?(Array)
|
1140
|
+
@nick = {} unless @nick.is_a?(Hash)
|
1141
|
+
@gnick = {} unless @gnick.is_a?(Hash)
|
1142
|
+
|
1143
|
+
rescue SyntaxError => e
|
1144
|
+
puts "\n\033[31mERROR: Syntax error in .rshrc:\033[0m"
|
1145
|
+
puts e.message
|
1146
|
+
puts "\n\033[33mAttempting to auto-heal .rshrc...\033[0m\n"
|
1147
|
+
|
1148
|
+
if auto_heal_rshrc
|
1149
|
+
puts "\033[32m.rshrc has been healed! Retrying...\033[0m\n"
|
1150
|
+
begin
|
1151
|
+
load(Dir.home+'/.rshrc')
|
1152
|
+
rescue => e2
|
1153
|
+
puts "\033[31mAuto-heal failed. Loading with defaults.\033[0m"
|
1154
|
+
load_defaults
|
1155
|
+
end
|
1156
|
+
else
|
1157
|
+
puts "\033[31mAuto-heal failed. Loading with defaults.\033[0m"
|
1158
|
+
load_defaults
|
1159
|
+
end
|
1160
|
+
|
1161
|
+
rescue => e
|
1162
|
+
puts "\n\033[31mERROR loading .rshrc: #{e.message}\033[0m"
|
1163
|
+
puts "\033[33mLoading with defaults...\033[0m\n"
|
1164
|
+
load_defaults
|
1165
|
+
end
|
1166
|
+
end
|
1167
|
+
|
1168
|
+
def auto_heal_rshrc
|
1169
|
+
begin
|
1170
|
+
rshrc_path = Dir.home + '/.rshrc'
|
1171
|
+
return false unless File.exist?(rshrc_path)
|
1172
|
+
|
1173
|
+
# Backup the corrupted file
|
1174
|
+
backup_path = rshrc_path + '.backup.' + Time.now.strftime('%Y%m%d_%H%M%S')
|
1175
|
+
File.write(backup_path, File.read(rshrc_path))
|
1176
|
+
puts "Backed up corrupted .rshrc to #{backup_path}"
|
1177
|
+
|
1178
|
+
content = File.read(rshrc_path)
|
1179
|
+
original_content = content.dup
|
1180
|
+
healed = false
|
1181
|
+
|
1182
|
+
# Fix common history array issues
|
1183
|
+
if content =~ /^@history\s*=\s*\[.*\]\s*\n\s*,/m
|
1184
|
+
# Fix case where array ends with ] followed by comma on next line
|
1185
|
+
content.gsub!(/^(@history\s*=\s*\[.*\])\s*\n\s*,(.*)$/m) do |match|
|
1186
|
+
# Remove the extra closing bracket and merge the lines
|
1187
|
+
history_line = $1
|
1188
|
+
continuation = $2
|
1189
|
+
# Remove trailing ] from first part
|
1190
|
+
history_line = history_line.sub(/\]\s*$/, '')
|
1191
|
+
# Combine and close properly
|
1192
|
+
"#{history_line}, #{continuation}]"
|
1193
|
+
end
|
1194
|
+
healed = true
|
1195
|
+
end
|
1196
|
+
|
1197
|
+
# Fix unclosed arrays
|
1198
|
+
['@history', '@nick', '@gnick'].each do |var|
|
1199
|
+
if content =~ /^#{var}\s*=\s*[[{](?!.*[}\]]\s*$)/m
|
1200
|
+
content.sub!(/^(#{var}\s*=\s*)(\[.*?)$/m) { "#{$1}#{$2}]" }
|
1201
|
+
content.sub!(/^(#{var}\s*=\s*)({.*?)$/m) { "#{$1}#{$2}}" }
|
1202
|
+
healed = true
|
1203
|
+
end
|
1204
|
+
end
|
1205
|
+
|
1206
|
+
# Validate Ruby syntax of the healed content
|
1207
|
+
begin
|
1208
|
+
# Try to parse the content
|
1209
|
+
eval("BEGIN {return true}\n" + content)
|
1210
|
+
rescue SyntaxError => e
|
1211
|
+
# If still has syntax errors, extract only valid parts
|
1212
|
+
new_content = ""
|
1213
|
+
|
1214
|
+
# Extract valid variable assignments
|
1215
|
+
content.each_line do |line|
|
1216
|
+
if line =~ /^(@\w+|\w+)\s*=\s*.+$/
|
1217
|
+
begin
|
1218
|
+
eval(line)
|
1219
|
+
new_content += line
|
1220
|
+
rescue
|
1221
|
+
# Skip invalid lines
|
1222
|
+
end
|
1223
|
+
elsif line =~ /^(def|class|module|end|if|else|elsif|when|case|begin|rescue)/
|
1224
|
+
new_content += line
|
1225
|
+
elsif line.strip.start_with?('#') || line.strip.empty?
|
1226
|
+
new_content += line
|
1227
|
+
end
|
1228
|
+
end
|
1229
|
+
|
1230
|
+
content = new_content
|
1231
|
+
healed = true
|
1232
|
+
end
|
1233
|
+
|
1234
|
+
if healed && content != original_content
|
1235
|
+
File.write(rshrc_path, content)
|
1236
|
+
return true
|
1237
|
+
end
|
1238
|
+
|
1239
|
+
false
|
1240
|
+
rescue => e
|
1241
|
+
puts "Error during auto-heal: #{e.message}"
|
1242
|
+
false
|
1243
|
+
end
|
1244
|
+
end
|
1245
|
+
|
1246
|
+
def load_defaults
|
1247
|
+
@history ||= []
|
1248
|
+
@nick ||= {"ls" => "ls --color -F"}
|
1249
|
+
@gnick ||= {}
|
1250
|
+
puts "Loaded with default configuration."
|
1251
|
+
end
|
1252
|
+
|
1107
1253
|
begin # Load .rshrc and populate @history
|
1108
1254
|
trap "SIGINT" do end
|
1109
|
-
trap "SIGHUP" do
|
1255
|
+
trap "SIGHUP" do
|
1110
1256
|
rshrc
|
1111
1257
|
exit
|
1112
1258
|
end
|
1113
|
-
trap "SIGTERM" do
|
1259
|
+
trap "SIGTERM" do
|
1114
1260
|
rshrc
|
1115
1261
|
exit
|
1116
1262
|
end
|
1117
1263
|
firstrun unless File.exist?(Dir.home+'/.rshrc') # Initial loading - to get history
|
1118
|
-
|
1264
|
+
load_rshrc_safe
|
1119
1265
|
# Load login shell files if rsh is running as login shell
|
1120
1266
|
if ENV['LOGIN_SHELL'] or $0 == "-rsh" or ARGV.include?('-l') or ARGV.include?('--login')
|
1121
1267
|
['/etc/profile', Dir.home+'/.profile', Dir.home+'/.bash_profile', Dir.home+'/.bashrc'].each do |f|
|
@@ -1159,7 +1305,7 @@ loop do
|
|
1159
1305
|
begin
|
1160
1306
|
@user = Etc.getpwuid(Process.euid).name # For use in @prompt
|
1161
1307
|
@node = Etc.uname[:nodename] # For use in @prompt
|
1162
|
-
h = @history;
|
1308
|
+
h = @history; load_rshrc_safe; @history = h # reload prompt but not history safely
|
1163
1309
|
@prompt.gsub!(/#{Dir.home}/, '~') # Simplify path in prompt
|
1164
1310
|
system("printf \"\033]0;rsh: #{Dir.pwd}\007\"") # Set Window title to path
|
1165
1311
|
@history[0] = "" unless @history[0]
|
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.1
|
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-09-
|
11
|
+
date: 2025-09-22 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
|