about summary refs log tree commit diff
path: root/Functions/Zle/incremental-complete-word
blob: c01bc4f6bbf6138d3c155b1393395cfe20a4236a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# Autoload this function, run `zle -N <func-name>' and bind <func-name>
# to a key.


# This allows incremental completion of a word.  After starting this
# command, a list of completion choices can be shown after every character
# you type, which you can delete with ^h or DEL.  RET will accept the
# completion so far.  You can hit TAB to do normal completion, ^g to
# abort back to the state when you started, and ^d to list the matches.
#
# This works only with the new function based completion system.

# The main widget function.

incremental-complete-word() {
  #emulate -L zsh
  unsetopt autolist menucomplete automenu # doesn't work well

  local key lbuf="$LBUFFER" rbuf="$RBUFFER" pmpt pstr word
  local lastl lastr wid twid num alt post toolong
  local curcontext="${curcontext}" stop brk

  [[ -z "$curcontext" ]] && curcontext=:::
  curcontext="incremental:${curcontext#*:}"

  zstyle -s ":completion:${curcontext}" prompt pmpt ||
    pmpt='incremental (%c): %u%s  %l'
  zstyle -s ":completion:${curcontext}" stop stop
  zstyle -s ":completion:${curcontext}" break brk

  if zstyle -t ":completion:${curcontext}" list; then
    wid=list-choices
    post=( icw-list-helper )
  else
    wid=complete-word
    post=()
  fi

  comppostfuncs=( "$post[@]" )
  zle $wid "$@"
  LBUFFER="$lbuf"
  RBUFFER="$rbuf"
  num=$_lastcomp[nmatches]
  if (( ! num )); then
    num="${_lastcomp[alternate_nmatches]}"
    alt=' -alt-'
  fi
  if (( ! num )); then
    word=''
    state='-no match-'
  elif [[ "${LBUFFER}${RBUFFER}" = *${_lastcomp[unambiguous]}* ]]; then
    word=''
    state='-no prefix-'
  else
    word="${_lastcomp[unambiguous]}"
    state=''
  fi
  zformat -f pstr "$pmpt" "u:${word}" "s:$state" "n:$num" "a:$alt" \
                          "l:$toolong" "c:${_lastcomp[completer][2,-1]}"
  zle -R "$pstr"
  read -k key

  while [[ '#key' -ne '#\\r' && '#key' -ne '#\\n' &&
           '#key' -ne '#\\C-g' ]]; do
    twid=$wid
    if [[ "$key" = ${~stop} ]]; then
      zle -U "$key"
      return
    elif [[ "$key" = ${~brk} ]]; then
      return
    elif [[ '#key' -eq '#\\C-h' || '#key' -eq '#\\C-?' ]]; then
      [[ $#LBUFFER -gt $#l ]] && LBUFFER="$LBUFFER[1,-2]"
    elif [[ '#key' -eq '#\\t' ]]; then
      zle complete-word "$@"
      lbuf="$LBUFFER"
      rbuf="$RBUFFER"
    elif [[ '#key' -eq '#\\C-d' ]]; then
      twid=list-choices
    else
      LBUFFER="$LBUFFER$key"
    fi
    lastl="$LBUFFER"
    lastr="$RBUFFER"
    [[ "$twid" = "$wid" ]] && comppostfuncs=( "$post[@]" )
    toolong=''
    zle $twid "$@"
    LBUFFER="$lastl"
    RBUFFER="$lastr"
    num=$_lastcomp[nmatches]
    if (( ! num )); then
      num="${_lastcomp[alternate_nmatches]}"
      alt=' -alt-'
    else
      alt=''
    fi
    if (( ! num )); then
      word=''
      state='-no match-'
    elif [[ "${LBUFFER}${RBUFFER}" = *${_lastcomp[unambiguous]}* ]]; then
      word=''
      state='-no prefix-'
    else
      word="${_lastcomp[unambiguous]}"
      state=''
    fi
    zformat -f pstr "$pmpt" "u:${word}" "s:$state" "n:$num" "a:$alt" \
                            "l:$toolong" "c:${_lastcomp[completer][2,-1]}"
    zle -R "$pstr"
    read -k key
  done

  if [[ '#key' -eq '#\\C-g' ]]; then
    LBUFFER="$lbuf"
    RBUFFER="$rbuf"
  fi
  zle -Rc
}

# Helper function used as a completion post-function used to make sure that
# the list of matches in only shown if it fits on the screen.

icw-list-helper() {

  # +1 for the status line we will add...

  if [[ compstate[list_lines]+BUFFERLINES+1 -gt LINES ]]; then
    compstate[list]='list explanations'
    if [[ compstate[list_lines]+BUFFERLINES+1 -gt LINES ]]; then
      compstate[list]=''
      compstate[force_list]=yes
    fi
    toolong='...'
  fi
}

incremental-complete-word "$@"