ruby-shell 1.1 → 2.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.
Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/bin/rsh +185 -163
  4. metadata +8 -8
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 99b63b13ddf019d5fbac48dd76cbd8c53b381c46eebbf0717499e9b904015209
4
- data.tar.gz: 40c43d51e54bdf37d7bc35d5e127e824314ec7ea89956e0015f6b8673dce016d
3
+ metadata.gz: 0ec039977b048309a3b3762f8b009b83820693ec99857c9ce700322339dbecf5
4
+ data.tar.gz: 35498c5cdd7dd2eea545b85d994370dca0cfadb74415eb28bf0169f46673c425
5
5
  SHA512:
6
- metadata.gz: 035ee8876b1b89dcf4cea42e9d636a167e9909a44a629c130bbd09dda0487fcbae4d07ad5e148a48d06213486774cebc6e3e804107e842ce6a2e3544ee2b70d3
7
- data.tar.gz: a5209bc92c252335efa4d07518cdab32b095c1e3c19dbae7dc2180f25e15997ed52f40c44f6186d03c668d7f6d65fd26630dd48548990f62831647d1794597fc
6
+ metadata.gz: b262ececc24a31380445f8e88e645cccbef5bb4ce043143d4268c6a116bbe4df3293cd5affd26b036be1d58af7bf4fd653b1f1747a78419e40a3ef0e34d41380
7
+ data.tar.gz: 9de2ac401010abd356a3b1aefca9848de07ba1829eb45c958a963b40d78825449de04737b9e0cf78da5ba2f1530e5306656830d3c5a4ae61d6635ccb749abe6c
data/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
  The Ruby SHell
5
5
 
6
6
  # Why?
7
- Ruby is my goto language (pun kinda intended). I want full control over my tools and I like challenges that I can tinker with late at night. This is an incomplete project continually being improved. Feel free to add suggestions or code.
7
+ <img src="img/rsh-logo.jpg" align="left" width="150" height="150">Ruby is my goto language (pun kinda intended). I want full control over my tools and I like challenges that I can tinker with late at night. This is an incomplete project continually being improved. Feel free to add suggestions or code.
8
8
 
9
9
  # Design principles
10
10
  Simple. One file. Minimum external requirements.
data/bin/rsh CHANGED
@@ -7,25 +7,20 @@
7
7
  # Author: Geir Isene <g@isene.com>
8
8
  # Web_site: http://isene.com/
9
9
  # Github: https://github.com/isene/rsh
10
- # License: I release all copyright claims. This code is in the public domain.
11
- # Permission is granted to use, copy modify, distribute, and sell
12
- # this software for any purpose. I make no guarantee about the
13
- # suitability of this software for any purpose and I am not liable
14
- # for any damages resulting from its use. Further, I am under no
15
- # obligation to maintain or extend this software. It is provided
16
- # on an 'as is' basis without any expressed or implied warranty.
17
- @version = "1.1"
10
+ # License: Public domain
11
+ @version = "2.0"
18
12
 
19
13
  # MODULES, CLASSES AND EXTENSIONS
20
14
  class String # Add coloring to strings (with escaping for Readline)
21
- def c(code); color(self, "\001\e[38;5;#{code}m\002"); end
22
- def b; color(self, "\001\e[1m\002"); end
23
- def i; color(self, "\001\e[3m\002"); end
24
- def u; color(self, "\001\e[4m\002"); end
25
- def l; color(self, "\001\e[5m\002"); end
15
+ def c(code); color(self, "\001\e[38;5;#{code}m\002"); end # Color code
16
+ def b; color(self, "\001\e[1m\002"); end # Bold
17
+ def i; color(self, "\001\e[3m\002"); end # Italic
18
+ def u; color(self, "\001\e[4m\002"); end # Underline
19
+ def l; color(self, "\001\e[5m\002"); end # Blink
20
+ def r; color(self, "\001\e[7m\002"); end # Reverse
26
21
  def color(text, color_code) "#{color_code}#{text}\001\e[0m\002" end
27
22
  end
28
- module Cursor # Terminal cursor movement ANSI codes (thanks to https://github.com/piotrmurach/tty-cursor/tree/master)
23
+ module Cursor # Terminal cursor movement ANSI codes (thanks to https://github.com/piotrmurach/tty-cursor)
29
24
  module_function
30
25
  ESC = "\e".freeze
31
26
  CSI = "\e[".freeze
@@ -93,6 +88,12 @@ module Cursor # Terminal cursor movement ANSI codes (thanks to https://github.co
93
88
  print(CSI + 'J')
94
89
  end
95
90
  end
91
+ def stdin_clear
92
+ begin
93
+ $stdin.getc while $stdin.ready?
94
+ rescue
95
+ end
96
+ end
96
97
 
97
98
  # INITIALIZATION
98
99
  begin # Requires
@@ -102,13 +103,13 @@ begin # Requires
102
103
  end
103
104
  begin # Initialization
104
105
  # Theming
105
- @c_prompt = 196 # Color for basic prompt
106
- @c_cmd = 48 # Color for valid command
107
- @c_nick = 51 # Color for matching nick
108
- @c_gnick = 87 # Color for matching gnick
109
- @c_path = 208 # Color for valid path
110
- @c_switch = 148 # Color for switches/options
111
- @c_tabselect = 207 # Color for selected tabcompleted item
106
+ @c_prompt = 10 # Color for basic prompt
107
+ @c_cmd = 2 # Color for valid command
108
+ @c_nick = 6 # Color for matching nick
109
+ @c_gnick = 14 # Color for matching gnick
110
+ @c_path = 3 # Color for valid path
111
+ @c_switch = 6 # Color for switches/options
112
+ @c_tabselect = 5 # Color for selected tabcompleted item
112
113
  @c_taboption = 244 # Color for unselected tabcompleted item
113
114
  @c_stamp = 244 # Color for time stamp/command
114
115
  # Prompt
@@ -123,12 +124,14 @@ begin # Initialization
123
124
  "/usr/bin",
124
125
  "/home/#{@user}/bin"] # Basic paths for executables if not set in .rshrc
125
126
  # History
126
- @histsize = 100 # Max history if not set in .rshrc
127
+ @histsize = 200 # Max history if not set in .rshrc
127
128
  @hloaded = false # Variable to determine if history is loaded
128
- # Use run-mailcap instead of xgd-open? Set = true in .rshrc if iyou want run-mailcap
129
+ # Use run-mailcap instead of xgd-open? Set "= true" in .rshrc if you want run-mailcap
129
130
  @runmailcap = false
130
131
  # Variable initializations
131
132
  @dirs = ["."]*10
133
+ def pre_cmd; end # User-defined function to be run BEFORE command execution
134
+ def post_cmd; end # User-defined function to be run AFTER command execution
132
135
  end
133
136
 
134
137
  # HELP TEXT
@@ -158,7 +161,7 @@ end
158
161
  Special functions/integrations:
159
162
  * Use `r` to launch rtfm (https://github.com/isene/RTFM) - if you have it installed
160
163
  * Use `f` to launch fzf (https://github.com/junegunn/fzf) - if you have it installed
161
- * Use `=` followed by xrpn commands separated by commas (https://github.com/isene/xrpn)
164
+ * Use `=` followed by xrpn commands separated by commas or double-spaces (https://github.com/isene/xrpn)
162
165
  * Use `:` followed by a Ruby expression to access the whole world of Ruby
163
166
 
164
167
  Special commands:
@@ -177,7 +180,7 @@ def firstrun
177
180
  puts "Since there is no rsh configuration file (.rshrc), I will help you set it up to suit your needs.\n\n"
178
181
  puts "The prompt you see now is the very basic rsh prompt:"
179
182
  print "#{@prompt} (press ENTER)"
180
- STDIN.gets
183
+ $stdin.gets
181
184
  puts "\nI will now change the prompt into something more useful."
182
185
  puts "Feel free to amend the prompt in your .rshrc.\n\n"
183
186
  rc = <<~RSHRC
@@ -202,30 +205,33 @@ RSHRC
202
205
  File.write(Dir.home+'/.rshrc', rc)
203
206
  end
204
207
  def getchr # Process key presses
205
- c = STDIN.getch
208
+ c = $stdin.getch
206
209
  case c
207
- when "\e" # ANSI escape sequences
208
- case STDIN.getc
210
+ when "\e" # ANSI escape sequences (with only ESC, it should stop right here)
211
+ return "ESC" if $stdin.ready? == nil
212
+ case $stdin.getc
209
213
  when '[' # CSI
210
- case STDIN.getc
214
+ case $stdin.getc # Will get (or ASK) for more (remaining part of special character)
211
215
  when 'A' then chr = "UP"
212
216
  when 'B' then chr = "DOWN"
213
217
  when 'C' then chr = "RIGHT"
214
218
  when 'D' then chr = "LEFT"
215
219
  when 'Z' then chr = "S-TAB"
216
- when '2' then chr = "INS" ; chr = "C-INS" if STDIN.getc == "^"
217
- when '3' then chr = "DEL" ; chr = "C-DEL" if STDIN.getc == "^"
218
- when '5' then chr = "PgUP" ; chr = "C-PgUP" if STDIN.getc == "^"
219
- when '6' then chr = "PgDOWN" ; chr = "C-PgDOWN" if STDIN.getc == "^"
220
- when '7' then chr = "HOME" ; chr = "C-HOME" if STDIN.getc == "^"
221
- when '8' then chr = "END" ; chr = "C-END" if STDIN.getc == "^"
220
+ when '2' then chr = "INS" ; chr = "C-INS" if $stdin.getc == "^"
221
+ when '3' then chr = "DEL" ; chr = "C-DEL" if $stdin.getc == "^"
222
+ when '5' then chr = "PgUP" ; chr = "C-PgUP" if $stdin.getc == "^"
223
+ when '6' then chr = "PgDOWN" ; chr = "C-PgDOWN" if $stdin.getc == "^"
224
+ when '7' then chr = "HOME" ; chr = "C-HOME" if $stdin.getc == "^"
225
+ when '8' then chr = "END" ; chr = "C-END" if $stdin.getc == "^"
226
+ else chr = ""
222
227
  end
223
228
  when 'O' # Set Ctrl+ArrowKey equal to ArrowKey; May be used for other purposes in the future
224
- case STDIN.getc
229
+ case $stdin.getc
225
230
  when 'a' then chr = "C-UP"
226
231
  when 'b' then chr = "C-DOWN"
227
232
  when 'c' then chr = "C-RIGHT"
228
233
  when 'd' then chr = "C-LEFT"
234
+ else chr = ""
229
235
  end
230
236
  end
231
237
  when "", "" then chr = "BACK"
@@ -245,7 +251,9 @@ def getchr # Process key presses
245
251
  when "\r" then chr = "ENTER"
246
252
  when "\t" then chr = "TAB"
247
253
  when /[[:print:]]/ then chr = c
254
+ else chr = ""
248
255
  end
256
+ stdin_clear
249
257
  return chr
250
258
  end
251
259
  def getstr # A custom Readline-like function
@@ -260,11 +268,15 @@ def getstr # A custom Readline-like function
260
268
  @c.clear_line
261
269
  print @prompt
262
270
  row, @pos0 = @c.pos
271
+ #@history[0] = "" if @history[0].nil?
263
272
  print cmd_check(@history[0])
264
- @ci = @history[1..].find_index {|e| e =~ /^#{Regexp.escape(@history[0])}/}
265
- @ci += 1 unless @ci == nil
266
- if @history[0].length > 2 and @ci
267
- print @history[@ci][@history[0].length..].to_s.c(@c_stamp)
273
+ @ci = @history[1..].find_index {|e| e =~ /^#{Regexp.escape(@history[0].to_s)}./}
274
+ unless @ci == nil
275
+ @ci += 1
276
+ @ciprompt = @history[@ci][@history[0].to_s.length..].to_s
277
+ end
278
+ if @history[0].to_s.length > 1 and @ci
279
+ print @ciprompt.c(@c_stamp)
268
280
  right = true
269
281
  end
270
282
  @c.col(@pos0 + @pos)
@@ -283,10 +295,9 @@ def getstr # A custom Readline-like function
283
295
  @c.row(1)
284
296
  @c.clear_screen_down
285
297
  when 'UP' # Go up in history
286
- #@history[0] = @history[@history[(@stk+1)..].index{|h| h =~ /#{@history[0]}/}+1] #Future magick
287
298
  if @stk == 0 and @history[0].length > 0
288
299
  @tabsearch = @history[0]
289
- tabbing("hist")
300
+ tab("hist")
290
301
  else
291
302
  if lift
292
303
  @history.unshift("")
@@ -296,6 +307,7 @@ def getstr # A custom Readline-like function
296
307
  unless @stk >= @history.length - 1
297
308
  @stk += 1
298
309
  @history[0] = @history[@stk].dup
310
+ @history[0] = "" unless @history[0]
299
311
  @pos = @history[0].length
300
312
  end
301
313
  lift = false
@@ -368,6 +380,7 @@ def getstr # A custom Readline-like function
368
380
  @pos = 0
369
381
  else
370
382
  @history[0] = @history[@stk].dup
383
+ @history[0] = "" unless @history[0]
371
384
  @pos = @history[0].length
372
385
  end
373
386
  when 'LDEL' # Delete readline (Ctrl-U)
@@ -376,7 +389,8 @@ def getstr # A custom Readline-like function
376
389
  lift = true
377
390
  when 'TAB' # Tab completion of dirs and files
378
391
  @ci = nil
379
- @tabsearch =~ /^-/ ? tabbing("switch") : tabbing("all")
392
+ #@tabsearch =~ /^-/ ? tabbing("switch") : tabbing("all")
393
+ tab("all")
380
394
  lift = true
381
395
  when 'S-TAB'
382
396
  @ci = nil
@@ -387,138 +401,133 @@ def getstr # A custom Readline-like function
387
401
  @pos += 1
388
402
  lift = true
389
403
  end
390
- while STDIN.ready?
391
- chr = STDIN.getc
404
+ while $stdin.ready?
405
+ chr = $stdin.getc
392
406
  @history[0].insert(@pos,chr)
393
407
  @pos += 1
394
408
  end
395
409
  end
410
+ @c.col(@pos0 + @history[0].length)
411
+ @c.clear_screen_down
396
412
  end
397
- def tabbing(type)
398
- @tabstr = @history[@stk][0...@pos]
399
- @tabend = @history[@stk][@pos..]
400
- elements = @tabstr.split(" ")
401
- if @tabstr.match(" $")
402
- elements.append("")
403
- @tabsearch = ""
404
- else
405
- @tabsearch = elements.last.to_s
406
- @tabstr = @tabstr[0...-@tabsearch.length]
407
- end
408
- i = elements.length - 1
409
- if @tabsearch =~ /^-/
410
- until i == 0
411
- i -= 1
412
- if elements[i] !~ /^-/
413
- tab_switch(elements[i])
414
- break
415
- end
416
- end
417
- elsif type == 'all'
418
- tab_all(@tabsearch)
419
- elsif type == 'hist'
420
- tab_hist(@tabsearch)
421
- end
422
- @history[@stk] = @tabstr.to_s + @tabsearch.to_s + @tabend.to_s
423
- end
424
- def tab_all(str) # TAB completion for Dirs/files, nicks and commands
425
- exe = []
426
- @path.each do |p|
427
- Dir.glob(p).each do |c|
428
- exe.append(File.basename(c)) if File.executable?(c) and not Dir.exist?(c)
429
- end
430
- end
431
- exe.prepend(*@nick.keys)
432
- exe.prepend(*@gnick.keys)
433
- compl = exe.select {|s| s =~ Regexp.new("^" + str)}
434
- fdir = str
435
- fdir += "/" if Dir.exist?(fdir)
436
- fdir += "*"
437
- compl.prepend(*Dir.glob(fdir))
438
- match = tabselect(compl) unless compl.empty?
439
- @tabsearch = match if match
440
- @pos = @tabstr.length + @tabsearch.length if match
441
- end
442
- def tab_switch(str) # TAB completion for command switches (TAB after "-")
443
- begin
444
- hlp = `#{str} --help 2>/dev/null`
445
- hlp = hlp.split("\n").grep(/^\s*-{1,2}[^-]/)
446
- hlp = hlp.map{|h| h.sub(/^\s*/, '').sub(/^--/, ' --')}
447
- switch = tabselect(hlp)
448
- switch = switch.sub(/ .*/, '').sub(/,/, '')
449
- @tabsearch = switch if switch
450
- @pos = @tabstr.length + @tabsearch.length
451
- rescue
452
- end
453
- end
454
- def tab_hist(str)
455
- sel = @history.select {|el| el =~ /#{str}/}
456
- sel.shift
457
- sel.delete("")
458
- hist = tabselect(sel, true)
459
- if hist
460
- @tabsearch = hist
461
- @tabstr = ""
462
- @pos = @tabsearch.length
463
- end
464
- end
465
- def tabselect(ary, hist=false) # Let user select from the incoming array
466
- ary.uniq!
467
- @c_row, @c_col = @c.pos
468
- chr = ""
413
+
414
+ def tab(type)
469
415
  i = 0
416
+ chr = ""
417
+ @tabarray = []
418
+ @pretab = @history[0][0...@pos].to_s # Extract the current line up to cursor
419
+ @postab = @history[0][@pos..].to_s # Extract the current line from cursor to end
420
+ @c_row, @c_col = @c.pos # Get cursor position
421
+ @tabstr = @pretab.split(/[|, ]/).last.to_s # Get the sustring that is being tab completed
422
+ @tabstr = "" if @pretab[-1] =~ /[ |]/
423
+ @pretab = @pretab.delete_suffix(@tabstr)
424
+ type = "switch" if @tabstr[0] == "-"
470
425
  while chr != "ENTER"
471
- @c.clear_screen_down
472
- ary.length - i < 5 ? l = ary.length - i : l = 5
473
- l.times do |x|
474
- tl = @tabsearch.length
475
- if x == 0
476
- @c.clear_line
477
- tabchoice = ary[i].sub(/^ *(.*?)[ ,].*/, '\1')
478
- tabline = "#{@prompt}#{cmd_check(@tabstr)}#{tabchoice.c(@c_tabselect)}#{@tabend}"
479
- print tabline # Full command line
480
- @c_col = @pos0 + @tabstr.length + tabchoice.length
481
- nextline
482
- print " " + ary[i].sub(/(.*?)#{@tabsearch}(.*)/, '\1'.c(@c_tabselect) + @tabsearch + '\2'.c(@c_tabselect))
426
+ case type
427
+ when "hist" # Handle history completions ('UP' key)
428
+ @tabarray = @history.select {|el| el =~ /#{@tabstr}/} # Select history items matching @tabstr
429
+ @tabarray.shift # Take away @history[0]
430
+ return if @tabarray.empty?
431
+ when "switch"
432
+ cmdswitch = @pretab.split(/[|, ]/).last.to_s
433
+ hlp = `#{cmdswitch} --help 2>/dev/null`
434
+ hlp = hlp.split("\n").grep(/^\s*-{1,2}[^-]/)
435
+ hlp = hlp.map{|h| h.sub(/^\s*/, '').sub(/^--/, ' --')}
436
+ hlp = hlp.reject{|h| /-</ =~ h}
437
+ @tabarray = hlp
438
+ when "all" # Handle all other tab completions
439
+ exe = []
440
+ @path.each do |p| # Add all executables in @path
441
+ Dir.glob(p).each do |c|
442
+ exe.append(File.basename(c)) if File.executable?(c) and not Dir.exist?(c)
443
+ end
444
+ end
445
+ exe.sort!
446
+ exe.prepend(*@nick.keys) # Add nicks
447
+ exe.prepend(*@gnick.keys) # Add gnicks
448
+ compl = exe.select {|s| s =~ Regexp.new(@tabstr)} # Select only that which matches so far
449
+ fdir = @tabstr + "*"
450
+ compl.prepend(*Dir.glob(fdir)).map! do |e|
451
+ if e =~ /(?<!\\) /
452
+ e = e.sub(/(.*\/|^)(.*)/, '\1\'\2\'') unless e =~ /'/
453
+ end
454
+ Dir.exist?(e) ? e + "/" : e # Add matching dirs
455
+ end
456
+ @tabarray = compl # Finally put it into @tabarray
457
+ end
458
+ return if @tabarray.empty?
459
+ @tabarray.delete("") # Don't remember why
460
+ @c.clear_screen_down # Here we go
461
+ @tabarray.length.to_i - i < 5 ? l = @tabarray.length.to_i - i : l = 5 # Max 5 rows of completion items
462
+ l.times do |x| # Iterate through
463
+ if x == 0 # First item goes onto the commandline
464
+ @c.clear_line # Clear the line
465
+ tabchoice = @tabarray[i] # Select the item from the @tabarray
466
+ tabchoice = tabchoice.sub(/\s*(-.*?)[,\s].*/, '\1') if type == "switch"
467
+ @newhist0 = @pretab + tabchoice + @postab # Remember now the new value to be given to @history[0]
468
+ line1 = cmd_check(@pretab).to_s # Syntax highlight before @tabstr
469
+ line2 = cmd_check(@postab).to_s # Syntax highlight after @tabstr
470
+ # Color and underline the current tabchoice on the commandline:
471
+ tabline = tabchoice.sub(/(.*)#{@tabstr}(.*)/, '\1'.c(@c_tabselect) + @tabstr.u.c(@c_tabselect) + '\2'.c(@c_tabselect))
472
+ print @prompt + line1 + tabline + line2 # Print the commandline
473
+ @pos = @pretab.length.to_i + tabchoice.length.to_i # Set the position on that commandline
474
+ @c_col = @pos0 + @pos # The cursor position must include the prompt as well
475
+ @c.col(@c_col) # Set the cursor position
476
+ nextline # Then start showing the completion items
477
+ tabline = @tabarray[i] # Get the next matching tabline
478
+ # Can't nest ANSI codes, they must each complete/conclude or they will mess eachother up
479
+ tabline1 = tabline.sub(/(.*?)#{@tabstr}.*/, '\1').c(@c_tabselect) # Color the part before the @tabstr
480
+ tabline2 = tabline.sub(/.*?#{@tabstr}(.*)/, '\1').c(@c_tabselect) # Color the part after the @tabstr
481
+ print " " + tabline1 + @tabstr.c(@c_tabselect).u + tabline2 # Color & underline @tabstr
483
482
  else
484
483
  begin
485
- print " " + ary[i+x].sub(/(.*?)#{@tabsearch}(.*)/, '\1'.c(@c_taboption) + @tabsearch + '\2'.c(@c_taboption))
484
+ tabline = @tabarray[i+x] # Next tabline, and next, etc (usually 4 times here)
485
+ tabline1 = tabline.sub(/(.*?)#{@tabstr}.*/, '\1').c(@c_taboption) # Color before @tabstr
486
+ tabline2 = tabline.sub(/.*?#{@tabstr}(.*)/, '\1').c(@c_taboption) # Color after @tabstr
487
+ print " " + tabline1 + @tabstr.c(@c_taboption).u + tabline2 # Print the whole line
486
488
  rescue
487
489
  end
488
490
  end
489
- nextline
491
+ nextline # To not run off screen
490
492
  end
491
- @c.row(@c_row)
492
- @c.col(@c_col)
493
- chr = getchr
494
- case chr
495
- when 'C-G', 'C-C'
496
- @c.clear_screen_down
497
- return @tabsearch
493
+ @c.row(@c_row) # Set cursor row to commandline
494
+ @c.col(@c_col) # Set cursor col on commandline
495
+ chr = getchr # Now get user input
496
+ case chr # Treat the keypress
497
+ when 'C-G', 'C-C', 'ESC'
498
+ tabend; return
498
499
  when 'DOWN'
499
- i += 1 unless i > ary.length - 2
500
+ i += 1 unless i > @tabarray.length.to_i - 2
500
501
  when 'UP'
501
502
  i -= 1 unless i == 0
502
- when 'TAB'
503
+ when 'TAB', 'RIGHT' # Effectively the same as ENTER
503
504
  chr = "ENTER"
504
- when 'BACK'
505
- if @tabsearch == ''
506
- @c.clear_screen_down
507
- return ""
505
+ when 'BACK', 'LEFT' # Delete one character to the left
506
+ if @tabstr == ""
507
+ @history[0] = @pretab + @postab
508
+ tabend
509
+ return
510
+ end
511
+ @tabstr.chop!
512
+ when 'WBACK' # Delete one word to the left (Ctrl-W)
513
+ if @tabstr == ""
514
+ @history[0] = @pretab + @postab
515
+ tabend
516
+ return
508
517
  end
509
- @tabsearch.chop!
510
- hist ? tab_hist(@tabsearch) : tab_all(@tabsearch)
511
- return @tabsearch
518
+ @tabstr.sub!(/#{@tabstr.split(/[|, ]/).last}.*/, '')
519
+ when ' '
520
+ @tabstr += " "
521
+ chr = "ENTER"
512
522
  when /^[[:print:]]$/
513
- @tabsearch += chr
514
- hist ? tab_hist(@tabsearch) : tab_all(@tabsearch)
515
- return @tabsearch
523
+ @tabstr += chr
524
+ i = 0
516
525
  end
517
526
  end
518
527
  @c.clear_screen_down
519
528
  @c.row(@c_row)
520
529
  @c.col(@c_col)
521
- return ary[i].sub(/^ */, '')
530
+ @history[0] = @newhist0
522
531
  end
523
532
  def nextline # Handle going to the next line in the terminal
524
533
  row, col = @c.pos
@@ -528,26 +537,33 @@ def nextline # Handle going to the next line in the terminal
528
537
  end
529
538
  @c.next_line
530
539
  end
540
+ def tabend
541
+ @c.clear_screen_down
542
+ @pos = @history[0].length
543
+ @c_col = @pos0 + @pos
544
+ @c.col(@c_col)
545
+ end
531
546
  def hist_clean # Clean up @history
532
547
  @history.uniq!
533
548
  @history.compact!
534
549
  @history.delete("")
535
550
  end
536
551
  def cmd_check(str) # Check if each element on the readline matches commands, nicks, paths; color them
537
- str.gsub(/\S+/) do |el|
552
+ return if str.nil?
553
+ str.gsub(/(?:\S'[^']*'|[^ '])+/) do |el|
538
554
  if @nick.include?(el)
539
555
  el.c(@c_nick)
540
- elsif el == "r"
556
+ elsif el == "r" or el == "f"
541
557
  el.c(@c_nick)
542
558
  elsif @gnick.include?(el)
543
559
  el.c(@c_gnick)
544
- elsif File.exist?(el.sub(/^~/, "/home/#{@user}"))
560
+ elsif File.exist?(el.gsub("'", ""))
545
561
  el.c(@c_path)
546
562
  elsif system "which #{el}", %i[out err] => File::NULL
547
563
  el.c(@c_cmd)
548
564
  elsif el == "cd"
549
565
  el.c(@c_cmd)
550
- elsif el =~ /^-/
566
+ elsif el[0] == "-"
551
567
  el.c(@c_switch)
552
568
  else
553
569
  el
@@ -568,7 +584,7 @@ def rshrc # Write updates to .rshrc
568
584
  conf.sub!(/^@history.*\n/, "")
569
585
  conf += "@history = #{@history.last(@histsize)}\n"
570
586
  File.write(Dir.home+'/.rshrc', conf)
571
- puts ".rshrc updated"
587
+ puts "\n.rshrc updated"
572
588
  end
573
589
 
574
590
  # RSH FUNCTIONS
@@ -610,9 +626,9 @@ def gnick(nick_str) # Define a generic/global nick to match not only commands (f
610
626
  end
611
627
  def nick? # Show nicks
612
628
  puts " Command nicks:".c(@c_nick)
613
- @nick.each {|key, value| puts " #{key} = #{value}"}
629
+ @nick.sort.each {|key, value| puts " #{key} = #{value}"}
614
630
  puts " General nicks:".c(@c_gnick)
615
- @gnick.each {|key, value| puts " #{key} = #{value}"}
631
+ @gnick.sort.each {|key, value| puts " #{key} = #{value}"}
616
632
  end
617
633
  def dirs
618
634
  puts "Past direactories:"
@@ -654,6 +670,7 @@ loop do
654
670
  h = @history; load(Dir.home+'/.rshrc') if File.exist?(Dir.home+'/.rshrc'); @history = h # reload prompt but not history
655
671
  @prompt.gsub!(/#{Dir.home}/, '~') # Simplify path in prompt
656
672
  system("printf \"\033]0;rsh: #{Dir.pwd}\007\"") # Set Window title to path
673
+ @history[0] = "" unless @history[0]
657
674
  getstr # Main work is here
658
675
  @cmd = @history[0]
659
676
  @dirs.unshift(Dir.pwd)
@@ -676,7 +693,10 @@ loop do
676
693
  system("git status .") if Dir.exist?(".git")
677
694
  next
678
695
  end
679
- @cmd = "echo \"#{@cmd[1...]},prx,off\" | xrpn" if @cmd =~ /^\=/ # Integration with xrpn (https://github.com/isene/xrpn)
696
+ if @cmd =~ /^\=/ # Integration with xrpn (https://github.com/isene/xrpn)
697
+ @cmd.gsub!(" ", ",")
698
+ @cmd = "echo \"#{@cmd[1...]},prx,off\" | xrpn"
699
+ end
680
700
  if @cmd.match(/^\s*:/) # Ruby commands are prefixed with ":"
681
701
  begin
682
702
  eval(@cmd[1..-1])
@@ -689,7 +709,7 @@ loop do
689
709
  else # Execute command
690
710
  ca = @nick.transform_keys {|k| /((^\K\s*\K)|(\|\K\s*\K))\b(?<!-)#{Regexp.escape k}\b/}
691
711
  @cmd = @cmd.gsub(Regexp.union(ca.keys), @nick)
692
- ga = @gnick.transform_keys {|k| /\b#{Regexp.escape k}\b/}
712
+ ga = @gnick.transform_keys {|k| /\b(?<!-)#{Regexp.escape k}\b/}
693
713
  @cmd = @cmd.gsub(Regexp.union(ga.keys), @gnick)
694
714
  @cmd = "~" if @cmd == "cd"
695
715
  @cmd.sub!(/^cd (\S*).*/, '\1')
@@ -717,15 +737,17 @@ loop do
717
737
  end
718
738
  else
719
739
  begin
720
- puts "No such command or nick: #{@cmd}" unless system (@cmd) # Try execute the command
740
+ pre_cmd
741
+ puts " Not executed: #{@cmd}" unless system (@cmd) # Try execute the command
742
+ post_cmd
721
743
  rescue StandardError => err
722
744
  puts "\n#{err}"
723
745
  end
724
746
  end
725
747
  end
726
748
  end
727
- rescue StandardError => err # Throw error nicely
728
- puts "\n#{err}"
749
+ #rescue StandardError => err # Throw error nicely
750
+ # puts "\n#{err}"
729
751
  end
730
752
  end
731
753
 
metadata CHANGED
@@ -1,19 +1,19 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-shell
3
3
  version: !ruby/object:Gem::Version
4
- version: '1.1'
4
+ version: '2.0'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Geir Isene
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-06-22 00:00:00.000000000 Z
11
+ date: 2024-10-23 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. In
15
- continual development. New in 1.1: Added; Copy current command line to primary selection
16
- (paste w/middle button) with Ctrl-y'
15
+ continual development. New in 2.0: Full rewrite of tab completion engine. Lots of
16
+ other bug fixes.'
17
17
  email: g@isene.com
18
18
  executables:
19
19
  - rsh
@@ -28,7 +28,7 @@ licenses:
28
28
  - Unlicense
29
29
  metadata:
30
30
  source_code_uri: https://github.com/isene/rsh
31
- post_install_message:
31
+ post_install_message:
32
32
  rdoc_options: []
33
33
  require_paths:
34
34
  - lib
@@ -43,8 +43,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
43
43
  - !ruby/object:Gem::Version
44
44
  version: '0'
45
45
  requirements: []
46
- rubygems_version: 3.3.5
47
- signing_key:
46
+ rubygems_version: 3.4.20
47
+ signing_key:
48
48
  specification_version: 4
49
49
  summary: rsh - Ruby SHell
50
50
  test_files: []