ruby-shell 3.6.10 → 3.6.12

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 +38 -49
  3. metadata +4 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 76a48b3b13e6a1eb7fed0d68be6934d03182b8a176960d81b3c680367cd1d72e
4
- data.tar.gz: 4491a5c43703b4ad519df7e51ec3804a80bd9e6f45c84e8c53745453ec695b94
3
+ metadata.gz: 83be89da460ab7d6b0534773b414a23daebaa9c93e3dedae3c1e78d53fba1a3b
4
+ data.tar.gz: c95fffc211adbc81780bcf3e9d4003cd2880d0d370777ebeb9c70a90e9f4e5e3
5
5
  SHA512:
6
- metadata.gz: 9b502692bbb3d9471e24c97f8475c117381795ed431f002744a7774e98161ab2e9721e86e303c4e70e3b4685dbc07df30dd875bba8b178d180097a5a58ffedb0
7
- data.tar.gz: 14c7824dcfcb688d3f63fbbe7fa621c06f3d41e7a9680376315c018ab4198defa22b47c74ef0644bcf046326bd4610502c7ef3ace49f05a5a8258f2c4af6d3ea
6
+ metadata.gz: fd7b51b6c55a5c84e4a3a04a7ab3ce127a6977e064cc4f133c2d2ebf9759835398b60f7044e76aeb6ecf1f286db59110815e37733b0ff6ce0949ed039e1cc71b
7
+ data.tar.gz: 84f6015d8eede6d78a226124730676bbb241dd9205077767776f8b4b19b9f45fa60716fc3b2a65d7bbd5547f85f6c8e3e50f6e52b71b272682d35353df780cdc
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.6.10" # OSC 7: Report cwd to terminal (for wezterm etc.)
11
+ @version = "3.6.12" # Fix long command line wrapping
12
12
 
13
13
  # MODULES, CLASSES AND EXTENSIONS
14
14
  class String # Add coloring to strings (with escaping for Readline)
@@ -374,30 +374,23 @@ def getstr # A custom Readline-like function
374
374
  row, col = @c.pos
375
375
  @prompt_last_line = @display_prompt
376
376
  # Calculate visible length (strip ANSI) - don't trust @c.pos with complex prompts
377
- @pos0 = @display_prompt.gsub(/\001\e\[[0-9;]*m\002/, '').length
377
+ @pos0 = @display_prompt.gsub(/\001?\e\[[0-9;]*m\002?/, '').length
378
378
  @cmd_row = @row0
379
379
  @is_multiline = false
380
380
  end
381
381
 
382
- @skip_prompt_print = false # Track if prompt already printed (for Ctrl-L)
383
-
384
382
  while chr != "ENTER" # Keep going with readline until user presses ENTER
385
383
  @ci = nil
386
384
  lift = false
387
385
  right = false
388
386
 
389
- # Update command line display (not the prompt!)
387
+ # Clear from cmd_row down (handles wrapped lines from previous iteration)
390
388
  @c.row(@cmd_row)
389
+ @c.col(1)
390
+ @c.clear_screen_down
391
391
 
392
- # Reprint the prompt line (preserves colors) - skip if Ctrl-L just printed it
393
- unless @skip_prompt_print
394
- @c.col(1)
395
- print @prompt_last_line
396
- @c.clear_line_after
397
- end
398
- @skip_prompt_print = false # Reset flag
399
-
400
- # Print command text with syntax highlighting
392
+ # Always reprint prompt + command text
393
+ print @prompt_last_line
401
394
  print cmd_check(@history[0])
402
395
 
403
396
  # Print history suggestion if available
@@ -411,12 +404,21 @@ def getstr # A custom Readline-like function
411
404
  right = true
412
405
  end
413
406
 
414
- # Position cursor (unified - both now use string length which is 0-indexed)
415
- # @pos0 = visible length of prompt (14 for "geir@juba: ~/ ")
416
- # @pos = position in command text (0 = start, 5 = after 5 chars)
417
- # Terminal columns are 1-indexed, so add +1
418
- cursor_col = @pos0 + @pos + 1
419
- @c.row(@cmd_row)
407
+ # Detect if terminal scrolled due to wrapping near the bottom
408
+ end_row, _ = @c.pos
409
+ printed_len = @pos0 + @history[0].to_s.length
410
+ printed_len += @ciprompt.to_s.length if right # Include suggestion text
411
+ expected_rows = printed_len > 0 ? (printed_len - 1) / @maxcol : 0
412
+ actual_start = end_row - expected_rows
413
+ if actual_start < @cmd_row
414
+ @cmd_row = [actual_start, 1].max # Terminal scrolled; adjust (min row 1)
415
+ end
416
+
417
+ # Position cursor with wrapping math
418
+ total_pos = @pos0 + @pos # 0-indexed total position
419
+ cursor_row = @cmd_row + total_pos / @maxcol
420
+ cursor_col = total_pos % @maxcol + 1
421
+ @c.row(cursor_row)
420
422
  @c.col(cursor_col)
421
423
  chr = getchr
422
424
  puts "DEBUG: Got char: '#{chr}' (length: #{chr.length})" if ENV['RSH_DEBUG']
@@ -473,11 +475,10 @@ def getstr # A custom Readline-like function
473
475
  row, col = @c.pos
474
476
  @prompt_last_line = @display_prompt
475
477
  # Calculate visible length (match main init)
476
- @pos0 = @display_prompt.gsub(/\001\e\[[0-9;]*m\002/, '').length
478
+ @pos0 = @display_prompt.gsub(/\001?\e\[[0-9;]*m\002?/, '').length
477
479
  @cmd_row = @row0
478
480
  @is_multiline = false
479
481
  end
480
- @skip_prompt_print = true # Skip reprinting on next loop iteration
481
482
  when 'UP' # Go up in history
482
483
  if @stk == 0 and @history[0].length > 0
483
484
  @tabsearch = @history[0]
@@ -541,7 +542,6 @@ def getstr # A custom Readline-like function
541
542
  @history[0][@pos] = ""
542
543
  end
543
544
  lift = true
544
- @c.clear_line_after
545
545
  when 'WBACK' # Delete one word to the left (Ctrl-W)
546
546
  unless @pos == @pos0
547
547
  # Skip over any trailing spaces first
@@ -556,7 +556,6 @@ def getstr # A custom Readline-like function
556
556
  end
557
557
  end
558
558
  lift = true
559
- @c.clear_line_after
560
559
  when 'C-Y' # Copy command line to primary selection
561
560
  system("echo -n '#{@history[0]}' | xclip")
562
561
  puts "\n#{Time.now.strftime("%H:%M:%S")}: Copied to primary selection (paste with middle buttoni)".c(@c_stamp)
@@ -603,6 +602,7 @@ def getstr # A custom Readline-like function
603
602
  end
604
603
  while $stdin.ready?
605
604
  chr = $stdin.getc
605
+ chr = " " if chr == "\n" || chr == "\r" # Flatten pasted newlines
606
606
  @history[0].insert(@pos,chr)
607
607
  @pos += 1
608
608
  end
@@ -1495,6 +1495,7 @@ def cmd_check(str) # Check if each element on the readline matches commands, nic
1495
1495
  end
1496
1496
  end
1497
1497
  def rshrc # Write user configuration to .rshrc (portable between machines)
1498
+ return if @rshrc_load_failed # Never overwrite .rshrc if we couldn't parse it
1498
1499
  hist_clean # Clean history before saving
1499
1500
  if File.exist?(Dir.home+'/.rshrc')
1500
1501
  conf = File.read(Dir.home+'/.rshrc')
@@ -3349,13 +3350,15 @@ def load_rshrc_safe
3349
3350
  load_defaults
3350
3351
  end
3351
3352
  else
3352
- puts "\033[31mAuto-heal failed. Loading with defaults.\033[0m"
3353
+ puts "\033[31mAuto-heal failed. Loading with defaults (your .rshrc is preserved).\033[0m"
3354
+ @rshrc_load_failed = true
3353
3355
  load_defaults
3354
3356
  end
3355
3357
 
3356
3358
  rescue => e
3357
3359
  puts "\n\033[31mERROR loading .rshrc: #{e.message}\033[0m"
3358
- puts "\033[33mLoading with defaults...\033[0m\n"
3360
+ puts "\033[33mLoading with defaults (your .rshrc is preserved)...\033[0m\n"
3361
+ @rshrc_load_failed = true
3359
3362
  load_defaults
3360
3363
  end
3361
3364
  end
@@ -3399,31 +3402,17 @@ def auto_heal_rshrc
3399
3402
  end
3400
3403
 
3401
3404
  # Validate Ruby syntax of the healed content
3405
+ # Only check syntax - never strip unknown lines, as user configs
3406
+ # may contain ENV settings, if/else blocks, method calls, etc.
3402
3407
  begin
3403
- # Try to parse the content
3404
- eval("BEGIN {return true}\n" + content)
3408
+ RubyVM::InstructionSequence.compile(content)
3405
3409
  rescue SyntaxError => e
3406
- # If still has syntax errors, extract only valid parts
3407
- new_content = ""
3408
-
3409
- # Extract valid variable assignments
3410
- content.each_line do |line|
3411
- if line =~ /^(@\w+|\w+)\s*=\s*.+$/
3412
- begin
3413
- eval(line)
3414
- new_content += line
3415
- rescue
3416
- # Skip invalid lines
3417
- end
3418
- elsif line =~ /^(def|class|module|end|if|else|elsif|when|case|begin|rescue)/
3419
- new_content += line
3420
- elsif line.strip.start_with?('#') || line.strip.empty?
3421
- new_content += line
3422
- end
3423
- end
3424
-
3425
- content = new_content
3426
- healed = true
3410
+ # Log the error but do NOT destructively rewrite the file.
3411
+ # Stripping "invalid" lines destroys legitimate config like
3412
+ # ENV assignments, prompt logic, and File.read() calls.
3413
+ puts "Warning: .rshrc has syntax error: #{e.message}"
3414
+ puts "Please fix manually. Your config was NOT modified."
3415
+ return false
3427
3416
  end
3428
3417
 
3429
3418
  if healed && content != original_content
metadata CHANGED
@@ -1,18 +1,19 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-shell
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.6.10
4
+ version: 3.6.12
5
5
  platform: ruby
6
6
  authors:
7
7
  - Geir Isene
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-01-18 00:00:00.000000000 Z
11
+ date: 2026-02-19 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
- v3.6.10: OSC 7 support - reports cwd to terminal for wezterm/kitty spawn-in-same-dir.'
15
+ v3.6.12: Fix long command line wrapping - correct cursor positioning when commands
16
+ exceed terminal width.'
16
17
  email: g@isene.com
17
18
  executables:
18
19
  - rsh