about summary refs log tree commit diff
path: root/Functions/Zle/incremental-complete-word
blob: 8b8bded3975fa1df3bbb72c9530ac6b507ceb5a8 (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
# 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 post toolong
  local curcontext="${curcontext}" stop brk

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

  zstyle -s ":incremental" prompt pmpt ||
    pmpt='incremental (%c): %u%s  %l'
  zstyle -s ":incremental" stop-keys stop
  zstyle -s ":incremental" break-keys brk

  if zstyle -t ":incremental" 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
    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" \
                          "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
    if (( ! PENDING )); then
      lastl="$LBUFFER"
      lastr="$RBUFFER"
      [[ "$twid" = "$wid" ]] && comppostfuncs=( "$post[@]" )
      toolong=''
      zle $twid "$@"
      LBUFFER="$lastl"
      RBUFFER="$lastr"
      num=$_lastcomp[nmatches]
      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" \
                              "l:$toolong" "c:${_lastcomp[completer][2,-1]}"
      zle -R "$pstr"
    else
      zle -R
    fi
    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 messages'
    [[ compstate[list_lines]+BUFFERLINES+1 -gt LINES ]] && compstate[list]=''

    toolong='...'
  fi
}

incremental-complete-word "$@"