ruby-shell 1.1 → 2.0

Sign up to get free protection for your applications and to get access to all the features.
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: []