#compdef rails # ------------------------------------------------------------------------------ # Copyright (c) 2016 Github zsh-users - https://github.com/zsh-users # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # * Neither the name of the zsh-users nor the # names of its contributors may be used to endorse or promote products # derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # DISCLAIMED. IN NO EVENT SHALL ZSH-USERS BE LIABLE FOR ANY # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # ------------------------------------------------------------------------------ # Description # ----------- # # Completion script for Ruby on Rails (https://rubyonrails.org/). # # ------------------------------------------------------------------------------ # Authors # ------- # # * Kazuya Takeshima (https://github.com/mitukiii) # # ------------------------------------------------------------------------------ _rails() { local context state state_descr line curcontext="$curcontext" typeset -A opt_args local -a runtime_options rails_options runtime_options=( '(- *)'{-h,--help}'[Show this help message and quit]' '(- *)'{-v,--version}'[Show Rails version and quit]' ) runtime_options=( '(-f --force)'{-f,--force}'[Overwrite files that already exist]' '(-p --pretend)'{-p,--pretend}'[Run but do not make any changes]' '(-q --quiet)'{-q,--quiet}'[Suppress status output]' '(-s --skip)'{-s,--skip}'[Skip files that already exist]' ) local ret=1 _arguments -C \ $rails_options \ '1: :_rails_subcommands' \ '*:: :->command' && ret=0 case "$state" in (command) case $words[1] in (new) _rails_new && ret=0 ;; (generate|g|destroy|d) _rails_generate && ret=0 ;; (console|c) _arguments \ '(- *)'{-h,--help}'[Show this help message and quit]' \ '(-e --environment)'{-e,--environment=}'[The environment to run "console" in]:env:(test development production)' \ '(-s --sandbox)'{-s,--sandbox}'[Rollback database modifications on exit]' \ && ret=0 ;; (server|s) _arguments \ '(- *)'{-h,--help}'[Show this help message and quit]' \ '(-e --environment)'{-e,--environment=}'[The environment to run "server" in]:env:(test development production)' \ '(-p --port)'{-p,--port}'[Run Rails on the specified port]:port' \ '(-b --binding)'{-b,--binding=}'[Bind Rails to the specified IP]:binding' \ '(-c --config)'{-c,--config=}'[Use a custom rackup configuration]:config file:_files -g "*.ru"' \ '(-d --daemon)'{-d,--daemon}'[Run server as a Daemon]' \ '(-u --using)'{-u,--using=}'[Specify the Rack server used to run the application]:server:(thin puma webrick)' \ '(-P --pid)'{-P,--pid=}'[Specify the PID file]:pid file:_files -g "*.pid"' \ '(-C --dev-caching --no-dev-caching)'{-C,--dev-caching}'[Perform caching in development]' \ '(-C --dev-caching --no-dev-caching)--no-dev-caching[Not perform caching in development]' \ '--early-hints[Enable HTTP/2 early hints]' \ '(--log-to-stdout --no-log-to-stdout)--log-to-stdout[Log to stdout]' \ '(--log-to-stdout --no-log-to-stdout)--no-log-to-stdout[Not log to stdout]' \ && ret=0 ;; (dbconsole|db) _arguments \ '(- *)'{-h,--help}'[Show this help message and quit]' \ '(-e --environment)'{-e,--environment=}'[The environment to run "server" in]:env:(test development production)' \ '(-p --include-password)'{-p,--include-password}'[Automatically provide the password from database.yml]' \ '--mode=[Automatically put the sqlite3 database in the specified mode]:mode:(html list line column)' \ '(--header --no-header)--header[Display header]' \ '(--header --no-header)--no-header[Not display header]' \ '(--db --database)'{--db=,--database=}'[Specify the database to use]:database:_files' \ && ret=0 ;; esac ;; esac return ret } (( $+functions[_rails_subcommands] )) || _rails_subcommands() { local -a commands _rails_is_in_app if (( $? == 1 )); then # is not in rails app directory commands=( new'[Create a new Rails application]' ) else commands=( {generate,g}'[Generate new code]' {console,c}'[Start the Rails console]' {server,s}'[Start the Rails server]' {dbconsole,db}'[Start a console for the database specified in config/database.yml]' {destroy,d}'[Remove code generated by "bin/rails generates"]' plugin'[Install a plugin]' {runner,r}'[Run a piece of code in the application environment]' {test,t}'[Run tests]' ) fi _values 'command' $commands } # rails new (( $+functions[_rails_new] )) || _rails_new() { local ret=1 _arguments \ $runtime_options \ $rails_options \ --skip-namespace'[Skip namespace]' \ '(-n --name)'{-n,--name=}'[Name of the app]:name' \ '(-r --ruby)'{-r,--ruby=}'[Path to the Ruby binary of your choice]:path:_files' \ '(-b --builder)'{-b,--builder=}'[Path to a application builder(can be a filesystem path or URL)]: :_rails_path_or_url' \ '(-m --template)'{-m,--template=}'[Path to an application template(can be a filesystem path or URL)]: :_rails_path_or_url' \ '(-d --database)'{-d,--database=}'[Preconfigure for selected database]:database:(mysql trilogy oracle postgresql sqlite3 frontbase ibm_db sqlserver jdbcmysql jdbcsqlite3 jdbcpostgresql jdbc)' \ --skip-gemfile"[Don't create a Gemfile]" \ --skip-bundle"[Don't run bundle install]" \ '(-G --skip-git)'{-G,--skip-git}'[Skip git init]' \ --skip-docker'[Skip Dockerfile]' \ --skip-keeps'[Skip source control .keep files]' \ '(-M --skip-action-mailer)'{-M,--skip-action-mailer}'[Skip Action Mailder files]' \ --skip-action-mailbox'[Skip Action Mailbox gem]' \ --skip-action-text'[Skip Action Text gem]' \ '(-O --skip-active-record)'{-O,--skip-active-record}'[Skip Active Record files]' \ --skip-active-job'[Skip Active Job]' \ --skip-active-storage'[Skip Active Storage files]' \ '(-C --skip-action-cable)'{-C,--skip-action-cable}'[Skip Action Cable files]' \ '(-A --skip-asset-pipeline)'{-A,--skip-asset-pipeline}'[Skip asset pipeline]' \ '(-a --asset-pipeline)'{-a,--asset-pipeline=}'[Choose your asset pipeline]:asset pipeline:(sprockets propshaft)' \ '(-J --skip-js)'{-J,--skip-js}'[Skip JavaScript files]' \ --skip-hotwire'[Skip Hotwire integration]' \ --skip-jbuilder'[Skip jbuilder gem]' \ '(-T --skip-test)'{-T,--skip-test}'[Skip test files]' \ --skip-system-test'[Skip system test files]' \ --skip-bootsnap'[Skip bootsnap gem]' \ --skip-dev-gems'[Skip development gems(e.g. web-console)]' \ --dev'[Setup the application with Gemfile pointing to your Rails checkout]' \ --edge'[Setup the application with Gemfile pointing to Rails repository]' \ --master'[Set up the application with Gemfile pointing to Rails repository main branch]' \ --rc='[Path to file containing extra configuration options for rails command]:rc:_files' \ --api'[Preconfigure smaller stack for API only apps]' \ --minimal'[Preconfigure a minimal rails app]' \ '(-j --js)'{-j,--js=}'[Choose JavaScript approach]:javascript:(importmap bun webpack esbuild rollup)' \ '(-c --css)'{-c,--css=}'[Choose CSS processor]:css processor:(tailwind bootstrap bulma postcss sass)' \ '(-B --skip-bundle)'{-B,--skip-bundle}"[Don't run bundle install]" \ --skip-decrypted-diffs"[Don't configure git to show decrypted diffs of encrypted credentials]" \ ':app path:_directories' && ret=0 return ret } # rails generate (( $+functions[_rails_generate] )) || _rails_generate() { local ret=1 _arguments -C \ '(- *)'{-h,--help}"[Print generator's options and usage]" \ $runtime_options \ '1:generator:_rails_generate_generator' \ '*:: :->generate' && ret=0 case "$state" in (generate) local -a opts opts=( '(- *)'{-h,--help}'[Show this help message and quit]' $runtime_options '--skip-namespace[Skip namespace]' '--skip-collision-check[Skip collision check]' ) case $words[1] in (application_record|migration|model|resource|scaffold|scaffold_controller) opts+=( '(-o --orm)'{-o,--orm=}'[ORM to be invoked]:orm:(active_record)' ) ;| (channel) opts+=( '--no-assets[Not generate assets]' ) ;| (controller|resource|scaffold|scaffold_controller) opts+=( '--skip-routes[Do not add routes to config/routes.rb]' '--no-helper[Not generate helper]' ) ;| (controller|job|model|resource|scaffold) opts+=( '--parent=[The parent class for the generated controler]:parent class' ) ;| (controler|mailer|resource|scaffold|scaffold_controller) opts+=( '(-e --template-engine)'{-e,--template-engine=}'[Template engine to be invoked]:engine:(erb)' ) ;| (channel|controller|generator|helper|job|mailbox|mailer|model|scaffold|scaffold_controller) opts+=( '(-t --test-framework)'{-t,--test-framework=}'[Test framework to be invoked]:test_framework:(test_unit)' ) ;| (generator|test_unit:channel) opts+=( '--no-namespace[Not generate namespace generate]' ) ;| (integration_test) opts+=( '--integration-tool=[Integration tool to be invoked]:tool:(test_unit)' ) ;| (jbuilder|resource|scaffold|scaffold_controller) opts+=( '--model-name=[ModelName to be used]:name' ) ;| (jbuilder|model|resource|scaffold|scaffold_controller) opts+=( '--force-plural[Do not singularize the model name]' ) ;| (jbuilder|migration|model|resource|scaffold_controller) opts+=( '--no-timestamps[Not generate timestamps]' ) ;| (job) opts+=( '--queue=[The queue name for the generated job]:name' ) ;| (migration|model|resource|scaffold) opts+=( '--primary-key-type=[The type for primary key]' '(--db --database)'{--db,--database=}'[The database for your migration]:db' ) ;| (model|resource|scaffold) opts+=( '--no-migration[Not generate migration]' '--no-indexes[Not add indexes for references and belongs_to columns]' '--no-fixture[Not generate fixture]' '(-r --fixture-replacement)'{-r,--fixture-replacement=}'[Fixture replacement to be invoked]:fixture' ) ;| (resource) opts+=( '(-c --resource-controller)'{-c,--resource-controller=}'[Resource controller to be invoked]:controller:(controller)' '(-a --actions)'{-a,--actions=}'[Actions for the source controller]:action' ) ;| (resource|scaffold|scaffold_controller) opts+=( '--no-resource-route[Not generate resource route]' ) ;| (scaffold) opts+=( '(-c --scaffold-controller)'{-c,--scaffold-controller=}'[Scaffold controller to be invoked]:controller:(scaffold_controller)' ) ;| (scaffold|scaffold_controller) opts+=( '--api[Generate API-only controller and tests, with no view templates]' '--no-jbuilder[Not generate jbuilder]' ) ;| (scaffold|scaffold_controller|system_test) opts+=( '--system-tests=[System test framework to be invoked]:framework:(test_unit)' ) ;| (stimulus) opts+=( '--skip-manifest[Do not update the stimulus manifest]' ) ;| esac _arguments $opts && ret=0 ;; esac return ret } (( $+functions[_rails_generate_generator] )) || _rails_generate_generator() { local -a generators=( # rails application_record benchmark channel controller generator helper integration_test jbuilder job mailbox mailer migration model resource scaffold scaffold_controller system_test task # active record "active_record\\:application_record" "active_record\\:multi_db" # Stimulus stimulus # TestUnit "test_unit\\:channel" "test_unit\\:generator" "test_unit\\:install" "test_unit\\:mailbox" "test_unit\\:plugin" ) _values 'generators' $generators } __rails_setup_generators_options() { local -a runtime_options __rails_setup_runtime_options generators_options=( $runtime_options --skip-namespace'[Skip namespace (affects only isolated applications)]' --old-style-hash"[Force using old style hash (:foo => 'bar') on Ruby >= 1.9]" ) } __rails_setup_model_generators_options() { local -a generators_options __rails_setup_generators_options model_generators_options=( $generators_options '(-o --orm)'{-o,--orm=}'[Orm to be invoked]:orm' ) } __rails_setup_resource_generators_options() { local -a model_generators_options __rails_setup_model_generators_options resource_generators_options=( $model_generators_options --force-plural'[Forces the use of a plural ModelName]' --resource-route'[Indicates when to generate resource route]: :__rails_boolean' ) } __rails_boolean() { _values 'boolean' 'true' 'false' } __rails_migration_fields() { if compset -P '*:*:'; then _values 'index' 'index' 'uniq' else if compset -P '*:'; then _values -s ':' 'type' 'string' 'text' 'integer' 'float' 'decimal' 'datetime' 'timestamp' 'time' 'date' 'binary' 'boolean' 'references' else _guard '[[:alnum:]_]#' 'field' fi fi } _rails_plugin() { local context state line curcontext="$curcontext" if (( CURRENT > 2 )); then (( CURRENT-- )) shift words _call_function - "_rails_plugin_${words[1]}" || _nothing else __rails_plugin_commands fi } __rails_plugin_commands() { _values 'plugin command' \ install'[Install plugin(s) from known repositories or URLs]' \ remove'[Uninstall plugins]' \ new } _rails_plugin_install() { _arguments \ '(-x --externals)'{-x,--externals}'[Use svn:externals to grab the plugin. Enables plugin updates and plugin versioning]' \ '(-o --checkout)'{-o,--checkout}'[Use svn checkout to grab the plugin. Enables updating but does not add a svn:externals entry]' \ '(-e --export)'{-e,--export}'[Use svn export to grab the plugin. Exports the plugin, allowing you to check it into your local repository. Does not enable updates or add an svn:externals entry]' \ '(-q --quiet)'{-q,--quiet}'[Suppresses the output from installation. Ignored if -v is passed (rails plugin -v install ...)]' \ '(-r --revision)'{-r,--revision=}'[Checks out the given revision from subversion or git. Ignored if subversion/git is not used]:revision' \ '(-f --force)'{-f,--force}"[Reinstalls a plugin if it's already installed]" \ '*:plugin:_urls' } _rails_plugin_remove() { local -a plugins plugins=($(_call_program rails_plugins ls -1 vendor/plugins)) _describe -t plugins 'plugin' plugins } _rails_plugin_new() { _rails_new } _rails_runner() { local context state line curcontext="$curcontext" _arguments -C \ '(- *)'{-h,--help}'[Show this help message]' \ '(-e --environment)'{-e,--environment=}'[Specifies the environment for the runner to operate under (test/development/production)]:name:(test development production)' \ ': :->code_or_path' case "$state" in code_or_path) _alternative \ 'files:filename:_files -g "*.rb"' \ 'codes:ruby code:_guard "^-*" "ruby code"' ;; esac } _rails_r() { _rails_runner } _rails_test() { local context state line curcontext="$curcontext" _arguments -C \ ': :->path' case "$state" in path) _alternative \ 'files:filename:_files -g "*.rb"' ;; esac } _rails_t() { _rails_test } # Utilities (( $+functions[_rails_is_in_app] )) || _rails_is_in_app() { local dir="$PWD" while [ -n "$dir" ]; do if [[ -f "${dir}/bin/rails" ]]; then return 0 fi dir="${dir/*}" done return 1 } (( $+functions[_rails_path_or_url] )) || _rails_path_or_url() { _alternative \ 'files:path:_files -g "*.rb"' \ 'url:url:_urls' } _rails "$@" # Local Variables: # mode: Shell-Script # sh-indentation: 2 # indent-tabs-mode: nil # sh-basic-offset: 2 # End: # vim: ft=zsh sw=2 ts=2 et