Remove "encoding=utf-8" from Vim modelines
[awesome.git] / lib / awful / completion.lua.in
blob66158e145bb595607f690edf45f098aa7b70be48
1 ---------------------------------------------------------------------------
2 -- @author Julien Danjou <julien@danjou.info>
3 -- @author Sébastien Gross <seb-awesome@chezwam.org>
4 -- @copyright 2008 Julien Danjou, Sébastien Gross
5 -- @release @AWESOME_VERSION@
6 ---------------------------------------------------------------------------
8 -- Grab environment we need
9 local io = io
10 local os = os
11 local table = table
12 local math = math
13 local print = print
14 local pairs = pairs
15 local util = require("awful.util")
17 --- Completion module.
18 -- This module store a set of function using shell to complete commands name.
19 module("awful.completion")
21 -- mapping of command/completion function
22 local bashcomp_funcs = {}
23 local bashcomp_src = "@SYSCONFDIR@/bash_completion"
25 --- Enable programmable bash completion in awful.completion.bash at the price of
26 -- a slight overhead.
27 -- @param src The bash completion source file, /etc/bash_completion by default.
28 function bashcomp_load(src)
29 if src then bashcomp_src = src end
30 local c, err = io.popen("/usr/bin/env bash -c 'source " .. bashcomp_src .. "; complete -p'")
31 if c then
32 while true do
33 local line = c:read("*line")
34 if not line then break end
35 -- if a bash function is used for completion, register it
36 if line:match(".* -F .*") then
37 bashcomp_funcs[line:gsub(".* (%S+)$","%1")] = line:gsub(".*-F +(%S+) .*$", "%1")
38 end
39 end
40 c:close()
41 else
42 print(err)
43 end
44 end
46 local function bash_escape(str)
47 str = str:gsub(" ", "\\ ")
48 str = str:gsub("%[", "\\[")
49 str = str:gsub("%]", "\\]")
50 str = str:gsub("%(", "\\(")
51 str = str:gsub("%)", "\\)")
52 return str
53 end
55 --- Use shell completion system to complete command and filename.
56 -- @param command The command line.
57 -- @param cur_pos The cursor position.
58 -- @param ncomp The element number to complete.
59 -- @param shell The shell to use for completion (bash (default) or zsh).
60 -- @return The new command, the new cursor position, the table of all matches.
61 function shell(command, cur_pos, ncomp, shell)
62 local wstart = 1
63 local wend = 1
64 local words = {}
65 local cword_index = 0
66 local cword_start = 0
67 local cword_end = 0
68 local i = 1
69 local comptype = "file"
71 -- do nothing if we are on a letter, i.e. not at len + 1 or on a space
72 if cur_pos ~= #command + 1 and command:sub(cur_pos, cur_pos) ~= " " then
73 return command, cur_pos
74 elseif #command == 0 then
75 return command, cur_pos
76 end
78 while wend <= #command do
79 wend = command:find(" ", wstart)
80 if not wend then wend = #command + 1 end
81 table.insert(words, command:sub(wstart, wend - 1))
82 if cur_pos >= wstart and cur_pos <= wend + 1 then
83 cword_start = wstart
84 cword_end = wend
85 cword_index = i
86 end
87 wstart = wend + 1
88 i = i + 1
89 end
91 if cword_index == 1 then
92 comptype = "command"
93 end
95 local shell_cmd
96 if shell == "zsh" or (not shell and os.getenv("SHELL"):match("zsh$")) then
97 if comptype == "file" then
98 shell_cmd = "/usr/bin/env zsh -c 'local -a res; res=( " .. words[cword_index] .. "* ); print -l -- ${res[@]}'"
99 else
100 -- check commands, aliases, builtins, functions and reswords
101 shell_cmd = "/usr/bin/env zsh -c 'local -a res; "..
102 "res=( "..
103 "\"${(k)commands[@]}\" \"${(k)aliases[@]}\" \"${(k)builtins[@]}\" \"${(k)functions[@]}\" \"${(k)reswords[@]}\" "..
104 "); "..
105 "print -l -- ${(M)res[@]:#"..words[cword_index].."*}'"
107 else
108 if bashcomp_funcs[words[1]] then
109 -- fairly complex command with inline bash script to get the possible completions
110 shell_cmd = "/usr/bin/env bash -c 'source " .. bashcomp_src .. "; " ..
111 "__print_completions() { for ((i=0;i<${#COMPREPLY[*]};i++)); do echo ${COMPREPLY[i]}; done }; " ..
112 "COMP_WORDS=(" .. command .."); COMP_LINE=\"" .. command .. "\"; " ..
113 "COMP_COUNT=" .. cur_pos .. "; COMP_CWORD=" .. cword_index-1 .. "; " ..
114 bashcomp_funcs[words[1]] .. "; __print_completions'"
115 else
116 shell_cmd = "/usr/bin/env bash -c 'compgen -A " .. comptype .. " " .. words[cword_index] .. "'"
119 local c, err = io.popen(shell_cmd .. " | sort -u")
120 local output = {}
121 i = 0
122 if c then
123 while true do
124 local line = c:read("*line")
125 if not line then break end
126 if os.execute("test -d " .. line) == 0 then
127 line = line .. "/"
129 table.insert(output, bash_escape(line))
132 c:close()
133 else
134 print(err)
137 -- no completion, return
138 if #output == 0 then
139 return command, cur_pos
142 -- cycle
143 while ncomp > #output do
144 ncomp = ncomp - #output
147 local str = command:sub(1, cword_start - 1) .. output[ncomp] .. command:sub(cword_end)
148 cur_pos = cword_end + #output[ncomp] + 1
150 return str, cur_pos, output
153 --- Run a generic completion.
154 -- For this function to run properly the awful.completion.keyword table should
155 -- be fed up with all keywords. The completion is run against these keywords.
156 -- @param text The current text the user had typed yet.
157 -- @param cur_pos The current cursor position.
158 -- @param ncomp The number of yet requested completion using current text.
159 -- @param keywords The keywords table uised for completion.
160 -- @return The new match, the new cursor position, the table of all matches.
161 function generic(text, cur_pos, ncomp, keywords)
162 -- The keywords table may be empty
163 if #keywords == 0 then
164 return text, #text + 1
167 -- if no text had been typed yet, then we could start cycling around all
168 -- keywords with out filtering and move the cursor at the end of keyword
169 if text == nil or #text == 0 then
170 ncomp = math.mod(ncomp - 1, #keywords) + 1
171 return keywords[ncomp], #keywords[ncomp] + 2
174 -- Filter out only keywords starting with text
175 local matches = {}
176 for _, x in pairs(keywords) do
177 if x:sub(1, #text) == text then
178 table.insert(matches, x)
182 -- if there are no matches just leave out with the current text and position
183 if #matches == 0 then
184 return text, #text + 1, matches
187 -- cycle around all matches
188 ncomp = math.mod(ncomp - 1, #matches) + 1
189 return matches[ncomp], #matches[ncomp] + 1, matches
192 -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80