diff --git a/bin/doom b/bin/doom index b2d94df93..558d218ab 100755 --- a/bin/doom +++ b/bin/doom @@ -277,7 +277,7 @@ SEE ALSO: (defgroup! "Development" :docs "Commands for developing or launching Doom." (defautoload! (ci)) - ;; TODO (defautoload! (make)) + (defautoload! (make)) (defautoload! (run)) ;; FIXME Test framework diff --git a/core/cli/make.el b/core/cli/make.el new file mode 100644 index 000000000..32f4e137e --- /dev/null +++ b/core/cli/make.el @@ -0,0 +1,64 @@ +;;; core/cli/make.el --- file generation commands -*- lexical-binding: t; -*- +;;; Commentary: +;;; Code: + +(load! "make/completions") +;; (load! "make/docs") +;; (load! "make/manpage") + + +;; +;;; Variables + +;; (defvar doom-make-codeowners () +;; "TODO") + + +;; +;;; Commands + +(defcli! make () + "(Re)Generate project files and boilerplate." + :partial t) + +;; TODO Finish and generalize me +(defcli! (make codeowners) () + "TODO" + :stub t + (print! (start "Generating CODEOWNERS file")) + (let ((codeowners (doom-path doom-emacs-dir ".github/CODEOWNERS"))) + (with-temp-file codeowners + (insert-file-contents codeowners) + (when (re-search-forward "^# Don't edit this by hand!" nil t) + (goto-char (line-end-position)) + (delete-region (point) (point-max)) + (insert "\n") + (dolist (path (cdr (doom-module-load-path (list doom-modules-dir)))) + (when (string-match "/modules/\\([^/]+\\)/\\([^/]+\\)/$" path) + (insert (format "%-35s @doomemacs/maintainers @doomemacs/%s-%s\n" + (concat (substring (match-string-no-properties 0 path) 1) "*") + (match-string-no-properties 1 path) + (match-string-no-properties 2 path))))))))) + +;; TODO Finish me +(defcli! (make changelog) () :stub t) + + + +;; +;;; Helpers + +(defmacro doom-make--with-file (file &rest body) + (declare (indent 1)) + `(let ((inhibit-read-only t)) + (with-current-buffer + (or (get-file-buffer ,file) + (find-file-noselect ,file)) + (save-excursion + (goto-char (point-min)) + ,@body + (when (buffer-modified-p) + (save-buffer)))))) + +(provide 'core-cli-make) +;;; make.el ends here diff --git a/core/cli/make/completions.el b/core/cli/make/completions.el new file mode 100644 index 000000000..6a3437a01 --- /dev/null +++ b/core/cli/make/completions.el @@ -0,0 +1,143 @@ +;;; core/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." + ;; :stub t + ;; (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