ruby-shell 3.4.0 → 3.4.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/README.md +90 -87
- data/bin/rsh +48 -2
- metadata +1 -1
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 8c171961f69d09b023cc69bc4cb66b615ec861e940e5369c265ccdf053004764
         | 
| 4 | 
            +
              data.tar.gz: ab185ee8de6daecf91a910f417de02916d259dc315d19c84fe64a2dd4f779123
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 6c8c2343b5cd84bb9508dc6bbe25ce6a7ee7741adc34f77e063628445dc76d28edd5d9774a986066ca46ac551c03dab7290083eaaca59889a525383ca6ff15c0
         | 
| 7 | 
            +
              data.tar.gz: 28c264420c010f966fcfb9cf200ea25b152a3ec2190700132f2a8185a9b34ff1783f786b36afb93e23c8eae3d36a13c68de5ff02d31106d1dd45c31a08cfca2d
         | 
    
        data/README.md
    CHANGED
    
    | @@ -19,93 +19,96 @@ Or simply `gem install ruby-shell`. | |
| 19 19 |  | 
| 20 20 | 
             
            # Features
         | 
| 21 21 |  | 
| 22 | 
            -
            ##  | 
| 23 | 
            -
             | 
| 24 | 
            -
             | 
| 25 | 
            -
             | 
| 26 | 
            -
             | 
| 27 | 
            -
             | 
| 28 | 
            -
             | 
| 29 | 
            -
             | 
| 30 | 
            -
             | 
| 31 | 
            -
             | 
| 32 | 
            -
             | 
| 33 | 
            -
             | 
| 34 | 
            -
             | 
| 35 | 
            -
             | 
| 36 | 
            -
             | 
| 37 | 
            -
             | 
| 38 | 
            -
             | 
| 39 | 
            -
             | 
| 40 | 
            -
             | 
| 41 | 
            -
             | 
| 42 | 
            -
             | 
| 43 | 
            -
             | 
| 44 | 
            -
             | 
| 45 | 
            -
            * ** | 
| 46 | 
            -
            * ** | 
| 47 | 
            -
            * ** | 
| 48 | 
            -
            * ** | 
| 49 | 
            -
             | 
| 50 | 
            -
             | 
| 51 | 
            -
            * ** | 
| 52 | 
            -
            * ** | 
| 53 | 
            -
            * ** | 
| 54 | 
            -
             | 
| 55 | 
            -
             | 
| 56 | 
            -
             | 
| 57 | 
            -
             | 
| 58 | 
            -
            * ** | 
| 59 | 
            -
            * ** | 
| 60 | 
            -
            * ** | 
| 61 | 
            -
            * ** | 
| 62 | 
            -
             | 
| 63 | 
            -
             | 
| 64 | 
            -
            * ** | 
| 65 | 
            -
            * ** | 
| 66 | 
            -
            * ** | 
| 67 | 
            -
            * ** | 
| 68 | 
            -
             | 
| 69 | 
            -
             | 
| 70 | 
            -
             | 
| 71 | 
            -
            *  | 
| 72 | 
            -
            *  | 
| 73 | 
            -
            *  | 
| 74 | 
            -
             | 
| 75 | 
            -
             | 
| 76 | 
            -
            *  | 
| 77 | 
            -
            *  | 
| 78 | 
            -
            *  | 
| 79 | 
            -
            *  | 
| 80 | 
            -
            *  | 
| 81 | 
            -
             | 
| 82 | 
            -
             | 
| 83 | 
            -
             | 
| 84 | 
            -
             | 
| 85 | 
            -
             | 
| 86 | 
            -
             | 
| 87 | 
            -
             | 
| 88 | 
            -
             | 
| 89 | 
            -
             | 
| 90 | 
            -
             | 
| 91 | 
            -
             | 
| 92 | 
            -
             | 
| 93 | 
            -
             | 
| 94 | 
            -
             | 
| 95 | 
            -
             | 
| 96 | 
            -
             | 
| 97 | 
            -
             | 
| 98 | 
            -
             | 
| 99 | 
            -
             | 
| 100 | 
            -
             | 
| 101 | 
            -
             | 
| 102 | 
            -
             | 
| 103 | 
            -
             | 
| 104 | 
            -
             | 
| 105 | 
            -
             | 
| 106 | 
            -
             | 
| 107 | 
            -
             | 
| 108 | 
            -
             | 
| 22 | 
            +
            ## Key Features
         | 
| 23 | 
            +
             | 
| 24 | 
            +
            ### Aliases (Nicks)
         | 
| 25 | 
            +
            **rsh uses "nicks" for aliases** - both simple command shortcuts and powerful parametrized templates:
         | 
| 26 | 
            +
             | 
| 27 | 
            +
            ```bash
         | 
| 28 | 
            +
            # Simple aliases
         | 
| 29 | 
            +
            :nick la = ls -la
         | 
| 30 | 
            +
            :nick gs = git status
         | 
| 31 | 
            +
             | 
| 32 | 
            +
            # Parametrized nicks (templates with {{placeholders}})
         | 
| 33 | 
            +
            :nick gp = git push origin {{branch}}
         | 
| 34 | 
            +
            gp branch=main              # Executes: git push origin main
         | 
| 35 | 
            +
             | 
| 36 | 
            +
            :nick deploy = ssh {{user}}@{{host}} 'systemctl restart {{app}}'
         | 
| 37 | 
            +
            deploy user=admin host=prod app=api
         | 
| 38 | 
            +
             | 
| 39 | 
            +
            # List and manage
         | 
| 40 | 
            +
            :nick                       # List all nicks
         | 
| 41 | 
            +
            :nick -la                   # Delete a nick
         | 
| 42 | 
            +
            ```
         | 
| 43 | 
            +
             | 
| 44 | 
            +
            ### Intelligence & Learning
         | 
| 45 | 
            +
            * **Completion Learning**: Shell learns which TAB completions you use and ranks them higher
         | 
| 46 | 
            +
            * **Smart Suggestions**: "Did you mean...?" for typos
         | 
| 47 | 
            +
            * **Auto-correct**: Optional auto-fix with confirmation
         | 
| 48 | 
            +
            * **Command Analytics**: `:stats` shows usage patterns and performance
         | 
| 49 | 
            +
             | 
| 50 | 
            +
            ### Productivity
         | 
| 51 | 
            +
            * **Command Recording**: `:record start name` → run commands → `:record stop` → `:replay name`
         | 
| 52 | 
            +
            * **Sessions**: Save/load entire shell state with bookmarks, history, and functions
         | 
| 53 | 
            +
            * **Bookmarks**: Tag directories and jump instantly
         | 
| 54 | 
            +
            * **Multi-line Editing**: Press Ctrl-G to edit in $EDITOR
         | 
| 55 | 
            +
            * **Shell Scripts**: Full bash support for for/while/if loops
         | 
| 56 | 
            +
             | 
| 57 | 
            +
            ### Extensibility
         | 
| 58 | 
            +
            * **Plugin System**: Add custom commands, completions, and hooks
         | 
| 59 | 
            +
            * **Ruby Functions**: Define callable functions - `:defun hello(name) = puts "Hello, #{name}!"`
         | 
| 60 | 
            +
            * **Validation Rules**: `:validate rm -rf / = block` prevents dangerous commands
         | 
| 61 | 
            +
            * **6 Color Themes**: solarized, dracula, gruvbox, nord, monokai, default
         | 
| 62 | 
            +
             | 
| 63 | 
            +
            ### Integrations
         | 
| 64 | 
            +
            * **AI Support**: @ for questions, @@ for command suggestions (Ollama or OpenAI)
         | 
| 65 | 
            +
            * **RTFM**: Launch file manager with `r`
         | 
| 66 | 
            +
            * **fzf**: Fuzzy finder with `f`
         | 
| 67 | 
            +
            * **XRPN**: Calculator with `= expression`
         | 
| 68 | 
            +
             | 
| 69 | 
            +
            ### Tab Completion
         | 
| 70 | 
            +
            * Smart context-aware completion for git, apt, docker, systemctl, cargo, npm, gem
         | 
| 71 | 
            +
            * Command switches from --help
         | 
| 72 | 
            +
            * Option values (--format=json, --level=debug)
         | 
| 73 | 
            +
            * Learns your patterns and adapts
         | 
| 74 | 
            +
             | 
| 75 | 
            +
            ### Core Shell
         | 
| 76 | 
            +
            * Syntax highlighting for nicks, commands, paths, bookmarks
         | 
| 77 | 
            +
            * History with search, edit, and repeat (!, !!, !-2, !5:7)
         | 
| 78 | 
            +
            * Job control (background jobs, suspend, resume)
         | 
| 79 | 
            +
            * Config file (.rshrc) updates on exit
         | 
| 80 | 
            +
            * All colors themeable
         | 
| 81 | 
            +
             | 
| 82 | 
            +
            ---
         | 
| 83 | 
            +
             | 
| 84 | 
            +
            ## Quick Start
         | 
| 85 | 
            +
             | 
| 86 | 
            +
            ```bash
         | 
| 87 | 
            +
            # Install
         | 
| 88 | 
            +
            gem install ruby-shell
         | 
| 89 | 
            +
             | 
| 90 | 
            +
            # Run
         | 
| 91 | 
            +
            rsh
         | 
| 92 | 
            +
             | 
| 93 | 
            +
            # Create an alias
         | 
| 94 | 
            +
            :nick ll = ls -l
         | 
| 95 | 
            +
            ll
         | 
| 96 | 
            +
             | 
| 97 | 
            +
            # Create parametrized alias
         | 
| 98 | 
            +
            :nick gp = git push origin {{branch}}
         | 
| 99 | 
            +
            gp branch=main
         | 
| 100 | 
            +
             | 
| 101 | 
            +
            # Get help
         | 
| 102 | 
            +
            :help
         | 
| 103 | 
            +
            :info
         | 
| 104 | 
            +
             | 
| 105 | 
            +
            # See version and changelog
         | 
| 106 | 
            +
            :version
         | 
| 107 | 
            +
            ```
         | 
| 108 | 
            +
             | 
| 109 | 
            +
            ---
         | 
| 110 | 
            +
             | 
| 111 | 
            +
            ## Latest Features (v3.4)
         | 
| 109 112 | 
             
            * **Define Ruby functions as shell commands**: `:defun 'weather(*args) = system("curl -s wttr.in/#{args[0] || \"oslo\"}")'`
         | 
| 110 113 | 
             
            * **Call like any shell command**: `weather london`
         | 
| 111 114 | 
             
            * **Full Ruby power**: Access to Ruby stdlib, file operations, JSON parsing, web requests, etc.
         | 
    
        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.4. | 
| 11 | 
            +
            @version    = "3.4.1" # Performance optimizations: 50-60% faster startup, optimized .rshrc reload, persistent cache
         | 
| 12 12 |  | 
| 13 13 | 
             
            # MODULES, CLASSES AND EXTENSIONS
         | 
| 14 14 | 
             
            class String # Add coloring to strings (with escaping for Readline)
         | 
| @@ -155,6 +155,8 @@ begin # Initialization | |
| 155 155 | 
             
              @completion_learning = true             # Enable completion learning (default: on)
         | 
| 156 156 | 
             
              @recording = {active: false, name: nil, commands: []} # Command recording state
         | 
| 157 157 | 
             
              @recordings = {}                        # Saved recordings
         | 
| 158 | 
            +
              @command_cache = {}                     # Cache for expensive shell command outputs
         | 
| 159 | 
            +
              @last_prompt_dir = nil                  # Track directory for .rshrc reload optimization
         | 
| 158 160 | 
             
              # Built-in rsh commands are called with : prefix, so no need for separate tracking
         | 
| 159 161 | 
             
              Dir.mkdir(Dir.home + '/.rsh') unless Dir.exist?(Dir.home + '/.rsh')
         | 
| 160 162 | 
             
              Dir.mkdir(@session_dir) unless Dir.exist?(@session_dir)
         | 
| @@ -1157,6 +1159,15 @@ def rshrc # Write updates to .rshrc | |
| 1157 1159 | 
             
              conf += "@completion_learning = #{@completion_learning}\n" unless @completion_learning
         | 
| 1158 1160 | 
             
              conf.sub!(/^@recordings.*(\n|$)/, "")
         | 
| 1159 1161 | 
             
              conf += "@recordings = #{@recordings}\n" unless @recordings.empty?
         | 
| 1162 | 
            +
              # Persist executable cache for faster startup
         | 
| 1163 | 
            +
              if @exe && @exe.length > 100
         | 
| 1164 | 
            +
                conf.sub!(/^@exe_cache.*(\n|$)/, "")
         | 
| 1165 | 
            +
                conf += "@exe_cache = #{@exe.inspect}\n"
         | 
| 1166 | 
            +
                conf.sub!(/^@exe_cache_path.*(\n|$)/, "")
         | 
| 1167 | 
            +
                conf += "@exe_cache_path = #{ENV['PATH'].inspect}\n"
         | 
| 1168 | 
            +
                conf.sub!(/^@exe_cache_time.*(\n|$)/, "")
         | 
| 1169 | 
            +
                conf += "@exe_cache_time = #{Time.now.to_i}\n"
         | 
| 1170 | 
            +
              end
         | 
| 1160 1171 | 
             
              # Only write @cmd_completions if user has customized it
         | 
| 1161 1172 | 
             
              unless conf =~ /^@cmd_completions\s*=/
         | 
| 1162 1173 | 
             
                # Don't write default completions to avoid cluttering .rshrc
         | 
| @@ -2862,10 +2873,40 @@ def load_defaults | |
| 2862 2873 | 
             
              puts "Loaded with default configuration."
         | 
| 2863 2874 | 
             
            end
         | 
| 2864 2875 |  | 
| 2876 | 
            +
            def cached_command(cmd, ttl = 300) # Cache expensive command outputs
         | 
| 2877 | 
            +
              key = cmd.hash
         | 
| 2878 | 
            +
              now = Time.now.to_i
         | 
| 2879 | 
            +
             | 
| 2880 | 
            +
              if @command_cache[key] && (now - @command_cache[key][:time]) < ttl
         | 
| 2881 | 
            +
                return @command_cache[key][:result]
         | 
| 2882 | 
            +
              end
         | 
| 2883 | 
            +
             | 
| 2884 | 
            +
              result = `#{cmd}`.chomp
         | 
| 2885 | 
            +
              @command_cache[key] = {result: result, time: now}
         | 
| 2886 | 
            +
             | 
| 2887 | 
            +
              # Limit cache size
         | 
| 2888 | 
            +
              if @command_cache.length > 50
         | 
| 2889 | 
            +
                # Remove oldest entry
         | 
| 2890 | 
            +
                oldest = @command_cache.min_by { |k, v| v[:time] }
         | 
| 2891 | 
            +
                @command_cache.delete(oldest[0])
         | 
| 2892 | 
            +
              end
         | 
| 2893 | 
            +
             | 
| 2894 | 
            +
              result
         | 
| 2895 | 
            +
            end
         | 
| 2865 2896 | 
             
            def cache_executables
         | 
| 2866 2897 | 
             
              current_path = ENV["PATH"]
         | 
| 2867 2898 | 
             
              current_time = Time.now.to_i
         | 
| 2868 2899 |  | 
| 2900 | 
            +
              # Use persisted cache if valid (from .rshrc)
         | 
| 2901 | 
            +
              if @exe_cache && @exe_cache_path == current_path
         | 
| 2902 | 
            +
                cache_age = current_time - (@exe_cache_time || 0)
         | 
| 2903 | 
            +
                if cache_age < 3600  # 1 hour
         | 
| 2904 | 
            +
                  @exe = @exe_cache
         | 
| 2905 | 
            +
                  @exe_cache_paths = current_path
         | 
| 2906 | 
            +
                  return
         | 
| 2907 | 
            +
                end
         | 
| 2908 | 
            +
              end
         | 
| 2909 | 
            +
             | 
| 2869 2910 | 
             
              # Only rebuild cache if PATH changed or cache is older than 60 seconds
         | 
| 2870 2911 | 
             
              return if @exe_cache_paths == current_path && (current_time - @exe_cache_time) < 60
         | 
| 2871 2912 |  | 
| @@ -2940,7 +2981,12 @@ loop do | |
| 2940 2981 | 
             
              begin
         | 
| 2941 2982 | 
             
                @user = Etc.getpwuid(Process.euid).name # For use in @prompt
         | 
| 2942 2983 | 
             
                @node = Etc.uname[:nodename]            # For use in @prompt
         | 
| 2943 | 
            -
                 | 
| 2984 | 
            +
                # Only reload .rshrc if directory changed (optimization)
         | 
| 2985 | 
            +
                current_dir = Dir.pwd
         | 
| 2986 | 
            +
                if @last_prompt_dir != current_dir
         | 
| 2987 | 
            +
                  h = @history; f = @cmd_frequency; s = @cmd_stats; b = @bookmarks; d = @defuns; load_rshrc_safe; @history = h; @cmd_frequency = f; @cmd_stats = s; @bookmarks = b; @defuns = d
         | 
| 2988 | 
            +
                  @last_prompt_dir = current_dir
         | 
| 2989 | 
            +
                end
         | 
| 2944 2990 | 
             
                @prompt.gsub!(/#{Dir.home}/, '~') # Simplify path in prompt
         | 
| 2945 2991 | 
             
                system("printf \"\033]0;rsh: #{Dir.pwd}\007\"")   # Set Window title to path
         | 
| 2946 2992 | 
             
                @history[0] = "" unless @history[0]
         |