mirror of
https://git.savannah.gnu.org/git/emacs.git
synced 2024-11-29 07:58:28 +00:00
111 lines
4.7 KiB
EmacsLisp
111 lines
4.7 KiB
EmacsLisp
;;; pcmpl-git.el --- Completions for Git -*- lexical-binding: t -*-
|
|
|
|
;; Copyright (C) 2022-2024 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
|