|
@@ -0,0 +1,139 @@
|
|
|
|
+#!/usr/bin/lua5.2
|
|
|
|
+
|
|
|
|
+-- CivetWeb command line completion for bash
|
|
|
|
+--
|
|
|
|
+-- To use it, create a file called "civetweb" in the completion folder
|
|
|
|
+-- (/usr/share/bash-completion/completions/ or /etc/bash_completion)
|
|
|
|
+-- This file has to contain just one line:
|
|
|
|
+-- complete -C /path/to/civetweb/resources/complete.lua civetweb
|
|
|
|
+--
|
|
|
|
+
|
|
|
|
+-- The bash "complete -C" has an awkward interface:
|
|
|
|
+-- see https://unix.stackexchange.com/questions/250262/how-to-use-bashs-complete-or-compgen-c-command-option
|
|
|
|
+-- Command line arguments
|
|
|
|
+cmd = arg[1] -- typically "./civetweb" or whatever path was used
|
|
|
|
+this = arg[2] -- characters already typed for the next options
|
|
|
|
+last = arg[3] -- option before this one
|
|
|
|
+-- Environment variables
|
|
|
|
+comp_line = os.getenv("COMP_LINE") -- entire command line
|
|
|
|
+comp_point = os.getenv("COMP_POINT") -- position of cursor (index)
|
|
|
|
+comp_type = os.getenv("COMP_TYPE") -- type:
|
|
|
|
+-- 9 for normal completion
|
|
|
|
+-- 33 when listing alternatives on ambiguous completions
|
|
|
|
+-- 37 for menu completion
|
|
|
|
+-- 63 when tabbing between ambiguous completions
|
|
|
|
+-- 64 to list completions after a partial completion
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+-- Debug-Print function (must use absolute path for log file)
|
|
|
|
+function dp(txt)
|
|
|
|
+ local f = io.open("/tmp/complete.log", "a");
|
|
|
|
+ f:write(txt .. "\n")
|
|
|
|
+ f:close()
|
|
|
|
+end
|
|
|
|
+
|
|
|
|
+-- Helper function: Check if files exist
|
|
|
|
+function fileexists(name)
|
|
|
|
+ local f = io.open(name, "r")
|
|
|
|
+ if f then
|
|
|
|
+ f:close()
|
|
|
|
+ return true
|
|
|
|
+ end
|
|
|
|
+ return false
|
|
|
|
+end
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+-- Debug logging
|
|
|
|
+dp("complete: cmd=" .. cmd .. ", this=" .. this .. ", last=" .. last .. ", type=" .. comp_type)
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+-- Trim command line (remove spaces)
|
|
|
|
+trim_comp_line = string.match(comp_line, "^%s*(.-)%s*$")
|
|
|
|
+
|
|
|
|
+if (trim_comp_line == cmd) then
|
|
|
|
+ -- this is the first option
|
|
|
|
+ dp("Suggest --help argument")
|
|
|
|
+ print("--help ")
|
|
|
|
+ os.exit(0)
|
|
|
|
+end
|
|
|
|
+
|
|
|
|
+is_h = string.find(comp_line, "^%s*" .. cmd .. "%s+%-h%s")
|
|
|
|
+is_h = is_h or string.find(comp_line, "^%s*" .. cmd .. "%s+%--help%s")
|
|
|
|
+is_h = is_h or string.find(comp_line, "^%s*" .. cmd .. "%s+%-H%s")
|
|
|
|
+
|
|
|
|
+if (is_h) then
|
|
|
|
+ dp("If --help is used, no additional argument is allowed")
|
|
|
|
+ os.exit(0)
|
|
|
|
+end
|
|
|
|
+
|
|
|
|
+is_a = string.find(comp_line, "^%s*" .. cmd .. "%s+%-A%s")
|
|
|
|
+is_c = string.find(comp_line, "^%s*" .. cmd .. "%s+%-C%s")
|
|
|
|
+is_i = string.find(comp_line, "^%s*" .. cmd .. "%s+%-I%s")
|
|
|
|
+is_r = string.find(comp_line, "^%s*" .. cmd .. "%s+%-R%s")
|
|
|
|
+
|
|
|
|
+if (is_i) then
|
|
|
|
+ dp("If --I is used, no additional argument is allowed")
|
|
|
|
+ os.exit(0)
|
|
|
|
+end
|
|
|
|
+
|
|
|
|
+-- -A and -R require the password file as second argument
|
|
|
|
+htpasswd = ".htpasswd"
|
|
|
|
+if ((last == "-A") or (last == "-R")) and (this == htpasswd:sub(1,#this)) then
|
|
|
|
+ print(htpasswd)
|
|
|
|
+ os.exit(0)
|
|
|
|
+end
|
|
|
|
+
|
|
|
|
+-- -C requires an URL, usually starting with http:// or https://
|
|
|
|
+http = "http://"
|
|
|
|
+if (last == "-C") and (this == http:sub(1,#this)) then
|
|
|
|
+ print(http)
|
|
|
|
+ print(http.. "localhost/")
|
|
|
|
+ os.exit(0)
|
|
|
|
+end
|
|
|
|
+http = "https://"
|
|
|
|
+if (last == "-C") and (this == http:sub(1,#this)) then
|
|
|
|
+ print(http)
|
|
|
|
+ print(http.. "localhost/")
|
|
|
|
+ os.exit(0)
|
|
|
|
+end
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+-- Take options directly from "--help" output of executable
|
|
|
|
+optfile = "/tmp/civetweb.options"
|
|
|
|
+if not fileexists(optfile) then
|
|
|
|
+ dp("options file " .. optfile .. " missing")
|
|
|
|
+ os.execute(cmd .. " -h &> " .. optfile)
|
|
|
|
+else
|
|
|
|
+ dp("options file " .. optfile .. " found")
|
|
|
|
+end
|
|
|
|
+
|
|
|
|
+for l in io.lines(optfile) do
|
|
|
|
+ local lkey, lval = l:match("^%s+(%-[^%s]*)%s*([^%s]*)%s*$")
|
|
|
|
+ if lkey then
|
|
|
|
+ local thislen = string.len(this)
|
|
|
|
+ if (thislen>0) and (this == lkey:sub(1,thislen)) then
|
|
|
|
+ print(lkey)
|
|
|
|
+ dp("match: " .. lkey)
|
|
|
|
+ keymatch = true
|
|
|
|
+ end
|
|
|
|
+ if last == lkey then
|
|
|
|
+ valmatch = lval
|
|
|
|
+ end
|
|
|
|
+ end
|
|
|
|
+end
|
|
|
|
+
|
|
|
|
+if keymatch then
|
|
|
|
+ -- at least one options matches
|
|
|
|
+ os.exit(0)
|
|
|
|
+end
|
|
|
|
+
|
|
|
|
+if valmatch then
|
|
|
|
+ -- suggest the default value
|
|
|
|
+ print(valmatch)
|
|
|
|
+ os.exit(0)
|
|
|
|
+end
|
|
|
|
+
|
|
|
|
+-- No context to determine next argument
|
|
|
|
+dp("no specific option")
|
|
|
|
+os.exit(0)
|
|
|
|
+
|