Add git-commit-mode
This commit is contained in:
parent
0e5fd6169b
commit
99744fc874
30
elpa/git-commit-mode-0.13/git-commit-mode-autoloads.el
Normal file
30
elpa/git-commit-mode-0.13/git-commit-mode-autoloads.el
Normal file
@ -0,0 +1,30 @@
|
||||
;;; git-commit-mode-autoloads.el --- automatically extracted autoloads
|
||||
;;
|
||||
;;; Code:
|
||||
(add-to-list 'load-path (or (file-name-directory #$) (car load-path)))
|
||||
|
||||
;;;### (autoloads nil "git-commit-mode" "git-commit-mode.el" (21633
|
||||
;;;;;; 45697 22043 886000))
|
||||
;;; Generated autoloads from git-commit-mode.el
|
||||
|
||||
(autoload 'git-commit-mode "git-commit-mode" "\
|
||||
Major mode for editing git commit messages.
|
||||
|
||||
This mode helps with editing git commit messages both by
|
||||
providing commands to do common tasks, and by highlighting the
|
||||
basic structure of and errors in git commit messages.
|
||||
|
||||
\(fn)" t nil)
|
||||
|
||||
(eval-after-load 'magit '(progn (setq git-commit-skip-magit-header-regexp (format "\\(?:\\(?:[A-Za-z0-9-_]+: *.*\n\\)*%s\\)?" (regexp-quote magit-log-header-end))) (defvar git-commit-magit-font-lock-keywords `((,git-commit-skip-magit-header-regexp (0 'git-commit-skip-magit-header-face))) "Font lock keywords for Magit Log Edit Mode.") (define-derived-mode magit-log-edit-mode git-commit-mode "Magit Log Edit" (font-lock-add-keywords nil git-commit-magit-font-lock-keywords) (set (make-local-variable 'git-commit-commit-function) (apply-partially #'call-interactively 'magit-log-edit-commit))) (substitute-key-definition 'magit-log-edit-toggle-signoff 'git-commit-signoff magit-log-edit-mode-map) (substitute-key-definition 'magit-log-edit-commit 'git-commit-commit magit-log-edit-mode-map)))
|
||||
|
||||
(dolist (pattern '("/COMMIT_EDITMSG\\'" "/NOTES_EDITMSG\\'" "/MERGE_MSG\\'" "/TAG_EDITMSG\\'" "/PULLREQ_EDITMSG\\'")) (add-to-list 'auto-mode-alist (cons pattern 'git-commit-mode)))
|
||||
|
||||
;;;***
|
||||
|
||||
;; Local Variables:
|
||||
;; version-control: never
|
||||
;; no-byte-compile: t
|
||||
;; no-update-autoloads: t
|
||||
;; End:
|
||||
;;; git-commit-mode-autoloads.el ends here
|
1
elpa/git-commit-mode-0.13/git-commit-mode-pkg.el
Normal file
1
elpa/git-commit-mode-0.13/git-commit-mode-pkg.el
Normal file
@ -0,0 +1 @@
|
||||
(define-package "git-commit-mode" "0.13" "Major mode for editing git commit messages" 'nil)
|
601
elpa/git-commit-mode-0.13/git-commit-mode.el
Normal file
601
elpa/git-commit-mode-0.13/git-commit-mode.el
Normal file
@ -0,0 +1,601 @@
|
||||
;;; git-commit-mode.el --- Major mode for editing git commit messages -*- lexical-binding: t; -*-
|
||||
|
||||
;; Copyright (c) 2012, 2013 Sebastian Wiesner <lunaryorn@gmail.com>
|
||||
;; Copyright (c) 2010 Florian Ragwitz.
|
||||
;;
|
||||
;; Author: Sebastian Wiesner <lunaryorn@gmail.com>
|
||||
;; Florian Ragwitz <rafl@debian.org>
|
||||
;; Maintainer: Sebastian Wiesner <lunaryorn@gmail.com>
|
||||
;; URL: https://github.com/lunaryorn/git-modes
|
||||
;; Version: 0.13
|
||||
;; Keywords: convenience vc git
|
||||
|
||||
;; This file is not part of GNU Emacs.
|
||||
|
||||
;; This program 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 2 of the License, or (at your option) any later
|
||||
;; version.
|
||||
|
||||
;; This program 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
|
||||
;; this program; if not, write to the Free Software Foundation, Inc., 51
|
||||
;; Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;; A major mode for editing Git commit messages.
|
||||
|
||||
;; * Formatting
|
||||
;;
|
||||
;; Highlight the formatting of git commit messages and indicate errors according
|
||||
;; to the guidelines for commit messages (see
|
||||
;; http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html).
|
||||
;;
|
||||
;; Highlight the first line (aka "summary") specially if it exceeds 54
|
||||
;; characters.
|
||||
;;
|
||||
;; Enable `auto-fill-mode' and set the `fill-column' to 72 according to the
|
||||
;; aforementioned guidelines.
|
||||
|
||||
;; * Headers
|
||||
;;
|
||||
;; Provide commands to insert standard headers into commit messages.
|
||||
;;
|
||||
;; - C-c C-x s or C-c C-s inserts Signed-off-by (`git-commit-signoff').
|
||||
;; - C-C C-x a inserts Acked-by (`git-commit-ack').
|
||||
;; - C-c C-x t inserts Tested-by (`git-commit-test').
|
||||
;; - C-c C-x r inserts Reviewed-by (`git-commit-review').
|
||||
;; - C-c C-x o inserts Cc (`git-commit-cc').
|
||||
;; - C-c C-x p inserts Reported-by (`git-commit-reported').
|
||||
|
||||
;; * Committing
|
||||
;;
|
||||
;; C-c C-c finishes a commit. By default this means to save and kill the
|
||||
;; buffer. Customize `git-commit-commit-function' to change this behaviour.
|
||||
;;
|
||||
;; Check a buffer for stylistic errors before committing, and ask for
|
||||
;; confirmation before committing with style errors.
|
||||
|
||||
;; * Magit integration
|
||||
;;
|
||||
;; Overwrite `magit-log-edit-mode' to provide font locking and header insertion
|
||||
;; for Magit.
|
||||
;;
|
||||
;; Change the keymap of `magit-log-edit-mode' to use the header insertion of
|
||||
;; `git-commit-mode'.
|
||||
|
||||
;;; Code:
|
||||
|
||||
(defgroup git-commit nil
|
||||
"Mode for editing git commit messages"
|
||||
:prefix "git-commit-"
|
||||
:group 'tools)
|
||||
|
||||
(defgroup git-commit-faces nil
|
||||
"Faces for highlighting git commit messages"
|
||||
:prefix "git-commit-"
|
||||
:group 'git-commit
|
||||
:group 'faces)
|
||||
|
||||
(defface git-commit-summary-face
|
||||
'((t :inherit font-lock-type-face))
|
||||
"Face used to highlight the summary in git commit messages"
|
||||
:group 'git-commit-faces)
|
||||
|
||||
(defface git-commit-overlong-summary-face
|
||||
'((t :inherit font-lock-warning-face))
|
||||
"Face used to highlight overlong parts of git commit message summaries"
|
||||
:group 'git-commit-faces)
|
||||
|
||||
(defface git-commit-nonempty-second-line-face
|
||||
'((t :inherit font-lock-warning-face))
|
||||
"Face used to highlight text on the second line of git commit messages"
|
||||
:group 'git-commit-faces)
|
||||
|
||||
(defface git-commit-note-face
|
||||
'((t :inherit font-lock-string-face))
|
||||
"Face used to highlight notes in git commit messages"
|
||||
:group 'git-commit-faces)
|
||||
|
||||
(defface git-commit-pseudo-header-face
|
||||
'((t :inherit font-lock-string-face))
|
||||
"Font used to hightlight pseudo headers in git commit messages"
|
||||
:group 'git-commit-faces)
|
||||
|
||||
(defface git-commit-known-pseudo-header-face
|
||||
'((t :inherit font-lock-keyword-face))
|
||||
"Face used to hightlight common pseudo headers in git commit messages"
|
||||
:group 'git-commit-faces)
|
||||
|
||||
(defface git-commit-branch-face
|
||||
'((t :inherit font-lock-variable-name-face))
|
||||
"Face used to highlight the branch name in comments in git commit messages"
|
||||
:group 'git-commit-faces)
|
||||
|
||||
(defface git-commit-no-branch-face
|
||||
'((t :inherit git-commit-branch-face))
|
||||
"Face used when a commit is going to be made outside of any branches"
|
||||
:group 'git-commit-faces)
|
||||
|
||||
(defface git-commit-comment-heading-face
|
||||
'((t :inherit git-commit-known-pseudo-header-face))
|
||||
"Face used to highlight section headings in the default
|
||||
comments in git commit messages"
|
||||
:group 'git-commit-faces)
|
||||
|
||||
(defface git-commit-comment-file-face
|
||||
'((t :inherit git-commit-pseudo-header-face))
|
||||
"Face used to highlight file names in the default comments in
|
||||
git commit messages"
|
||||
:group 'git-commit-faces)
|
||||
|
||||
(defface git-commit-comment-action-face
|
||||
'((t :inherit git-commit-branch-face))
|
||||
"Face used to highlight what has happened to files in the
|
||||
default comments in git commit messages"
|
||||
:group 'git-commit-faces)
|
||||
|
||||
(defface git-commit-skip-magit-header-face
|
||||
'((t :inherit font-lock-preprocessor-face))
|
||||
"Face used to highlight the magit header that should be skipped"
|
||||
:group 'git-commit-faces)
|
||||
|
||||
(defun git-commit-end-session ()
|
||||
"Save the buffer and end the session.
|
||||
|
||||
If the current buffer has clients from the Emacs server, call
|
||||
`server-edit' to mark the buffer as done and let the clients
|
||||
continue, otherwise kill the buffer via `kill-buffer'."
|
||||
(save-buffer)
|
||||
(if (and (fboundp 'server-edit)
|
||||
(boundp 'server-buffer-clients)
|
||||
server-buffer-clients)
|
||||
(server-edit) ; The message buffer comes from emacsclient
|
||||
(kill-buffer)))
|
||||
|
||||
(defcustom git-commit-commit-function
|
||||
#'git-commit-end-session
|
||||
"Function called by `git-commit-commit' to actually perform a commit.
|
||||
|
||||
The function is called without argument, with the current buffer
|
||||
being the commit message buffer. It shall return t, if the
|
||||
commit was successful, or nil otherwise."
|
||||
:group 'git-commit
|
||||
:type '(radio (function-item :doc "Save the buffer and end the session."
|
||||
git-commit-end-session)
|
||||
(function)))
|
||||
|
||||
(defcustom git-commit-confirm-commit t
|
||||
"Whether to ask for confirmation before committing.
|
||||
|
||||
If t, ask for confirmation before creating a commit with style
|
||||
errors, unless the commit is forced. If nil, never ask for
|
||||
confirmation before committing."
|
||||
:group 'git-commit
|
||||
:type '(choice (const :tag "On style errors" t)
|
||||
(const :tag "Never" nil)))
|
||||
|
||||
(defun git-commit-has-style-errors-p ()
|
||||
"Check whether the current buffer has style errors.
|
||||
|
||||
Return t, if the current buffer has style errors, or nil
|
||||
otherwise."
|
||||
(save-excursion
|
||||
(goto-char (point-min))
|
||||
(when (re-search-forward (git-commit-find-summary-regexp) nil t)
|
||||
(or (string-match-p ".+" (or (match-string 2) ""))
|
||||
(string-match-p "^.+$" (or (match-string 3) ""))))))
|
||||
|
||||
(defun git-commit-may-do-commit (&optional force)
|
||||
"Check whether a commit may be performed.
|
||||
|
||||
Check for stylistic errors in the current message, unless FORCE
|
||||
is non-nil. If stylistic errors are found, ask the user to
|
||||
confirm commit depending on `git-commit-confirm-commit'.
|
||||
|
||||
Return t if the commit may be performed, or nil otherwise."
|
||||
(cond
|
||||
((or force (not git-commit-confirm-commit))
|
||||
t)
|
||||
((git-commit-has-style-errors-p)
|
||||
(yes-or-no-p "Buffer has style errors. Commit anyway?"))
|
||||
(t t)))
|
||||
|
||||
(defun git-commit-commit (&optional force)
|
||||
"Finish editing the commit message and commit.
|
||||
|
||||
Check for stylistic errors in the current commit, and ask the
|
||||
user for confirmation depending on `git-commit-confirm-commit'.
|
||||
If FORCE is non-nil or if a raw prefix arg is given, commit
|
||||
immediately without asking.
|
||||
|
||||
Call `git-commit-commit-function' to actually perform the commit.
|
||||
|
||||
Return t, if the commit was successful, or nil otherwise."
|
||||
(interactive "P")
|
||||
(if (git-commit-may-do-commit force)
|
||||
(funcall git-commit-commit-function)
|
||||
(message "Commit canceled due to stylistic errors.")))
|
||||
|
||||
(defun git-commit-git-config-var (key)
|
||||
"Retrieve a git configuration value.
|
||||
Invokes 'git config --get' to retrieve the value for the
|
||||
configuration key KEY."
|
||||
(ignore-errors
|
||||
(car (process-lines "git" "config" "--get" key))))
|
||||
|
||||
(defun git-commit-first-env-var (&rest vars)
|
||||
"Get the value of the first defined environment variable.
|
||||
Walk VARS, call `getenv' on each element and return the first
|
||||
non-nil return value of `getenv'."
|
||||
(let ((current vars)
|
||||
(val nil))
|
||||
(while (and (not val) current)
|
||||
(setq val (getenv (car current)))
|
||||
(setq current (cdr current)))
|
||||
val))
|
||||
|
||||
(defun git-commit-committer-name ()
|
||||
"Get the git committer name of the current user.
|
||||
This uses the same mechanism git itself uses. That is, using the
|
||||
value of the 'GIT_AUTHOR_NAME' or 'GIT_COMMITTER_NAME'
|
||||
environment variables, or the 'user.name' git configuration
|
||||
variable.
|
||||
|
||||
If the above mechanism fails, the value of the variable
|
||||
`user-full-name' is used."
|
||||
(or
|
||||
(git-commit-first-env-var "GIT_AUTHOR_NAME" "GIT_COMMITTER_NAME")
|
||||
(git-commit-git-config-var "user.name")
|
||||
user-full-name))
|
||||
|
||||
(defun git-commit-committer-email ()
|
||||
"Get the git committer email address of the current user.
|
||||
This uses the same mechanism git itself uses. That is, using the
|
||||
value of the 'GIT_AUTHOR_EMAIL', 'GIT_COMMITTER_EMAIL', or
|
||||
'EMAIL' environment variables, or the 'user.email' git
|
||||
configuration variable.
|
||||
|
||||
If the above mechanism fails, the value of the variable
|
||||
`user-email-address' is used."
|
||||
(or
|
||||
(git-commit-first-env-var "GIT_AUTHOR_EMAIL" "GIT_COMMITTER_EMAIL" "EMAIL")
|
||||
(git-commit-git-config-var "user.email")
|
||||
user-mail-address))
|
||||
|
||||
(defconst git-commit-known-pseudo-headers
|
||||
'("Signed-off-by"
|
||||
"Acked-by"
|
||||
"Cc"
|
||||
"Reported-by"
|
||||
"Tested-by"
|
||||
"Reviewed-by")
|
||||
"A list of git pseudo headers to be highlighted.")
|
||||
|
||||
(defun git-commit-find-pseudo-header-position ()
|
||||
"Find the position at which commit pseudo headers should be inserted.
|
||||
|
||||
Those headers usually live at the end of a commit message, but
|
||||
before any trailing comments git or the user might have
|
||||
inserted."
|
||||
(save-excursion
|
||||
(goto-char (point-max))
|
||||
(if (not (re-search-backward "^\\S<.+$" nil t))
|
||||
;; no comment lines anywhere before end-of-buffer, so we
|
||||
;; want to insert right there
|
||||
(point-max)
|
||||
;; there's some comments at the end, so we want to insert before
|
||||
;; those; keep going until we find the first non-empty line
|
||||
;; NOTE: if there is no newline at the end of (point),
|
||||
;; (forward-line 1) will take us to (point-at-eol).
|
||||
(if (eq (point-at-bol) (point-at-eol)) (re-search-backward "^.+$" nil t))
|
||||
(forward-line 1)
|
||||
(point))))
|
||||
|
||||
(defun git-commit-determine-pre-for-pseudo-header ()
|
||||
"Find the characters to insert before the pseudo header.
|
||||
Returns either zero, one or two newlines after computation.
|
||||
|
||||
`point' either points to an empty line (with a non-empty previous
|
||||
line) or the end of a non-empty line."
|
||||
(let ((pre "")
|
||||
(prev-line nil))
|
||||
(if (not (eq (point) (point-at-bol)))
|
||||
(progn
|
||||
(setq pre (concat pre "\n"))
|
||||
(setq prev-line (thing-at-point 'line)))
|
||||
;; else: (point) is at an empty line
|
||||
(when (not (eq (point) (point-min)))
|
||||
(setq prev-line
|
||||
(save-excursion
|
||||
(forward-line -1)
|
||||
(thing-at-point 'line)))))
|
||||
|
||||
;; we have prev-line now; if it doesn't match any known pseudo
|
||||
;; header, add a newline
|
||||
(when prev-line
|
||||
(if (not (delq nil (mapcar (lambda (pseudo-header) (string-match pseudo-header prev-line))
|
||||
git-commit-known-pseudo-headers)))
|
||||
(setq pre (concat pre "\n"))))
|
||||
pre))
|
||||
|
||||
(defun git-commit-insert-header (type name email)
|
||||
"Insert a header into the commit message.
|
||||
The inserted headers have the format 'TYPE: NAME <EMAIL>'.
|
||||
|
||||
The header is inserted at the position returned by
|
||||
`git-commit-find-pseudo-header-position'. When this position
|
||||
isn't after an existing header or a newline, an extra newline is
|
||||
inserted before the header."
|
||||
(let ((header-at (git-commit-find-pseudo-header-position)))
|
||||
(save-excursion
|
||||
(goto-char header-at)
|
||||
(let ((pre (git-commit-determine-pre-for-pseudo-header)))
|
||||
(insert (format "%s%s: %s <%s>\n" pre type name email))))))
|
||||
|
||||
(defun git-commit-insert-header-as-self (type)
|
||||
"Insert a header with the name and email address of the current user.
|
||||
Call `git-commit-insert-header' with the user name and email
|
||||
address provided by `git-commit-committer-name' and
|
||||
`git-commit-committer-email'.
|
||||
|
||||
TYPE is passed along unmodified."
|
||||
(let ((committer-name (git-commit-committer-name))
|
||||
(committer-email (git-commit-committer-email)))
|
||||
(git-commit-insert-header type committer-name committer-email)))
|
||||
|
||||
(defmacro git-define-git-commit-self (action header)
|
||||
"Create function git-commit-ACTION.
|
||||
ACTION will be part of the function name.
|
||||
HEADER is the actual header to be inserted into the comment."
|
||||
(let ((func-name (intern (concat "git-commit-" action))))
|
||||
`(defun ,func-name ()
|
||||
,(format "Insert a '%s' header at the end of the commit message.
|
||||
|
||||
The author name and email address used for the header are
|
||||
retrieved automatically with the same mechanism git uses."
|
||||
header)
|
||||
(interactive)
|
||||
(git-commit-insert-header-as-self ,header))))
|
||||
|
||||
(git-define-git-commit-self "ack" "Acked-by")
|
||||
(git-define-git-commit-self "review" "Reviewed-by")
|
||||
(git-define-git-commit-self "signoff" "Signed-off-by")
|
||||
(git-define-git-commit-self "test" "Tested-by")
|
||||
|
||||
(defmacro git-define-git-commit (action header)
|
||||
"Create interactive function git-commit-ACTION.
|
||||
ACTION will be part of the function name.
|
||||
HEADER is the actual header to be inserted into the comment."
|
||||
(let ((func-name (intern (concat "git-commit-" action))))
|
||||
`(defun ,func-name (name email)
|
||||
,(format "Insert a '%s' header at the end of the commit message.
|
||||
The value of the header is determined by NAME and EMAIL.
|
||||
|
||||
When called interactively, both NAME and EMAIL are read from the
|
||||
minibuffer."
|
||||
header)
|
||||
(interactive
|
||||
(list (read-string "Name: ")
|
||||
(read-string "Email: ")))
|
||||
(git-commit-insert-header ,header name email))))
|
||||
|
||||
(git-define-git-commit "cc" "Cc")
|
||||
(git-define-git-commit "reported" "Reported-by")
|
||||
|
||||
(defconst git-commit-comment-headings-alist
|
||||
'(("Not currently on any branch." . git-commit-no-branch-face)
|
||||
("Changes to be committed:" . git-commit-comment-heading-face)
|
||||
("Untracked files:" . git-commit-comment-heading-face)
|
||||
("Changed but not updated:" . git-commit-comment-heading-face)
|
||||
("Changes not staged for commit:" . git-commit-comment-heading-face)
|
||||
("Unmerged paths:" . git-commit-comment-heading-face))
|
||||
"Headings in message comments.
|
||||
|
||||
The `car' of each cell is the heading text, the `cdr' the face to
|
||||
use for fontification.")
|
||||
|
||||
(defconst git-commit-skip-before-summary-regexp
|
||||
"\\(?:\\(?:\\s-*\\|\\s<.*\\)\n\\)*"
|
||||
"Regexp to skip empty lines and comments before the summary.
|
||||
|
||||
Do not use this expression directly, instead call
|
||||
`git-commit-find-summary-regexp' to create a regular expression
|
||||
to match the summary line.")
|
||||
|
||||
(defconst git-commit-summary-regexp
|
||||
"\\(?:^\\(.\\{,50\\}\\)\\(.*?\\)$\\)"
|
||||
"Regexp to match the summary line.
|
||||
|
||||
Do not use this expression directly, instead call
|
||||
`git-commit-find-summary-regexp' to create a regular expression
|
||||
to match the summary line.")
|
||||
|
||||
(defconst git-commit-nonempty-second-line-regexp
|
||||
"\\(?:\n\\(.*\\)\\)?$"
|
||||
"Regexp to match a nonempty line following the summary.
|
||||
|
||||
Do not use this expression directly, instead call
|
||||
`git-commit-find-summary-regexp' to create a regular expression
|
||||
to match the summary line.")
|
||||
|
||||
(defvar git-commit-skip-magit-header-regexp nil
|
||||
"Regexp to skip magit header.
|
||||
|
||||
This variable is nil until `magit' is loaded.
|
||||
|
||||
Do not use this expression directly, instead call
|
||||
`git-commit-find-summary-regexp' to create a regular expression
|
||||
to match the summary line.")
|
||||
|
||||
(defun git-commit-find-summary-regexp ()
|
||||
"Create a regular expression to find the Git summary line.
|
||||
|
||||
Return a regular expression that starts at the beginning of the
|
||||
buffer, skips over empty lines, comments and also over the magit
|
||||
header, if the current buffer is a `magit-log-edit-mode' buffer,
|
||||
and finds the summary line.
|
||||
|
||||
The regular expression matches three groups. The first group is
|
||||
the summary line, the second group contains any overlong part of
|
||||
the summary, and the third group contains a nonempty line
|
||||
following the summary line. The latter two groups may be empty."
|
||||
(format "\\`%s%s%s%s"
|
||||
(if (eq major-mode 'magit-log-edit-mode)
|
||||
git-commit-skip-magit-header-regexp
|
||||
"")
|
||||
git-commit-skip-before-summary-regexp
|
||||
git-commit-summary-regexp
|
||||
git-commit-nonempty-second-line-regexp))
|
||||
|
||||
(defun git-commit-mode-summary-font-lock-keywords (&optional errors)
|
||||
"Create font lock keywords to fontify the Git summary.
|
||||
|
||||
If ERRORS is non-nil create keywords that highlight errors in the
|
||||
summary line, not the summary line itself."
|
||||
(let ((regexp (git-commit-find-summary-regexp)))
|
||||
(if errors
|
||||
`(,regexp
|
||||
(2 'git-commit-overlong-summary-face t t)
|
||||
(3 'git-commit-nonempty-second-line-face t t))
|
||||
`(,regexp (1 'git-commit-summary-face t)))))
|
||||
|
||||
(defun git-commit-mode-heading-keywords ()
|
||||
"Create font lock keywords to fontify comment headings.
|
||||
|
||||
Known comment headings are provided by `git-commit-comment-headings'."
|
||||
(mapcar (lambda (cell) `(,(format "^\\s<\\s-+\\(%s\\)$"
|
||||
(regexp-quote (car cell)))
|
||||
(1 ',(cdr cell) t)))
|
||||
git-commit-comment-headings-alist))
|
||||
|
||||
(defvar git-commit-mode-font-lock-keywords
|
||||
(append
|
||||
`(("^\\s<.*$" . 'font-lock-comment-face)
|
||||
("^\\s<\\s-On branch \\(.*\\)$" (1 'git-commit-branch-face t))
|
||||
("^\\s<\t\\(?:\\([^:]+\\):\\s-+\\)?\\(.*\\)$"
|
||||
(1 'git-commit-comment-action-face t t)
|
||||
(2 'git-commit-comment-file-face t))
|
||||
(,(concat "^\\("
|
||||
(regexp-opt git-commit-known-pseudo-headers)
|
||||
":\\)\\(\s.*\\)$")
|
||||
(1 'git-commit-known-pseudo-header-face)
|
||||
(2 'git-commit-pseudo-header-face))
|
||||
("^\\<\\S-+:\\s-.*$" . 'git-commit-pseudo-header-face)
|
||||
(eval . (git-commit-mode-summary-font-lock-keywords))
|
||||
("\\[[^\n]+?\\]" (0 'git-commit-note-face t)) ; Notes override summary line
|
||||
;; Warnings from overlong lines and nonempty second line override
|
||||
;; everything
|
||||
(eval . (git-commit-mode-summary-font-lock-keywords t)))
|
||||
(git-commit-mode-heading-keywords)))
|
||||
|
||||
(defvar git-commit-mode-map
|
||||
(let ((map (make-sparse-keymap)))
|
||||
;; Short shortcut ;) for the frequently used signoff header
|
||||
(define-key map (kbd "C-c C-s") 'git-commit-signoff)
|
||||
;; Verbose shortcuts for all headers to avoid conflicts with magit bindings
|
||||
(define-key map (kbd "C-c C-x s") 'git-commit-signoff)
|
||||
(define-key map (kbd "C-c C-x a") 'git-commit-ack)
|
||||
(define-key map (kbd "C-c C-x t") 'git-commit-test)
|
||||
(define-key map (kbd "C-c C-x r") 'git-commit-review)
|
||||
(define-key map (kbd "C-c C-x o") 'git-commit-cc)
|
||||
(define-key map (kbd "C-c C-x p") 'git-commit-reported)
|
||||
;; Committing
|
||||
(define-key map (kbd "C-c C-c") 'git-commit-commit)
|
||||
map)
|
||||
"Key map used by `git-commit-mode'.")
|
||||
|
||||
(defvar git-commit-mode-syntax-table
|
||||
(let ((table (make-syntax-table text-mode-syntax-table)))
|
||||
(modify-syntax-entry ?# "<" table)
|
||||
(modify-syntax-entry ?\n ">" table)
|
||||
(modify-syntax-entry ?\r ">" table)
|
||||
table)
|
||||
"Syntax table used by `git-commit-mode'.")
|
||||
|
||||
(defun git-commit-font-lock-diff ()
|
||||
"Add font lock on diff."
|
||||
(save-excursion
|
||||
(goto-char (point-min))
|
||||
(when (re-search-forward "^diff --git" nil t)
|
||||
(let ((beg (match-beginning 0)))
|
||||
(let* ((buffer (current-buffer))
|
||||
(font-lock-verbose nil)
|
||||
(font-lock-support-mode nil)
|
||||
(text (with-temp-buffer
|
||||
(insert
|
||||
(with-current-buffer buffer
|
||||
(buffer-substring-no-properties beg (point-max))))
|
||||
(diff-mode)
|
||||
(font-lock-fontify-buffer)
|
||||
(let ((pos (point-min))
|
||||
next)
|
||||
(while (setq next (next-single-property-change pos 'face))
|
||||
(put-text-property pos next 'font-lock-face
|
||||
(get-text-property pos 'face))
|
||||
(setq pos next)))
|
||||
(buffer-string))))
|
||||
(delete-region beg (point-max))
|
||||
(insert text))))))
|
||||
|
||||
;;;###autoload
|
||||
(define-derived-mode git-commit-mode text-mode "Git Commit"
|
||||
"Major mode for editing git commit messages.
|
||||
|
||||
This mode helps with editing git commit messages both by
|
||||
providing commands to do common tasks, and by highlighting the
|
||||
basic structure of and errors in git commit messages."
|
||||
;; Font locking
|
||||
(setq font-lock-defaults '(git-commit-mode-font-lock-keywords t))
|
||||
(set (make-local-variable 'font-lock-multiline) t)
|
||||
(git-commit-font-lock-diff)
|
||||
;; Filling according to the guidelines
|
||||
(setq fill-column 72)
|
||||
(turn-on-auto-fill)
|
||||
;; Recognize changelog-style paragraphs
|
||||
(set (make-local-variable 'paragraph-start)
|
||||
(concat paragraph-start "\\|*\\|("))
|
||||
;; Do not remember point location in commit messages
|
||||
(when (fboundp 'toggle-save-place)
|
||||
(toggle-save-place 0)))
|
||||
|
||||
;;;###autoload
|
||||
;; Overwrite magit-log-edit-mode to derive from git-commit-mode, and change it's
|
||||
;; key bindings to use our commit and header insertion bindings
|
||||
(eval-after-load 'magit
|
||||
'(progn
|
||||
(setq git-commit-skip-magit-header-regexp
|
||||
(format
|
||||
"\\(?:\\(?:[A-Za-z0-9-_]+: *.*\n\\)*%s\\)?"
|
||||
(regexp-quote magit-log-header-end)))
|
||||
|
||||
(defvar git-commit-magit-font-lock-keywords
|
||||
`((,git-commit-skip-magit-header-regexp
|
||||
(0 'git-commit-skip-magit-header-face)))
|
||||
"Font lock keywords for Magit Log Edit Mode.")
|
||||
|
||||
(define-derived-mode magit-log-edit-mode git-commit-mode "Magit Log Edit"
|
||||
(font-lock-add-keywords nil git-commit-magit-font-lock-keywords)
|
||||
(set (make-local-variable 'git-commit-commit-function)
|
||||
(apply-partially #'call-interactively 'magit-log-edit-commit)))
|
||||
(substitute-key-definition 'magit-log-edit-toggle-signoff
|
||||
'git-commit-signoff
|
||||
magit-log-edit-mode-map)
|
||||
(substitute-key-definition 'magit-log-edit-commit
|
||||
'git-commit-commit
|
||||
magit-log-edit-mode-map)))
|
||||
|
||||
;;;###autoload
|
||||
(dolist (pattern '("/COMMIT_EDITMSG\\'" "/NOTES_EDITMSG\\'"
|
||||
"/MERGE_MSG\\'" "/TAG_EDITMSG\\'"
|
||||
"/PULLREQ_EDITMSG\\'"))
|
||||
(add-to-list 'auto-mode-alist (cons pattern 'git-commit-mode)))
|
||||
|
||||
(provide 'git-commit-mode)
|
||||
|
||||
;;; git-commit-mode.el ends here
|
Loading…
Reference in New Issue
Block a user