doom-emacs/lisp/cli/make/completions.el
Henrik Lissner b9933e6637
refactor!: restructure Doom core
BREAKING CHANGE: This restructures the project in preparation for Doom
to be split into two repos. Users that have reconfigured Doom's CLI
stand a good chance of seeing breakage, especially if they've referred
to any core-* feature, e.g.

  (after! core-cli-ci ...)

To fix it, simply s/core-/doom-/, i.e.

  (after! doom-cli-ci ...)

What this commit specifically changes is:
- Renames all core features from core-* to doom-*
- Moves core/core-* -> lisp/doom-*
- Moves core/autoloads/* -> lisp/lib/*
- Moves core/templates -> templates/

Ref: #4273
2022-07-30 22:41:13 +02:00

142 lines
6.1 KiB
EmacsLisp

;;; lisp/cli/make/completions.el --- generate shell completion scripts -*- lexical-binding: t; -*-
;;; Commentary:
;;; Code:
;;
;;; Variables
;; (defvar doom-make-completions-zsh-spec
;; '(("FILE" . "_files"))
;; "TODO")
;;
;;; Commands
(defcli! (make completions)
((shell ("--zsh" "--bash") "Generate a particular flavor of completion files (defaults to $SHELL)")
;; TODO (outfile ("-o" "--outfile" file))
&context context &args args)
"Generate completion scripts for a Doom-CLI script."
;; (unless outfile
;; (user-error "No destination file specified"))
(let ((shell (or shell (file-name-base (getenv "SHELL"))))
;; TODO Allow this command to read other Doom binscripts, which will
;; dump their `doom-cli--table' if __DOOMDUMP is set.
;; (table (read (letenv! (("__DOOMDUMP" "1")) (apply #'sh! script-file args))))
)
(print!
"%s" (pcase (string-remove-prefix "--" shell)
("zsh" (doom-make-completions-zsh context nil))
("bash" (doom-make-completions-bash context nil))
(_ (user-error "No support for %S shell at this time" shell))))))
;;
;;; ZSH Helpers
;; TODO Write to OUTFILE when specified
(defun doom-make-completions-zsh (context _outfile)
(let* ((cli (doom-cli-get context))
(prefix (doom-cli-context-prefix context))
(options (doom-cli-help--options cli t))
(commands (doom-cli-subcommands (list prefix))))
(with-temp-buffer
(insert "#compdef " (doom-cli-context-prefix context) "\n\n"
"_globalargs=(\n ")
(doom-make-completions--zsh-insert-options
(append '(((("--help") ("-?")) . "Show help documentation")
((("--version")) . "Show version information"))
(alist-get 'global options))
"\n ")
(insert "\n)\n\n")
(doom-make-completions--zsh-insert-command '("doom"))
(mapc #'doom-make-completions--zsh-insert-command commands)
;; (insert "\n\n_doom")
(buffer-string))
;; (set-file-modes outfile #o755)
;; outfile
))
(defun doom-make-completions--zsh-insert-options (options &optional cr)
;; FIXME Refactor, generalize, and parameterize this mess
(dolist (option options)
(let* ((switches (cl-loop for (sw . args) in (car option)
if (string-prefix-p "--[no-]" sw)
collect (cons (concat "--" (string-remove-prefix "--[no-]" sw)) args)
and collect (cons (concat "--no-" (string-remove-prefix "--[no-]" sw)) args)
else collect (cons sw args)))
(args (remove "..." (cdr (car switches))))
(argspec (cl-loop for arg in args
concat
(format ":%s:%s"
(replace-regexp-in-string
":" ";" (shell-quote-argument arg))
(or (plist-get (cdr (assoc (intern-soft (downcase (car args)))
doom-cli-option-arg-types))
:zshcomp)
""))))
(multiple? (member "..." (cdr (car switches)))))
(insert (format "%s%s%s"
(if multiple?
"\\*"
(format "'(%s)'" (mapconcat #'car switches " ")))
(if (cdr switches)
(format
"{%s}" (combine-and-quote-strings
(cl-loop for (sw . _) in switches
if (and args (string-prefix-p "--" sw))
collect (concat (shell-quote-argument sw) "=")
else collect (shell-quote-argument sw))
","))
(format "%s%s" (caar switches)
(if (and args (string-prefix-p "--" (caar switches)))
"=" "")))
(format "'[%s]%s'"
(replace-regexp-in-string "'" "''" (cdr option))
(or argspec "")))
(or cr "\n")))))
(defun doom-make-completions--zsh-insert-command (command)
(let* ((commandstr (doom-cli-command-string command))
(options (alist-get 'local (doom-cli-help--options (doom-cli-get command) t)))
(subcommands (doom-cli-subcommands command 1)))
(insert "_" (replace-regexp-in-string "[- ]" "_" commandstr) "() {\n"
" local line state\n"
" _arguments -s -S -C \"${_globalargs[@]}\" \\\n ")
(doom-make-completions--zsh-insert-options options " \\\n ")
(insert "\"1: :->cmds\" \"*::arg:->args\"\n"
" case $state in\n"
" cmds)\n"
" _values \"" commandstr "\" \\\n "
(string-join
(cl-loop for command in subcommands
unless (string-prefix-p ":" (car command))
collect (format "'%s[%s]' "
(car (last command))
(or (doom-cli-short-docs (doom-cli-get command))
"TODO")))
" \\\n ")
"\n ;;\n"
" args)\n"
" case $line[1] in\n "
(string-join
(cl-loop for command in subcommands
unless (string-prefix-p ":" (car command))
collect (format "%s) _%s ;; "
(car (last command))
(replace-regexp-in-string "[- ]" "_" (doom-cli-command-string command))))
"\n ")
"\n esac\n"
" ;;\n"
" esac\n"
"}\n")))
;;
;;; Bash helpers
(defun doom-make-completions-bash (context _outfile)
(user-error "Bash completion exporter hasn't been implemented yet!"))
;;; completions.el ends here