2012-08-28 55 views
1

我有一个程序,可以接受大量的有效参数。其中许多都有共同的前缀,并且处于目录树结构中。这些选项通常不存在,有些目录可以使用或不使用斜线,但有些只能使用斜线。bash可编程选项卡完成增量目录完成

如果我已经有bash补,显示我的选择列表,然后为我按改变了命令行和下面部分完成参数:

$ myprog <TAB><TAB> 
foo 
somedirectory/a 
somedirectory/b 
somedirectory/c 
zibble 
zibble/a 
zibble/b 
zibble/c 
$ myprog so<TAB> 
$ myprog somedirectory<TAB><TAB> 
somedirectory/a 
somedirectory/b 
somedirectory/c 
$ myprog somedirectory/<TAB><TAB> 
a 
b 
c 

我如何改变它的bash完成,这是否像普通的文件/目录完成:

$ myprog <TAB><TAB> 
foo 
somedirectory/ 
zibble 
zibble/ 
$ myprog so<TAB> 
$ myprog somedirectory/<TAB><TAB> 
a 
b 
c 

$ myprog <TAB><TAB> 
foo 
somedirectory/ 
zibble 
zibble/ 
$ myprog zi<TAB> 
$ myprog zibble<TAB><TAB> 
zibble 
zibble/ 
$ myprog zibble/<TAB><TAB> 
a 
b 
c 
+0

你怎么确定'zibble'应该没有'/'附加项,但'只有'/'有些目录'? – geirha

+0

如果有一个名为“zibble”的目标,那么它应该有没有/的额外条目,而如果有以“zibble /”作为前缀的目标,带有/的条目应该在那里。我已经用Debian的bash完成补丁解决了这个问题。 – codeshot

回答

0

最关键的是刚刚返回的应该表现得像目录完成字补之前添加此行:[[ $COMPREPLY == */ ]] && compopt -o nospace

通过compgen的COMPREPLY阵中唯一的建议符合当前字被完成后运行此。如果有多个建议,则只会部分完成,不会添加任何空间(标准行为)。如果只有一个建议,则用它来决定是否添加空格。

现在,如果你修剪zibble/bash下的所有文件名,当它发现zibble /是唯一匹配正在完成的单词时,不会添加空格分隔符。

下面是针对debian http://anonscm.debian.org/gitweb/?p=bash-completion/bash-completion.git的bash补丁的修补程序 - 因此修补程序环境中存在一些奇怪的内容。

它使用git的应用“混帐”版本控制程序的命令适用干净针对这个版本:http://anonscm.debian.org/gitweb/?p=bash-completion/bash-completion.git;a=commit;h=2897e62fe7e535eb048f7e08f03ac3fbc3a84fa5

diff --git a/completions/make b/completions/make 
index aa19b24..345deea 100644 
--- a/completions/make 
+++ b/completions/make 
@@ -1,11 +1,66 @@ 
# bash completion for GNU make        -*- shell-script -*- 

+function _make_target_extract_script() 
+{ 
+ local prefix=$(printf "%s\n" "$1" | sed 's/[][\.*^$(){}?+|/]/\\&/g') 
+ 
+ cat <<EOF 
+ /^# Make data base/,/^# Files/d    # skip until files section 
+ /^# Not a target/,/^$/  d    # skip not target blocks 
+ /^${prefix}/,/^$/!   d    # skip anything user dont want 
+ 
+ # The stuff above here describes lines that are not 
+ # explicit targets or not targets other than special ones 
+ # The stuff below here decides whether an explicit target 
+ # should be output. 
+ 
+ /^# File is an intermediate prerequisite/ { 
+  s/^.*$//;x        # unhold target 
+  d           # delete line 
+ } 
+ 
+ /^$/ {          # end of target block 
+  x           # unhold target 
+  s/^(${prefix}[^:/]*\/).*:.*$/\1/p   # write targets for subdirs 
+  s/:.*$/ /p         # write complete targets 
+  d           # hide any bugs 
+ } 
+ 
+ /^[^#\t:%]+:/ {   # found target block 
+ 
+  /^\.PHONY/     d    # special target 
+  /^\.SUFFIXES/    d    # special target 
+  /^\.DEFAULT/    d    # special target 
+  /^\.PRECIOUS/    d    # special target 
+  /^\.INTERMEDIATE/   d    # special target 
+  /^\.SECONDARY/    d    # special target 
+  /^\.SECONDEXPANSION/  d    # special target 
+  /^\.DELETE_ON_ERROR/  d    # special target 
+  /^\.IGNORE/     d    # special target 
+  /^\.LOW_RESOLUTION_TIME/ d    # special target 
+  /^\.SILENT/     d    # special target 
+  /^\.EXPORT_ALL_VARIABLES/ d    # special target 
+  /^\.NOTPARALLEL/   d    # special target 
+  /^\.ONESHELL/    d    # special target 
+  /^\.POSIX/     d    # special target 
+  /^\.NOEXPORT/    d    # special target 
+  /^\.MAKE/     d    # special target 
+ 
+  /^[^a-zA-Z0-9]/    d    # convention for hidden tgt 
+ 
+  h           # hold target 
+  d           # delete line 
+ } 
+ 
+EOF 
+} 
+ 
_make() 
{ 
    local cur prev words cword split 
    _init_completion -s || return 

- local file makef makef_dir="." makef_inc i 
+ local file makef makef_dir=("-C" ".") makef_inc i 

    case $prev in 
     -f|--file|--makefile|-o|--old-file|--assume-old|-W|--what-if|\ 
@@ -49,7 +104,7 @@ _make() 
     for ((i=0; i < ${#words[@]}; i++)); do 
      if [[ ${words[i]} == [email protected](C|-directory) ]]; then 
       # eval for tilde expansion 
-    eval makef_dir=${words[i+1]} 
+    eval makef_dir=(-C "${words[i+1]}") 
       break 
      fi 
     done 
@@ -59,18 +114,17 @@ _make() 
     for ((i=0; i < ${#words[@]}; i++)); do 
      if [[ ${words[i]} == [email protected](f|-?(make)file) ]]; then 
       # eval for tilde expansion 
-    eval makef=${words[i+1]} 
+    eval makef=(-f "${words[i+1]}") 
       break 
      fi 
     done 

-  [[ -n $makef ]] && makef="-f ${makef}" 
-  [[ -n $makef_dir ]] && makef_dir="-C ${makef_dir}" 
+  COMPREPLY=($(compgen -W "$( 
+   make -npq "${makef[@]}" "${makef_dir[@]}" .DEFAULT 2>/dev/null | \ 
+   sed -n -r -f <(_make_target_extract_script "$cur") 
+  )" -- "$cur")) 

-  COMPREPLY=($(compgen -W "$(make -qp $makef $makef_dir 2>/dev/null | \ 
-   awk -F':' '/^[a-zA-Z0-9][^$#\/\t=]*:([^=]|$)/ \ 
-   {split($1,A,/ /);for(i in A)print A[i]}')" \ 
-   -- "$cur")) 
+  [[ $COMPREPLY == */ ]] && compopt -o nospace 

    fi 
} &&