Add git-commit-mode
This commit is contained in:
		
							
								
								
									
										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 | ||||
		Reference in New Issue
	
	Block a user