From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!.POSTED!not-for-mail From: Tino Calancha Newsgroups: gmane.emacs.bugs Subject: bug#25105: bug#25400: M-p in diff-mode jumps too far Date: Wed, 11 Jan 2017 13:38:11 +0900 Message-ID: <87a8aydxe4.fsf@gmail.com> References: NNTP-Posting-Host: blaine.gmane.org Mime-Version: 1.0 Content-Type: text/plain X-Trace: blaine.gmane.org 1484109565 17543 195.159.176.226 (11 Jan 2017 04:39:25 GMT) X-Complaints-To: usenet@blaine.gmane.org NNTP-Posting-Date: Wed, 11 Jan 2017 04:39:25 +0000 (UTC) User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/26.0.50 (gnu/linux) Cc: 25400@debbugs.gnu.org, tino.calancha@gmail.com, npostavs@users.sourceforge.net, Dima Kogan , Mark Oteiza , Dmitry Gutov , 25105@debbugs.gnu.org To: Stefan Monnier Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Wed Jan 11 05:39:19 2017 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by blaine.gmane.org with esmtp (Exim 4.84_2) (envelope-from ) id 1cRAgp-0003Lw-4E for geb-bug-gnu-emacs@m.gmane.org; Wed, 11 Jan 2017 05:39:11 +0100 Original-Received: from localhost ([::1]:51359 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cRAgt-0005Pe-Ie for geb-bug-gnu-emacs@m.gmane.org; Tue, 10 Jan 2017 23:39:15 -0500 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:57136) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cRAgk-0005PP-18 for bug-gnu-emacs@gnu.org; Tue, 10 Jan 2017 23:39:08 -0500 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1cRAgg-0001iu-Lo for bug-gnu-emacs@gnu.org; Tue, 10 Jan 2017 23:39:06 -0500 Original-Received: from debbugs.gnu.org ([208.118.235.43]:33893) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1cRAgg-0001ii-HP for bug-gnu-emacs@gnu.org; Tue, 10 Jan 2017 23:39:02 -0500 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1cRAgg-00028K-AQ for bug-gnu-emacs@gnu.org; Tue, 10 Jan 2017 23:39:02 -0500 X-Loop: help-debbugs@gnu.org Resent-From: Tino Calancha Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Wed, 11 Jan 2017 04:39:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 25105 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: Original-Received: via spool by 25105-submit@debbugs.gnu.org id=B25105.14841095058149 (code B ref 25105); Wed, 11 Jan 2017 04:39:02 +0000 Original-Received: (at 25105) by debbugs.gnu.org; 11 Jan 2017 04:38:25 +0000 Original-Received: from localhost ([127.0.0.1]:49290 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1cRAg4-00027M-CI for submit@debbugs.gnu.org; Tue, 10 Jan 2017 23:38:24 -0500 Original-Received: from mail-pf0-f194.google.com ([209.85.192.194]:36237) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1cRAg2-000275-9P; Tue, 10 Jan 2017 23:38:23 -0500 Original-Received: by mail-pf0-f194.google.com with SMTP id b22so15622295pfd.3; Tue, 10 Jan 2017 20:38:22 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:references:date:in-reply-to:message-id :user-agent:mime-version; bh=RQVOQeTZrpl7WNEA6yaGDjJYlvnyTxePEFChM9ypKeQ=; b=c2A4tCkRqVv+ROXSwWBORLtAUtUH7pQ3XKSUEgd6USrrO1z8MVhpoSAzqUU4GlZHLK gWGnOGAQqcFyaaiXVnTVmmvRcsb3lDXjXHM4dE6Too4Osaad5e9gs8wD/nEtaiVFlJD3 CKXJ/hqMPAsZUjZZpGDReMVbPk7x6P9Gnqvs72tVFxep7zXfX6FZ3E1u9l76jQyctJpB UfqXVIIx+Tbd5i5AfOU8gYH33aNtdQS4VAd+d2KZaDBft3uKn755wEbwzF8rrFHFRyF7 ms36HgLV+mhRTwomeEbeIw8nkFGd267sNPH5f6bmm3jKL8ft4lP2CZrJ8KiWxzKG1gCH BGNA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:references:date:in-reply-to :message-id:user-agent:mime-version; bh=RQVOQeTZrpl7WNEA6yaGDjJYlvnyTxePEFChM9ypKeQ=; b=ScVHNDpdfAZa1W77qEKF86kbN0UKILi6bERBh07v61RXTX0r1Nt2bruxRtOefg8FUX 2Ad2UBNHhlf+tug9iwncahGoLLf0tWHxkDUOEuhHr31CUS3wF2OUIYBTNt8JVK+pzeyg vHe96trAIZUMn1gLlVqg0S5hmMeOYmx6JaDLY7CRtsFVnJMgYfbCFdCYaMo1Rhte1Qj/ 5+G2W2IS3iY91uZI9oZcsY5i7K/rdbDLswzmz2dXcWc3ZwrvhMtxUUFxmJz/wN+7/mh6 3Nb3E+6vFFHD0Faf7W8i3CjzLhglEGVpi+24T79xXktIAfVRGQn6Y8aNk+ECX2ibnBuT rdsQ== X-Gm-Message-State: AIkVDXLngZhJzUs2rOstZ8Rz38o04zEG7NKp3TPS5/ZV1qppv570Q5lagTtyL5pwivtupQ== X-Received: by 10.84.128.67 with SMTP id 61mr10242243pla.153.1484109496231; Tue, 10 Jan 2017 20:38:16 -0800 (PST) Original-Received: from calancha-pc (217.225.128.101.dy.bbexcite.jp. [101.128.225.217]) by smtp.gmail.com with ESMTPSA id y62sm9325755pfk.52.2017.01.10.20.38.12 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Tue, 10 Jan 2017 20:38:15 -0800 (PST) In-Reply-To: (Stefan Monnier's message of "Sun, 08 Jan 2017 16:21:16 -0500") X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 208.118.235.43 X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Original-Sender: "bug-gnu-emacs" Xref: news.gmane.org gmane.emacs.bugs:127982 Archived-At: Stefan Monnier writes: > In a buffer with more than one hunk, if I'm in the middle of hunk number > N, diff-hunk-prev (usually bound to M-p) jumps to the header of hunk > number N-1 rather than to the header of hunk N. > > This is contrary to the usual behavior of Emacs's navigation commands. >As pointed out elsewhere, it's particularly obnoxious from EOB (in which >case, you're not really "within N" but you're virtually on "the header >of the non-existent hunk N+1", so going to the header of N-1 is really >wrong). > >I also dislike the fact that M-n doesn't let me get to EOB. Following patch reverts commit 2c8a7e5. Then it fixes dots 1. and 2. described in the commit message of 2c8a7e5, i.e., Bug#17544. This patch preserves the original definitions for 'diff-hunk-prev' and 'diff-hunk-next'. After applying locally this patch, you might want to do: git diff 2c8a7e5^ HEAD lisp/vc/diff-mode.el to see more clearly how it solves Bug#17544. Regards, Tino ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; >From a2dfaf390f4069b4e948dd0df84450359e7a0d92 Mon Sep 17 00:00:00 2001 From: Tino Calancha Date: Wed, 11 Jan 2017 13:20:04 +0900 Subject: [PATCH] Fix Bugs 25105 and 25400 Revert 2c8a7e5 and implement a new fix for Bug#17544. This patch satisfies 1. and 2. in 2c8a7e5 commit message. The original definitions for 'diff-hunk-prev' and 'diff-hunk-next' are preserved. * lisp/vc/diff-mode.el (diff-file-junk-re): Move definition before it's used. (diff--at-diff-header-p): New predicate. (diff-beginning-of-hunk): Use it. (diff-apply-hunk): Jump to beginning of hunk before apply the hunk. (diff-hunk-kill, diff-file-kill): Jump to beginning of hunk after kill. (diff-post-command-hook): Call diff-beginning-of-hunk with non-nil argument. --- lisp/vc/diff-mode.el | 241 ++++++++++++++++++--------------------------------- 1 file changed, 83 insertions(+), 158 deletions(-) diff --git a/lisp/vc/diff-mode.el b/lisp/vc/diff-mode.el index 9dfcd944bb..3fc4713f0f 100644 --- a/lisp/vc/diff-mode.el +++ b/lisp/vc/diff-mode.el @@ -498,22 +498,55 @@ diff-end-of-hunk ;; The return value is used by easy-mmode-define-navigation. (goto-char (or end (point-max))))) +;; "index ", "old mode", "new mode", "new file mode" and +;; "deleted file mode" are output by git-diff. +(defconst diff-file-junk-re + "diff \\|index \\|\\(?:deleted file\\|new\\(?: file\\)?\\|old\\) mode\\|=== modified file") + +;; If point is in a diff header, then return beginning +;; of hunk position otherwise return nil. +(defun diff--at-diff-header-p () + "Return non-nil if point is inside a diff header." + (let ((regexp-hunk diff-hunk-header-re) + (regexp-file diff-file-header-re) + (regexp-junk diff-file-junk-re) + (orig (point))) + (catch 'headerp + (save-excursion + (forward-line 0) + (when (looking-at regexp-hunk) ; Hunk header. + (throw 'headerp (point))) + (forward-line -1) + (when (re-search-forward regexp-file (point-at-eol 4) t) ; File header. + (forward-line 0) + (throw 'headerp (point))) + (goto-char orig) + (forward-line 0) + (when (looking-at regexp-junk) ; Git diff junk. + (while (and (looking-at regexp-junk) + (not (bobp))) + (forward-line -1)) + (re-search-forward regexp-file nil t) + (forward-line 0) + (throw 'headerp (point)))) nil))) + (defun diff-beginning-of-hunk (&optional try-harder) "Move back to the previous hunk beginning, and return its position. If point is in a file header rather than a hunk, advance to the next hunk if TRY-HARDER is non-nil; otherwise signal an error." (beginning-of-line) - (if (looking-at diff-hunk-header-re) + (if (looking-at diff-hunk-header-re) ; At hunk header. (point) - (forward-line 1) - (condition-case () - (re-search-backward diff-hunk-header-re) - (error - (unless try-harder - (error "Can't find the beginning of the hunk")) - (diff-beginning-of-file-and-junk) - (diff-hunk-next) - (point))))) + (let ((pos (diff--at-diff-header-p)) + (regexp diff-hunk-header-re)) + (cond (pos ; At junk diff header. + (if try-harder + (goto-char pos) + (error "Can't find the beginning of the hunk"))) + ((re-search-backward regexp nil t)) ; In the middle of a hunk. + ((re-search-forward regexp nil t) ; At first hunk header. + (forward-line 0)) + (t (error "Can't find the beginning of the hunk")))))) (defun diff-unified-hunk-p () (save-excursion @@ -551,124 +584,26 @@ diff--auto-refine-data ;; Define diff-{hunk,file}-{prev,next} (easy-mmode-define-navigation - diff--internal-hunk diff-hunk-header-re "hunk" diff-end-of-hunk diff-restrict-view) + diff-hunk diff-hunk-header-re "hunk" diff-end-of-hunk diff-restrict-view + (when diff-auto-refine-mode + (unless (prog1 diff--auto-refine-data + (setq diff--auto-refine-data + (cons (current-buffer) (point-marker)))) + (run-at-time 0.0 nil + (lambda () + (when diff--auto-refine-data + (let ((buffer (car diff--auto-refine-data)) + (point (cdr diff--auto-refine-data))) + (setq diff--auto-refine-data nil) + (with-local-quit + (when (buffer-live-p buffer) + (with-current-buffer buffer + (save-excursion + (goto-char point) + (diff-refine-hunk)))))))))))) (easy-mmode-define-navigation - diff--internal-file diff-file-header-re "file" diff-end-of-file) - -(defun diff--wrap-navigation (skip-hunk-start - what orig - header-re goto-start-func count) - "Wrap diff-{hunk,file}-{next,prev} for more intuitive behavior. -Override the default diff-{hunk,file}-{next,prev} implementation -by skipping any lines that are associated with this hunk/file but -precede the hunk-start marker. For instance, a diff file could -contain - -diff --git a/lisp/vc/diff-mode.el b/lisp/vc/diff-mode.el -index 923de9a..6b1c24f 100644 ---- a/lisp/vc/diff-mode.el -+++ b/lisp/vc/diff-mode.el -@@ -590,6 +590,22 @@ -....... - -If a point is on 'index', then the point is considered to be in -this first hunk. Move the point to the @@... marker before -executing the default diff-hunk-next/prev implementation to move -to the NEXT marker." - (if (not skip-hunk-start) - (funcall orig count) - - (let ((start (point))) - (funcall goto-start-func) - - ;; Trap the error. - (condition-case nil - (funcall orig count) - (error nil)) - - (when (not (looking-at header-re)) - (goto-char start) - (user-error (format "No %s" what))) - - ;; We successfully moved to the next/prev hunk/file. Apply the - ;; auto-refinement if needed - (when diff-auto-refine-mode - (unless (prog1 diff--auto-refine-data - (setq diff--auto-refine-data - (cons (current-buffer) (point-marker)))) - (run-at-time 0.0 nil - (lambda () - (when diff--auto-refine-data - (let ((buffer (car diff--auto-refine-data)) - (point (cdr diff--auto-refine-data))) - (setq diff--auto-refine-data nil) - (with-local-quit - (when (buffer-live-p buffer) - (with-current-buffer buffer - (save-excursion - (goto-char point) - (diff-refine-hunk)))))))))))))) - -;; These functions all take a skip-hunk-start argument which controls -;; whether we skip pre-hunk-start text or not. In interactive uses we -;; always want to do this, but the simple behavior is still necessary -;; to, for example, avoid an infinite loop: -;; -;; diff-hunk-next calls -;; diff--wrap-navigation calls -;; diff-bounds-of-hunk calls -;; diff-beginning-of-hunk calls -;; diff-hunk-next -;; -;; Here the outer diff-hunk-next has skip-hunk-start set to t, but the -;; inner one does not, which breaks the loop. -(defun diff-hunk-prev (&optional count skip-hunk-start) - "Go to the previous COUNT'th hunk." - (interactive (list (prefix-numeric-value current-prefix-arg) t)) - (diff--wrap-navigation - skip-hunk-start - "prev hunk" - 'diff--internal-hunk-prev - diff-hunk-header-re - (lambda () (goto-char (car (diff-bounds-of-hunk)))) - count)) - -(defun diff-hunk-next (&optional count skip-hunk-start) - "Go to the next COUNT'th hunk." - (interactive (list (prefix-numeric-value current-prefix-arg) t)) - (diff--wrap-navigation - skip-hunk-start - "next hunk" - 'diff--internal-hunk-next - diff-hunk-header-re - (lambda () (goto-char (car (diff-bounds-of-hunk)))) - count)) - -(defun diff-file-prev (&optional count skip-hunk-start) - "Go to the previous COUNT'th file." - (interactive (list (prefix-numeric-value current-prefix-arg) t)) - (diff--wrap-navigation - skip-hunk-start - "prev file" - 'diff--internal-file-prev - diff-file-header-re - (lambda () (goto-char (car (diff-bounds-of-file))) (diff--internal-hunk-next)) - count)) - -(defun diff-file-next (&optional count skip-hunk-start) - "Go to the next COUNT'th file." - (interactive (list (prefix-numeric-value current-prefix-arg) t)) - (diff--wrap-navigation - skip-hunk-start - "next file" - 'diff--internal-file-next - diff-file-header-re - (lambda () (goto-char (car (diff-bounds-of-file))) (diff--internal-hunk-next)) - count)) - - - + diff-file diff-file-header-re "file" diff-end-of-file) (defun diff-bounds-of-hunk () "Return the bounds of the diff hunk at point. @@ -679,13 +614,12 @@ diff-bounds-of-hunk (let ((pos (point)) (beg (diff-beginning-of-hunk t)) (end (diff-end-of-hunk))) - (cond ((> end pos) + (cond ((>= end pos) (list beg end)) ;; If this hunk ends above POS, consider the next hunk. ((re-search-forward diff-hunk-header-re nil t) (list (match-beginning 0) (diff-end-of-hunk))) - ;; There's no next hunk, so just take the one we have. - (t (list beg end)))))) + (t (error "No hunk found")))))) (defun diff-bounds-of-file () "Return the bounds of the file segment at point. @@ -731,12 +665,8 @@ diff-hunk-kill hunk-bounds)) (inhibit-read-only t)) (apply 'kill-region bounds) - (goto-char (car bounds)))) - -;; "index ", "old mode", "new mode", "new file mode" and -;; "deleted file mode" are output by git-diff. -(defconst diff-file-junk-re - "diff \\|index \\|\\(?:deleted file\\|new\\(?: file\\)?\\|old\\) mode\\|=== modified file") + (goto-char (car bounds)) + (diff-beginning-of-hunk t))) (defun diff-beginning-of-file-and-junk () "Go to the beginning of file-related diff-info. @@ -771,7 +701,7 @@ diff-beginning-of-file-and-junk (setq prevfile nextfile)) (if (and previndex (numberp prevfile) (< previndex prevfile)) (setq prevfile previndex)) - (if (numberp prevfile) + (if (and (numberp prevfile) (<= prevfile start)) (progn (goto-char prevfile) ;; Now skip backward over the leading junk we may have before the @@ -789,7 +719,8 @@ diff-file-kill "Kill current file's hunks." (interactive) (let ((inhibit-read-only t)) - (apply 'kill-region (diff-bounds-of-file)))) + (apply 'kill-region (diff-bounds-of-file))) + (diff-beginning-of-hunk t)) (defun diff-kill-junk () "Kill spurious empty diffs." @@ -1373,7 +1304,7 @@ diff-post-command-hook ;; it's safer not to do it on big changes, e.g. when yanking a big ;; diff, or when the user edits the header, since we might then ;; screw up perfectly correct values. --Stef - (diff-beginning-of-hunk) + (diff-beginning-of-hunk t) (let* ((style (if (looking-at "\\*\\*\\*") 'context)) (start (line-beginning-position (if (eq style 'context) 3 2))) (mid (if (eq style 'context) @@ -1764,9 +1695,8 @@ diff-find-source-location SWITCHED is non-nil if the patch is already applied. NOPROMPT, if non-nil, means not to prompt the user." (save-excursion - (let* ((hunk-bounds (diff-bounds-of-hunk)) - (other (diff-xor other-file diff-jump-to-old-file)) - (char-offset (- (point) (goto-char (car hunk-bounds)))) + (let* ((other (diff-xor other-file diff-jump-to-old-file)) + (char-offset (- (point) (diff-beginning-of-hunk t))) ;; Check that the hunk is well-formed. Otherwise diff-mode and ;; the user may disagree on what constitutes the hunk ;; (e.g. because an empty line truncates the hunk mid-course), @@ -1775,7 +1705,7 @@ diff-find-source-location ;; Suppress check when NOPROMPT is non-nil (Bug#3033). (_ (unless noprompt (diff-sanity-check-hunk))) (hunk (buffer-substring - (point) (cadr hunk-bounds))) + (point) (save-excursion (diff-end-of-hunk) (point)))) (old (diff-hunk-text hunk reverse char-offset)) (new (diff-hunk-text hunk (not reverse) char-offset)) ;; Find the location specification. @@ -1838,6 +1768,7 @@ diff-apply-hunk With a prefix argument, REVERSE the hunk." (interactive "P") + (diff-beginning-of-hunk t) (pcase-let ((`(,buf ,line-offset ,pos ,old ,new ,switched) ;; Sometimes we'd like to have the following behavior: if ;; REVERSE go to the new file, otherwise go to the old. @@ -1883,15 +1814,8 @@ diff-apply-hunk ;; Display BUF in a window (set-window-point (display-buffer buf) (+ (car pos) (cdr new))) (diff-hunk-status-msg line-offset (diff-xor switched reverse) nil) - - ;; Advance to the next hunk with skip-hunk-start set to t - ;; because we want the behavior of moving to the next logical - ;; hunk, not the original behavior where were would sometimes - ;; stay on the current hunk. This is the behavior we get when - ;; navigating through hunks interactively, and we want it when - ;; applying hunks too (see http://debbugs.gnu.org/17544). (when diff-advance-after-apply-hunk - (diff-hunk-next nil t)))))) + (diff-hunk-next)))))) (defun diff-test-hunk (&optional reverse) @@ -1972,15 +1896,14 @@ diff-current-defun (defun diff-ignore-whitespace-hunk () "Re-diff the current hunk, ignoring whitespace differences." (interactive) - (let* ((hunk-bounds (diff-bounds-of-hunk)) - (char-offset (- (point) (goto-char (car hunk-bounds)))) + (let* ((char-offset (- (point) (diff-beginning-of-hunk t))) (opts (pcase (char-after) (?@ "-bu") (?* "-bc") (_ "-b"))) (line-nb (and (or (looking-at "[^0-9]+\\([0-9]+\\)") (error "Can't find line number")) (string-to-number (match-string 1)))) (inhibit-read-only t) (hunk (delete-and-extract-region - (point) (cadr hunk-bounds))) + (point) (save-excursion (diff-end-of-hunk) (point)))) (lead (make-string (1- line-nb) ?\n)) ;Line nums start at 1. (file1 (make-temp-file "diff1")) (file2 (make-temp-file "diff2")) @@ -2067,14 +1990,16 @@ diff-refine-hunk (interactive) (require 'smerge-mode) (save-excursion - (let* ((hunk-bounds (diff-bounds-of-hunk)) - (style (progn (goto-char (car hunk-bounds)) - (diff-hunk-style))) ;Skips the hunk header as well. + (diff-beginning-of-hunk t) + (let* ((start (point)) + (style (diff-hunk-style)) ;Skips the hunk header as well. (beg (point)) - (end (cadr hunk-bounds)) (props-c '((diff-mode . fine) (face diff-refine-changed))) (props-r '((diff-mode . fine) (face diff-refine-removed))) - (props-a '((diff-mode . fine) (face diff-refine-added)))) + (props-a '((diff-mode . fine) (face diff-refine-added))) + ;; Be careful to go back to `start' so diff-end-of-hunk gets + ;; to read the hunk header's line info. + (end (progn (goto-char start) (diff-end-of-hunk) (point)))) (remove-overlays beg end 'diff-mode 'fine) -- 2.11.0 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; In GNU Emacs 26.0.50.1 (x86_64-pc-linux-gnu, GTK+ Version 3.22.5) of 2017-01-10 Repository revision: fa0a2b4e7c81f57aecc1d94df00588a4dd5c281d