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.
Files changed (3) hide show
  1. checksums.yaml +4 -4
  2. data/bin/rsh +175 -29
  3. metadata +6 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9ceae5891b4b0deebdf2e2876232999e8c64374f4730ab4d5e8ef09ff2dc3835
4
- data.tar.gz: bee38e735fb5f9eb1b4b133471ea649faec9531c7138ef035c6c9a089db87f06
3
+ metadata.gz: ee2ef357d1196f43811ad6974313bbdb057f61cf90219146936f70a2ec6f16bb
4
+ data.tar.gz: 85540ca12677d88d6b2fb6999f17ce871b7c5142f20a0fa14e03685f82f41853
5
5
  SHA512:
6
- metadata.gz: 7e586a0d583b1d3c33f441ce1dcabf001dc1a12d3a375581ad2337db8cab2822850455cf599b5a5e7ba21a31d750f2133c10b0a71c3e9bdc6ff62454c98296ee
7
- data.tar.gz: 8b7ae87743f8fe9f0414dda5ae607f632ece3f8289131519d21d8ebc20d54d13d7d7361364b8eeef7d9c68d6af9006731790decbee4eb0862a159997af0f306c
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.9.1" # Bug fix: Improved command coloring for local executables and after ENTER
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
- $stdin.raw do |stdin|
36
- $stdout << CSI + '6n' # Tha actual ANSI get-position
37
- $stdout.flush
38
- while (c = stdin.getc) != 'R'
39
- res << c if c
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
- conf += "@history = #{@history.last(@histsize)}\n"
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 = true
868
+
869
+ result = nil # Start with nil to handle first command
858
870
  i = 0
871
+
859
872
  while i < parts.length
860
- command = parts[i].strip
861
- next if command.empty?
862
-
863
- if command == '&&'
864
- i += 1
865
- next unless result # Skip if previous command failed
866
- elsif command == '||'
867
- i += 1
868
- next if result # Skip if previous command succeeded
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(command)
893
+ success = system(part)
872
894
  result = success
873
- puts " Command failed: #{command} (exit #{$?.exitstatus})" unless success
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
- load(Dir.home+'/.rshrc')
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; load(Dir.home+'/.rshrc') if File.exist?(Dir.home+'/.rshrc'); @history = h # reload prompt but not 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.9.1
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-13 00:00:00.000000000 Z
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.9.0: AI integration! Use @ for AI text responses and @@ for AI command suggestions.
16
- Works with local Ollama or external providers like OpenAI. v2.8.0: Enhanced help
17
- system, :info command, and easier nick management. v2.7.0: Ruby Functions, job control,
18
- command substitution, and more.'
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