complete.lua 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. #!/usr/bin/lua5.2
  2. -- CivetWeb command line completion for bash
  3. --
  4. -- To use it, create a file called "civetweb" in the completion folder
  5. -- (/usr/share/bash-completion/completions/ or /etc/bash_completion)
  6. -- This file has to contain just one line:
  7. -- complete -C /path/to/civetweb/resources/complete.lua civetweb
  8. --
  9. -- The bash "complete -C" has an awkward interface:
  10. -- see https://unix.stackexchange.com/questions/250262/how-to-use-bashs-complete-or-compgen-c-command-option
  11. -- Command line arguments
  12. cmd = arg[1] -- typically "./civetweb" or whatever path was used
  13. this = arg[2] -- characters already typed for the next options
  14. last = arg[3] -- option before this one
  15. -- Environment variables
  16. comp_line = os.getenv("COMP_LINE") -- entire command line
  17. comp_point = os.getenv("COMP_POINT") -- position of cursor (index)
  18. comp_type = os.getenv("COMP_TYPE") -- type:
  19. -- 9 for normal completion
  20. -- 33 when listing alternatives on ambiguous completions
  21. -- 37 for menu completion
  22. -- 63 when tabbing between ambiguous completions
  23. -- 64 to list completions after a partial completion
  24. -- Debug-Print function (must use absolute path for log file)
  25. function dp(txt)
  26. local f = io.open("/tmp/complete.log", "a");
  27. f:write(txt .. "\n")
  28. f:close()
  29. end
  30. -- Helper function: Check if files exist
  31. function fileexists(name)
  32. local f = io.open(name, "r")
  33. if f then
  34. f:close()
  35. return true
  36. end
  37. return false
  38. end
  39. -- Debug logging
  40. dp("complete: cmd=" .. cmd .. ", this=" .. this .. ", last=" .. last .. ", type=" .. comp_type)
  41. -- Trim command line (remove spaces)
  42. trim_comp_line = string.match(comp_line, "^%s*(.-)%s*$")
  43. if (trim_comp_line == cmd) then
  44. -- this is the first option
  45. dp("Suggest --help argument")
  46. print("--help ")
  47. os.exit(0)
  48. end
  49. is_h = string.find(comp_line, "^%s*" .. cmd .. "%s+%-h%s")
  50. is_h = is_h or string.find(comp_line, "^%s*" .. cmd .. "%s+%--help%s")
  51. is_h = is_h or string.find(comp_line, "^%s*" .. cmd .. "%s+%-H%s")
  52. if (is_h) then
  53. dp("If --help is used, no additional argument is allowed")
  54. os.exit(0)
  55. end
  56. is_a = string.find(comp_line, "^%s*" .. cmd .. "%s+%-A%s")
  57. is_c = string.find(comp_line, "^%s*" .. cmd .. "%s+%-C%s")
  58. is_i = string.find(comp_line, "^%s*" .. cmd .. "%s+%-I%s")
  59. is_r = string.find(comp_line, "^%s*" .. cmd .. "%s+%-R%s")
  60. if (is_i) then
  61. dp("If --I is used, no additional argument is allowed")
  62. os.exit(0)
  63. end
  64. -- -A and -R require the password file as second argument
  65. htpasswd = ".htpasswd"
  66. if ((last == "-A") or (last == "-R")) and (this == htpasswd:sub(1,#this)) then
  67. print(htpasswd)
  68. os.exit(0)
  69. end
  70. -- -C requires an URL, usually starting with http:// or https://
  71. http = "http://"
  72. if (last == "-C") and (this == http:sub(1,#this)) then
  73. print(http)
  74. print(http.. "localhost/")
  75. os.exit(0)
  76. end
  77. http = "https://"
  78. if (last == "-C") and (this == http:sub(1,#this)) then
  79. print(http)
  80. print(http.. "localhost/")
  81. os.exit(0)
  82. end
  83. -- Take options directly from "--help" output of executable
  84. optfile = "/tmp/civetweb.options"
  85. if not fileexists(optfile) then
  86. dp("options file " .. optfile .. " missing")
  87. os.execute(cmd .. " -h &> " .. optfile)
  88. else
  89. dp("options file " .. optfile .. " found")
  90. end
  91. for l in io.lines(optfile) do
  92. local lkey, lval = l:match("^%s+(%-[^%s]*)%s*([^%s]*)%s*$")
  93. if lkey then
  94. local thislen = string.len(this)
  95. if (thislen>0) and (this == lkey:sub(1,thislen)) then
  96. print(lkey)
  97. dp("match: " .. lkey)
  98. keymatch = true
  99. end
  100. if last == lkey then
  101. valmatch = lval
  102. end
  103. end
  104. end
  105. if keymatch then
  106. -- at least one options matches
  107. os.exit(0)
  108. end
  109. if valmatch then
  110. -- suggest the default value
  111. print(valmatch)
  112. os.exit(0)
  113. end
  114. -- No context to determine next argument
  115. dp("no specific option")
  116. os.exit(0)