繁体   English   中英

bash可编程选项卡完成,带有增量目录完成

[英]bash programmable tab completion with incremental directory completion

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

如果我已经有了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

关键是在返回补全字样的单词之前添加此行,该单词的行为应类似于目录[[ $COMPREPLY == */ ]] && compopt -o nospace[[ $COMPREPLY == */ ]] && compopt -o nospace

通过在compgen之后运行此命令,COMPREPLY数组中的唯一建议与正在完成的当前单词匹配。 如果有多个建议,它将仅部分完成,并且不会添加任何空间(标准行为)。 如果只有一个建议,那么它将用于决定是否添加空格。

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

这是一个针对Debian的bash完成的补丁程序, http ://anonscm.debian.org/gitweb/ ? p=bash-completion/bash-completion.git-因此,补丁程序上下文中有些奇怪的东西。

使用“ git”版本控制程序的git apply命令,可以完全针对该版本进行应用: 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]} == -@(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]} == -@(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
 } &&

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM