From 96f48ebd97c19384f487c8a9c4cf474705ce1e37 Mon Sep 17 00:00:00 2001 From: Alexander Sulfrian Date: Tue, 24 Apr 2012 23:19:57 +0200 Subject: emacs.d/lisp/magit: version bump --- emacs.d/lisp/magit/rebase-mode.el | 320 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 320 insertions(+) create mode 100644 emacs.d/lisp/magit/rebase-mode.el (limited to 'emacs.d/lisp/magit/rebase-mode.el') diff --git a/emacs.d/lisp/magit/rebase-mode.el b/emacs.d/lisp/magit/rebase-mode.el new file mode 100644 index 0000000..0af7d6a --- /dev/null +++ b/emacs.d/lisp/magit/rebase-mode.el @@ -0,0 +1,320 @@ +;;; rebase-mode -- edit git rebase files. + +;; Copyright (C) 2010 Phil Jackson +;; Copyright (C) 2011 Peter J Weisberg +;; +;; Magit 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, or (at your option) +;; any later version. +;; +;; Magit 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 Magit. If not, see . + +;;; Commentary: + +;; Allows the editing of a git rebase file (which you might get when +;; using 'git rebase -i' or hitting 'E' in Magit). Assumes editing is +;; happening in a server. + +;;; Code: + +(defgroup rebase-mode nil + "Customize Rebase Mode" + :group 'faces) + +(defface rebase-mode-killed-action-face + '((((class color)) + :inherit font-lock-comment-face + :strike-through t)) + "Action lines in the rebase TODO list that have been commented out." + :group 'rebase-mode) + +(defface rebase-mode-description-face + '((t :inherit font-lock-comment-face)) + "Face for one-line commit descriptions" + :group 'rebase-mode) + +(defconst rebase-mode-action-line-re + (rx + line-start + (? "#") + (group + (| + (any "presf") + "pick" + "reword" + "edit" + "squash" + "fixup")) + (char space) + (group + (** 4 40 hex-digit)) ;sha1 + (char space) + (group + (* not-newline))) + "Regexp that matches an action line in a rebase buffer.") + +(defconst rebase-mode-exec-line-re + (rx + line-start + (? "#") + (group + (| "x" + "exec")) + (char space) + (group + (* not-newline))) + "Regexp that matches an exec line in a rebase buffer.") + +(defconst rebase-mode-dead-line-re + (rx-to-string `(and line-start + (char ?#) + (or (regexp ,(substring rebase-mode-action-line-re 1)) + (regexp ,(substring rebase-mode-exec-line-re 1)))) t) + "Regexp that matches a commented-out exec or action line in a rebase buffer.") + +(defvar rebase-mode-font-lock-keywords + (list + (list rebase-mode-action-line-re + '(1 font-lock-keyword-face) + '(2 font-lock-builtin-face) + '(3 'rebase-mode-description-face)) + (list rebase-mode-exec-line-re + '(1 font-lock-keyword-face)) + (list (rx line-start (char "#") (* not-newline)) 0 font-lock-comment-face) + (list rebase-mode-dead-line-re 0 ''rebase-mode-killed-action-face t)) + "Font lock keywords for `rebase-mode'.") + +(defvar key-to-action-map + '(("c" . "pick") + ("r" . "reword") + ("e" . "edit") + ("s" . "squash") + ("f" . "fixup")) + "Mapping from key to action.") + +(defvar rebase-mode-map + (let ((map (make-sparse-keymap))) + (define-key map (kbd "q") 'server-edit) + (define-key map (kbd "C-c C-c") 'server-edit) + + (define-key map (kbd "a") 'rebase-mode-abort) + (define-key map (kbd "C-c C-k") 'rebase-mode-abort) + + (define-key map (kbd "M-p") 'rebase-mode-move-line-up) + (define-key map (kbd "M-n") 'rebase-mode-move-line-down) + (define-key map (kbd "k") 'rebase-mode-kill-line) + (define-key map (kbd "x") 'rebase-mode-exec) + + (define-key map (kbd "n") 'forward-line) + (define-key map (kbd "p") '(lambda(n) + (interactive "p") + (forward-line (* n -1)))) + (define-key map [remap undo] 'rebase-mode-undo) + map) + "Keymap for rebase-mode. Note this will be added to by the +top-level code which defines the edit functions.") + +(require 'easymenu) +(easy-menu-define rebase-mode-menu rebase-mode-map + "Rebase-mode menu" + '("Rebase" + ["Pick" rebase-mode-pick t] + ["Reword" rebase-mode-reword t] + ["Edit" rebase-mode-edit t] + ["Squash" rebase-mode-squash t] + ["Fixup" rebase-mode-fixup t] + ["Kill" rebase-mode-kill-line t] + ["Move Down" rebase-mode-move-line-down t] + ["Move Up" rebase-mode-move-line-up t] + ["Execute" rebase-mode-exec t] + "---" + ["Abort" rebase-mode-abort t] + ["Done" server-edit t])) + +;; create the functions which edit the action lines themselves (based +;; on `key-to-action-map' above) +(mapc (lambda (key-action) + (let ((fun-name (intern (concat "rebase-mode-" (cdr key-action))))) + ;; define the function + (eval `(defun ,fun-name () + (interactive) + (rebase-mode-edit-line ,(cdr key-action)))) + + ;; bind the function in `rebase-mode-map' + (define-key rebase-mode-map (car key-action) fun-name))) + key-to-action-map) + +(defun rebase-mode-edit-line (change-to) + "Change the keyword at the start of the current action line to +that of CHANGE-TO." + (when (rebase-mode-looking-at-action) + (let ((buffer-read-only nil) + (start (point))) + (goto-char (point-at-bol)) + (delete-region (point) (progn (forward-word 1) (point))) + (insert change-to) + (goto-char start)))) + +(defun rebase-mode-looking-at-action () + "Return non-nil if looking at an action line." + (save-excursion + (goto-char (point-at-bol)) + (looking-at rebase-mode-action-line-re))) + +(defun rebase-mode-looking-at-action-or-exec () + "Return non-nil if looking at an action line or exec line." + (save-excursion + (goto-char (point-at-bol)) + (or (looking-at rebase-mode-action-line-re) + (looking-at rebase-mode-exec-line-re)))) + +(defun rebase-mode-looking-at-exec () + "Return non-nil if cursor is on an exec line." + (string-match rebase-mode-exec-line-re (thing-at-point 'line))) + +(defun rebase-mode-looking-at-killed-exec () + "Return non-nil if looking at an exec line that has been commented out" + (let ((line (thing-at-point 'line))) + (and (eq (aref line 0) ?#) + (string-match rebase-mode-exec-line-re line)))) + +(defun rebase-mode-move-line-up () + "Move the current action line up." + (interactive) + (when (rebase-mode-looking-at-action-or-exec) + (let ((buffer-read-only nil) + (col (current-column))) + (transpose-lines 1) + (forward-line -2) + (move-to-column col)))) + +(defun rebase-mode-move-line-down () + "Assuming the next line is also an action line, move the current line down." + (interactive) + ;; if we're on an action and the next line is also an action + (when (and (rebase-mode-looking-at-action-or-exec) + (save-excursion + (forward-line) + (rebase-mode-looking-at-action-or-exec))) + (let ((buffer-read-only nil) + (col (current-column))) + (forward-line 1) + (transpose-lines 1) + (forward-line -1) + (move-to-column col)))) + +(defun rebase-mode-abort () + "Abort this rebase (by emptying the buffer, saving and closing +server connection)." + (interactive) + (when (or (not (buffer-modified-p)) + (y-or-n-p "Abort this rebase? ")) + (let ((buffer-read-only nil)) + (delete-region (point-min) (point-max)) + (save-buffer) + (server-edit)))) + +(defun rebase-mode-kill-line () + "Kill the current action line." + (interactive) + (when (and (not (eq (char-after (point-at-bol)) ?#)) + (rebase-mode-looking-at-action-or-exec)) + (beginning-of-line) + (let ((buffer-read-only nil)) + (insert "#")) + (forward-line))) + +(defun rebase-mode-exec (edit) + "Prompt the user for a shell command to be executed, and add it to +the todo list. + +If the cursor is on a commented-out exec line, uncomment the +current line instead of prompting. + +When the prefix argument EDIT is non-nil and the cursor is on an +exec line, edit that line instead of inserting a new one. If the +exec line was commented out, also uncomment it." + (interactive "P") + (cond + ((and edit (rebase-mode-looking-at-exec)) + (let ((new-line (rebase-mode-read-exec-line + (match-string-no-properties 2 (thing-at-point 'line)))) + (inhibit-read-only t)) + (delete-region (point-at-bol) (point-at-eol)) + (if (not (equal "" new-line)) + (insert "exec " new-line) + (delete-char -1) + (forward-line)) + (move-beginning-of-line nil))) + ((rebase-mode-looking-at-killed-exec) + (save-excursion + (beginning-of-line) + (let ((buffer-read-only nil)) + (delete-char 1)))) + (t + (let ((inhibit-read-only t) + (line (rebase-mode-read-exec-line))) + (unless (equal "" line) + (move-end-of-line nil) + (newline) + (insert (concat "exec " line)))) + (move-beginning-of-line nil)))) + +(defun rebase-mode-read-exec-line (&optional initial-line) + (read-shell-command "Execute: " initial-line)) + +(defun rebase-mode-undo (&optional arg) + "A thin wrapper around `undo', which allows undoing in +read-only buffers." + (interactive "P") + (let ((inhibit-read-only t)) + (undo arg))) + +;;;###autoload +(define-derived-mode rebase-mode special-mode "Rebase" + "Major mode for editing of a Git rebase file. + +Rebase files are generated when you run 'git rebase -i' or run +`magit-interactive-rebase'. They describe how Git should perform +the rebase. See the documentation for git-rebase (e.g., by +running 'man git-rebase' at the command line) for details." + (setq font-lock-defaults '(rebase-mode-font-lock-keywords t t))) + +(defun rebase-mode-show-keybindings () + "Modify the \"Commands:\" section of the comment Git generates +at the bottom of the file so that in place of the one-letter +abbreviation for the command, it shows the command's keybinding. +By default, this is the same except for the \"pick\" command." + (save-excursion + (goto-char (point-min)) + (while (search-forward-regexp "^# \\(.\\), \\([[:alpha:]]+\\) = " nil t) + (let ((start (match-beginning 1)) + (end (match-end 1)) + (command (intern (concat "rebase-mode-" (match-string 2))))) + (when (fboundp command) + (let ((overlay (make-overlay start end))) + (overlay-put overlay + 'display + (key-description (where-is-internal command nil t))))))))) + +(add-hook 'rebase-mode-hook 'rebase-mode-show-keybindings t) + +(defun rebase-mode-disable-before-save-hook () + (set (make-local-variable 'before-save-hook) nil)) + +(add-hook 'rebase-mode-hook 'rebase-mode-disable-before-save-hook) + +;;;###autoload +(add-to-list 'auto-mode-alist + '("git-rebase-todo" . rebase-mode)) + +(provide 'rebase-mode) + +;;; rebase-mode.el ends here -- cgit v1.2.3