diff --git a/README.md b/README.md index e6bd2b3f0..a1e58cfa6 100644 --- a/README.md +++ b/README.md @@ -96,6 +96,7 @@ complement existing completion scripts that ship with git. * [hub bash completion](https://github.com/github/hub/blob/master/etc/hub.bash_completion.sh) * [hub zsh completion](https://github.com/github/hub/blob/master/etc/hub.zsh_completion) +* [hub fish completion](https://github.com/github/hub/blob/master/etc/hub.fish_completion) Meta ---- diff --git a/commands/alias.go b/commands/alias.go index 641fff2f4..fa994f08e 100644 --- a/commands/alias.go +++ b/commands/alias.go @@ -102,7 +102,7 @@ func alias(command *Command, args *Args) { var eval string switch shell { case "fish": - eval = `function git --description 'Alias for hub, which wraps git to provide extra functionality with GitHub.' + eval = `function git --wraps hub --description 'Alias for hub, which wraps git to provide extra functionality with GitHub.' hub $argv end` case "csh", "tcsh": diff --git a/etc/README.md b/etc/README.md index 991de3e1e..a75b24df9 100644 --- a/etc/README.md +++ b/etc/README.md @@ -6,32 +6,37 @@ If you're using Homebrew, just run `brew install hub` and you should be all set ## bash -Open your `.bashrc` file if you're on Linux, or your `.bash_profile` if you're on OS X and add: +Open your `.bashrc` file if you're on Linux, or your `.bash_profile` if you're on macOS and add: ```sh if [ -f /path/to/hub.bash_completion ]; then - . /path/to/hub.bash_completion + . /path/to/hub.bash_completion fi ``` ## zsh -Create a new folder for completions: +Copy the file `etc/hub.zsh_completion` from the location where you downloaded +`hub` to the folder `~/.zsh/completions/` and rename it to `_hub`: ```sh mkdir -p ~/.zsh/completions +cp etc/hub.zsh_completion ~/.zsh/completions/_hub ``` -Copy the file `/etc/hub.zsh_completion` from the location where you downloaded `hub` to the folder `~/.zsh/completions/` and rename it to `_hub`: +Then add the following lines to your `.zshrc` file: ```sh -cp /path/to/etc/hub.zsh_completion ~/.zsh/completions/ \ - mv ~/.zsh/completions/hub.zsh_completion ~/.zsh/completions/_hub +fpath=(~/.zsh/completions $fpath) +autoload -U compinit && compinit ``` -Then add the following lines to your `.zshrc` file: +## fish + +Copy the file `etc/hub.fish_completion` from the location where you downloaded +`hub` to the folder `~/.config/fish/completions/` and rename it to `hub.fish`: ```sh -fpath=(~/.zsh/completions $fpath) -autoload -U compinit && compinit +mkdir -p ~/.config/fish/completions +cp etc/hub.fish_completion ~/.config/fish/completions/hub.fish ``` diff --git a/etc/hub.fish_completion b/etc/hub.fish_completion new file mode 100644 index 000000000..fcb32384f --- /dev/null +++ b/etc/hub.fish_completion @@ -0,0 +1,61 @@ +function __fish_hub_needs_command + set cmd (commandline -opc) + if [ (count $cmd) -eq 1 ] + return 0 + else + return 1 + end +end + +function __fish_hub_using_command + set cmd (commandline -opc) + if [ (count $cmd) -gt 1 ] + if [ $argv[1] = $cmd[2] ] + return 0 + end + end + return 1 +end + +complete -f -c hub -n '__fish_hub_needs_command' -a alias -d "show shell instructions for wrapping git" +complete -f -c hub -n '__fish_hub_needs_command' -a browse -d "browse the project on GitHub" +complete -f -c hub -n '__fish_hub_needs_command' -a compare -d "lookup commit in GitHub Status API" +complete -f -c hub -n '__fish_hub_needs_command' -a create -d "create new repo on GitHub for the current project" +complete -f -c hub -n '__fish_hub_needs_command' -a fork -d "fork origin repo on GitHub" +complete -f -c hub -n '__fish_hub_needs_command' -a pull-request -d "open a pull request on GitHub" +complete -f -c hub -n '__fish_hub_needs_command' -a ci-status -d "display GitHub Status information for a commit" + +# alias +complete -f -c hub -n ' __fish_hub_using_command alias' -a 'bash zsh sh ksh csh fish' -d "output shell script suitable for eval" +# pull-request +complete -f -c hub -n ' __fish_hub_using_command pull-request' -s f -d "Skip the check for unpushed commits" +complete -f -c hub -n ' __fish_hub_using_command pull-request' -s -m -d "Use the first line of as pull request title, and the rest as pull request description" +complete -f -c hub -n ' __fish_hub_using_command pull-request' -s F -d "Read the pull request title and description from " +complete -f -c hub -n ' __fish_hub_using_command pull-request' -s o -d "Open the new pull request in a web browser" +complete -f -c hub -n ' __fish_hub_using_command pull-request' -l browse -d "Open the new pull request in a web browser" +complete -f -c hub -n ' __fish_hub_using_command pull-request' -s p -d "Push the current branch to before creating the pull request" +complete -f -c hub -n ' __fish_hub_using_command pull-request' -s b -d 'The base branch in "[OWNER:]BRANCH" format' +complete -f -c hub -n ' __fish_hub_using_command pull-request' -s h -d 'The head branch in "[OWNER:]BRANCH" format' +complete -f -c hub -n ' __fish_hub_using_command pull-request' -s a -d 'A comma-separated list of GitHub handles to assign to this pull request' +complete -f -c hub -n ' __fish_hub_using_command pull-request' -s M -d "Add this pull request to a GitHub milestone with id " +complete -f -c hub -n ' __fish_hub_using_command pull-request' -s l -d "Add a comma-separated list of labels to this pull request" +# fork +complete -f -c hub -n ' __fish_hub_using_command fork' -l no-remote -d "Skip adding a git remote for the fork" +# browse +complete -f -c hub -n ' __fish_hub_using_command browse' -s u -d "Print the URL instead of opening it" +complete -f -c hub -n ' __fish_hub_using_command browse' -s c -d "Put the URL in clipboard instead of opening it" +complete -f -c hub -n ' __fish_hub_using_command browse' -a '-- commits' -d 'commits' +complete -f -c hub -n ' __fish_hub_using_command browse' -a '-- contributors' -d 'contributors' +complete -f -c hub -n ' __fish_hub_using_command browse' -a '-- issues' -d 'issues' +complete -f -c hub -n ' __fish_hub_using_command browse' -a '-- pulls' -d 'pull requests' +complete -f -c hub -n ' __fish_hub_using_command browse' -a '-- wiki' -d 'wiki' +# compare +complete -f -c hub -n ' __fish_hub_using_command compare' -s u -d 'Print the URL instead of opening it' +# create +complete -f -c hub -n ' __fish_hub_using_command create' -s o -d "Open the new repository in a web browser" +complete -f -c hub -n ' __fish_hub_using_command create' -l browse -d "Open the new repository in a web browser" +complete -f -c hub -n ' __fish_hub_using_command create' -s p -d "Create a private repository" +complete -f -c hub -n ' __fish_hub_using_command create' -s c -d "Put the URL of the new repository to clipboard instead of printing it." +complete -f -c hub -n ' __fish_hub_using_command create' -l copy -d "Put the URL of the new repository to clipboard instead of printing it." +# ci-status +complete -f -c hub -n ' __fish_hub_using_command ci-status' -s v -d "Print detailed report of all status checks and their URLs" diff --git a/features/alias.feature b/features/alias.feature index 598d4b2e5..c67ce0d8f 100644 --- a/features/alias.feature +++ b/features/alias.feature @@ -17,7 +17,7 @@ Feature: hub alias """ # Wrap git automatically by adding the following to ~/.config/fish/functions/git.fish: - function git --description 'Alias for hub, which wraps git to provide extra functionality with GitHub.' + function git --wraps hub --description 'Alias for hub, which wraps git to provide extra functionality with GitHub.' hub $argv end\n """ diff --git a/features/fish_completion.feature b/features/fish_completion.feature new file mode 100644 index 000000000..6cc7e6be0 --- /dev/null +++ b/features/fish_completion.feature @@ -0,0 +1,24 @@ +@completion +Feature: fish tab-completion + + Background: + Given my shell is fish + + Scenario: "pu" matches multiple commands including "pull-request" + When I type "git pu" and press + Then the command should not expand + When I press again + Then the completion menu should offer "pull push pull-request" + + Scenario: "ci-" expands to "ci-status" + When I type "git ci-" and press + Then the command should expand to "git ci-status" + + Scenario: Offers pull-request flags + When I type "git pull-request -" and press + When I press again + Then the completion menu should offer "-F -b -f -h -m -a -M -l -o --browse -p --help" unsorted + + Scenario: Browse to issues + When I type "git browse -- i" and press + Then the command should expand to "git browse -- issues" diff --git a/features/support/completion.rb b/features/support/completion.rb index 35f2421a3..560655baf 100644 --- a/features/support/completion.rb +++ b/features/support/completion.rb @@ -6,6 +6,7 @@ # - tmux # - bash # - zsh +# - fish # - git require 'fileutils' @@ -16,6 +17,7 @@ cpldir = tmpdir + 'completion' zsh_completion = File.expand_path('../../../etc/hub.zsh_completion', __FILE__) bash_completion = File.expand_path('../../../etc/hub.bash_completion.sh', __FILE__) +fish_completion = File.expand_path('../../../etc/hub.fish_completion', __FILE__) _git_prefix = nil @@ -44,16 +46,21 @@ link_completion = Proc.new { |from, name| raise ArgumentError, from.to_s unless File.exist?(from) + FileUtils.mkdir_p(cpldir) FileUtils.ln_s(from, cpldir + name, :force => true) } +create_file = lambda { |name, &block| + FileUtils.mkdir_p(File.dirname(name)) + File.open(name, 'w', &block) +} + setup_tmp_home = lambda { |shell| FileUtils.rm_rf(tmpdir) - FileUtils.mkdir_p(cpldir) case shell when 'zsh' - File.open(File.join(tmpdir, '.zshrc'), 'w') do |zshrc| + create_file.call(tmpdir + '.zshrc') do |zshrc| zshrc.write <<-SH PS1='$ ' for site_fn in /usr/{local/,}share/zsh/site-functions; do @@ -66,7 +73,7 @@ SH end when 'bash' - File.open(File.join(tmpdir, '.bashrc'), 'w') do |bashrc| + create_file.call(tmpdir + '.bashrc') do |bashrc| bashrc.write <<-SH PS1='$ ' alias git=hub @@ -74,6 +81,26 @@ . '#{bash_completion}' SH end + when 'fish' + create_file.call(tmpdir + '.config/fish/config.fish') do |fishcfg| + fishcfg.write <<-SH + function fish_prompt + echo '$ ' + end + SH + end + + create_file.call(tmpdir + '.config/fish/functions/git.fish') do |gitfn| + gitfn.write <<-SH + function git --wraps hub + hub $argv + end + SH + end + + completion_dest = tmpdir + '.config/fish/completions/hub.fish' + FileUtils.mkdir_p(File.dirname(completion_dest)) + FileUtils.ln_s(fish_completion, completion_dest) end } @@ -153,21 +180,41 @@ def tmux_wait_for_completion end end + def tmux_output_lines + tmux_pane_contents.split("\n").reject do |line| + line.start_with?('$') + end + end + def tmux_completion_menu tmux_wait_for_completion hash = {} - tmux_pane_contents.split("\n").grep(/^[^\$].+ -- /).each { |line| - item, description = line.split(/ +-- +/, 2) - hash[item] = description - } + if 'fish' == shell + tmux_output_lines.each do |line| + line.scan(/([^(]+)\((.+?)\)/).each do |flags, description| + flags.strip.split(/\s+/).each do |flag| + hash[flag] = description + end + end + end + else + tmux_output_lines.each do |line| + item, description = line.split(/ +-- +/, 2) + hash[item] = description if description + end + end hash end def tmux_completion_menu_basic tmux_wait_for_completion - tmux_pane_contents.split("\n").grep(/^[^\$]/).map {|line| - line.split(/\s+/) - }.flatten + if 'fish' == shell + tmux_completion_menu.keys + else + tmux_output_lines.flat_map do |line| + line.split(/\s+/) + end + end end }