2016-08-26 44 views
9

我使用的是PHP工具http://robo.li和n98-magerun.phar - 都是基於Sympfony的CLI組件。基於Symfony的自動完成功能可以打破SCP自動完成功能

當我使用這樣的自動完成腳本:

https://gist.github.com/caseyfw/51bdbcb37e5dfb91b74e 

#!/bin/sh 
function __robo_list_cmds() 
{ 
     robo list --raw | awk '{print $1}' | sort 
} 

function __robo_list_opts() 
{ 
    robo list --no-ansi | sed -e '1,/Options:/d' -e '/^$/,$d' -e 's/^ *//' -e 's/ .*//' | sort 
} 

_robo() 
{ 
    local cur="${COMP_WORDS[COMP_CWORD]}" 
    COMPREPLY=($(compgen -W "$(__robo_list_opts) $(__robo_list_cmds)" -- ${cur})) 
    return 0; 
} 

complete -o default -F _robo robo 
COMP_WORDBREAKS=${COMP_WORDBREAKS//:} 

它打破了scp命令的自動完成(通常在遠程服務器上完成的文件 - 但是這一點 - 不相關的 - 在地方ROBO完成,SCP中移除了命令中的主機名)

這是爲什麼?怎麼修?

編輯

基於答案,固定的版本是在這裏:

https://gist.github.com/amenk/d68f1fe54b156952ced621f771ff48ba

+2

這不會解決你的問題,但是注意:完成腳本是* sourced *(通常在'〜/ .bashrc'或'/ etc/bash.bashrc'中),所以shebang行是不重要的。如果*不被忽略,事情就會中斷,因爲'sh'不知道數組,但是你使用它們。 –

回答

3

這可能無關,與你的robo compspec。與scp關聯的_scp完成功能也不是。

這可能是由於您的COMP_WORDBREAKS=${COMP_WORDBREAKS//:}

您從分隔符列表中刪除了:。顯然_scp是足夠強大的行爲相同或不:作爲一個字詞分隔符。它返回相同的候選完成列表。但是當_scp只返回一個候選者以完成時,替換的令牌例如scp host:public_ht,是host:public_ht,而不是僅僅public_ht。證明:

$ _foobar() { COMPREPLY=bazcux; return 0; } 
$ complete -o default -F _foobar foobar 
$ echo $COMP_WORDBREAKS 
"'><=;|&(: 

如果你試圖完成foobar host:public_ht,你foobar host:bazcux因爲取代令牌只是public_ht。雖然有:

$ COMP_WORDBREAKS=${COMP_WORDBREAKS//:} 
$ echo $COMP_WORDBREAKS 
"'><=;|&(

,如果你試圖完成foobar host:public_ht,你foobar bazcux,因爲它是由bazcux取代了完整host:public_ht

解決您的問題的方法很可能是修改您的_robo完成功能,以免它不要求:不是字詞分隔符。喜歡的東西:

_stem() { 
    local lcur lprev 
    lcur="$cur" 
    stem="$lcur" 
    for ((i = cword - 1; i >= 0; i -= 1)); do 
     lprev="${words[i]}" 
     [[ $lcur == ":" ]] && [[ $lprev == ":" ]] && break 
     [[ $lcur != ":" ]] && [[ $lprev != ":" ]] && break 
     stem="$lprev$stem" 
     lcur="$lprev" 
    done 
} 

_robo() { 
    local cur prev words cword 
    _init_completion || return 
    local stem options 
    options=($(__robo_list_opts) $(__robo_list_cmds)) 
    COMPREPLY=() 
    _stem 
    COMPREPLY=($(compgen -W '${options[@]}' -- "$stem")) 
    [[ $stem =~ : ]] && stem=${stem%:*}: && COMPREPLY=(${COMPREPLY[@]#"$stem"}) 
    return 0 
} 

complete -o default -F _robo robo 

一個多(顯然)簡單的解決方案在於通過bash_completion庫的現有__reassemble_comp_words_by_ref函數替換上面的_stem功能:

_robo() { 
    local cur prev words cword 
    _init_completion || return 
    __reassemble_comp_words_by_ref ":" words cword 
    options=($(__robo_list_opts) $(__robo_list_cmds)) 
    COMPREPLY=($(compgen -W '${options[@]}' -- "$cur")) 
    return 0 
} 

complete -o default -F _robo robo 

所有這可能不是你想要什麼。我不知道robo.il,並且可能有許多改進將考慮更多的上下文來提出具體的完成。但這可能是一個起點。

+0

「解決您的問題可能是爲了適應您的_robo完成功能,以便它不要求:不是字詞分隔符。」這將如何工作?大致?它在哪裏需要這些斷詞? – Alex

+0

呵呵,關鍵是robo/symfony的命令是這樣的:'robo main:sub:subsubcommand'因此也許這就是wordseperator進入的原因。是否有可能只爲'robo'和'magerun'激活該字詞分隔符,而不是'scp'? – Alex

+1

@Alex不,我不認爲你可以按照每個命令專門設計「COMP_WORDBREAKS」,不幸的是。你真的必須實現一個更復雜的_robo函數來從COMP_CWORD開始向後解析COMP_WORDS數組,以構建main:sub:subsu,2)調用compgen來獲得所有的可能的完成,3)從它們中取出莖並返回結果。請注意,它們有兩種可能性:字級完成(在':'處停止,就像路徑完成停在'/'處)或完整的組完成。這是你的選擇。 –