summaryrefslogtreecommitdiff
path: root/lisp/pcmpl-git.el
diff options
context:
space:
mode:
authorAugusto Stoffel <arstoffel@gmail.com>2022-09-08 11:09:42 +0200
committerLars Ingebrigtsen <larsi@gnus.org>2022-09-14 21:58:04 +0200
commita9941269683fe50673d0aa81feefb7a9d3d8a6b9 (patch)
tree566c9ecd3afb90b58607c71ad794cee14ba7b823 /lisp/pcmpl-git.el
parent05971d2b8d47e69e9585d0d6066b8a607555aa48 (diff)
downloademacs-a9941269683fe50673d0aa81feefb7a9d3d8a6b9.tar.gz
pcomplete: Generate completions from --help messages
* lisp/pcomplete.el (pcomplete-from-help): New function (and hash table) to get pcomplete candidates from help messages. (pcomplete-here-using-help): Helper function to define pcomplete for simple commands (pcomplete-completions-at-point): Provide annotation-function and company-docsig properties. * lisp/pcmpl-git.el: New file, provides pcomplete for Git. * lisp/pcmpl-gnu.el: Add pcomplete for awk, gpg and gdb, emacs and emacsclient. * lisp/pcmpl-linux.el: Add pcomplete for systemctl and journalctl. * lisp/pcmpl-rpm.el: Add pcomplete for dnf. * lisp/pcmpl-unix.el: Add pcomplete for sudo and most commands found in GNU Coreutils. * lisp/pcmpl-x.el: Add pcomplete for tex, pdftex, latex, pdflatex, rigrep and rclone. * test/lisp/pcomplete-tests.el (pcomplete-test-parse-gpg-help, pcomplete-test-parse-git-help): Tests for the new functions.
Diffstat (limited to 'lisp/pcmpl-git.el')
-rw-r--r--lisp/pcmpl-git.el110
1 files changed, 110 insertions, 0 deletions
diff --git a/lisp/pcmpl-git.el b/lisp/pcmpl-git.el
new file mode 100644
index 00000000000..3584fa06732
--- /dev/null
+++ b/lisp/pcmpl-git.el
@@ -0,0 +1,110 @@
+;;; pcmpl-git.el --- Completions for Git -*- lexical-binding: t -*-
+
+;; Copyright (C) 2022 Free Software Foundation, Inc.
+
+;; Package: pcomplete
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This library provides completion rules for the Git program.
+
+;;; Code:
+
+(require 'pcomplete)
+(require 'vc-git)
+
+(defun pcmpl-git--expand-flags (args)
+ "In the list of ARGS, expand arguments of the form --[no-]flag."
+ (mapcan (lambda (arg) (if (string-search "[no-]" arg)
+ (list (string-replace "[no-]" "" arg)
+ (string-replace "[no-]" "no-" arg))
+ (list arg)))
+ args))
+
+(defun pcmpl-git--tracked-file-predicate (&rest args)
+ "Return a predicate function determining the Git status of a file.
+Files listed by `git ls-files ARGS' satisfy the predicate."
+ (when-let ((files (mapcar #'expand-file-name
+ (ignore-errors
+ (apply #'process-lines
+ vc-git-program "ls-files" args)))))
+ (lambda (file)
+ (setq file (expand-file-name file))
+ (if (string-suffix-p "/" file)
+ (seq-some (lambda (f) (string-prefix-p file f))
+ files)
+ (member file files)))))
+
+(defun pcmpl-git--remote-refs (remote)
+ "List the locally known Git revisions from REMOTE."
+ (delq nil
+ (mapcar
+ (let ((re (concat "\\`" (regexp-quote remote) "/\\(.*\\)")))
+ (lambda (s) (when (string-match re s) (match-string 1 s))))
+ (vc-git-revision-table nil))))
+
+;;;###autoload
+(defun pcomplete/git ()
+ "Completion for the `git' command."
+ (let ((subcommands (pcomplete-from-help `(,vc-git-program "help" "-a")
+ :margin "^\\( +\\)[a-z]"
+ :argument "[[:alnum:]-]+")))
+ (while (not (member (pcomplete-arg 1) subcommands))
+ (if (string-prefix-p "-" (pcomplete-arg))
+ (pcomplete-here (pcomplete-from-help `(,vc-git-program "help")
+ :margin "\\(\\[\\)-"
+ :separator " | "
+ :description "\\`"))
+ (pcomplete-here (completion-table-merge
+ subcommands
+ (when (string-prefix-p "-" (pcomplete-arg 1))
+ (pcomplete-entries))))))
+ (let ((subcmd (pcomplete-arg 1)))
+ (while (pcase subcmd
+ ((guard (string-prefix-p "-" (pcomplete-arg)))
+ (pcomplete-here
+ (pcmpl-git--expand-flags
+ (pcomplete-from-help `(,vc-git-program "help" ,subcmd)
+ :argument
+ "-+\\(?:\\[no-\\]\\)?[a-z-]+=?"))))
+ ;; Complete modified tracked files
+ ((or "add" "commit" "restore")
+ (pcomplete-here
+ (pcomplete-entries
+ nil (pcmpl-git--tracked-file-predicate "-m"))))
+ ;; Complete all tracked files
+ ((or "mv" "rm" "grep" "status")
+ (pcomplete-here
+ (pcomplete-entries nil (pcmpl-git--tracked-file-predicate))))
+ ;; Complete revisions
+ ((or "branch" "merge" "rebase" "switch")
+ (pcomplete-here (vc-git-revision-table nil)))
+ ;; Complete revisions and tracked files
+ ;; TODO: diff and log accept revision ranges
+ ((or "checkout" "reset" "show" "diff" "log")
+ (pcomplete-here
+ (completion-table-in-turn
+ (vc-git-revision-table nil)
+ (pcomplete-entries nil (pcmpl-git--tracked-file-predicate)))))
+ ;; Complete remotes and their revisions
+ ((or "fetch" "pull" "push")
+ (pcomplete-here (process-lines vc-git-program "remote"))
+ (pcomplete-here (pcmpl-git--remote-refs (pcomplete-arg 1)))))))))
+
+(provide 'pcmpl-git)
+;;; pcmpl-git.el ends here