X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/642eb8b6afa1c16b134d296ed90fd8fe59dc1d49..c87c2cad94ab0570846015dcef91a38e84317be9:/lisp/indent.el diff --git a/lisp/indent.el b/lisp/indent.el index e733ece66d..0bbb5209e8 100644 --- a/lisp/indent.el +++ b/lisp/indent.el @@ -1,8 +1,8 @@ ;;; indent.el --- indentation commands for Emacs -*- lexical-binding:t -*- -;; Copyright (C) 1985, 1995, 2001-2013 Free Software Foundation, Inc. +;; Copyright (C) 1985, 1995, 2001-2016 Free Software Foundation, Inc. -;; Maintainer: FSF +;; Maintainer: emacs-devel@gnu.org ;; Package: emacs ;; This file is part of GNU Emacs. @@ -76,15 +76,32 @@ that case, indent by aligning to the previous non-blank line." ;; indenting. Replace with something ad-hoc. (let ((column (save-excursion (beginning-of-line) - (skip-chars-backward "\n \t") - (beginning-of-line) - (current-indentation)))) + (if (bobp) 0 + (beginning-of-line 0) + (if (looking-at "[ \t]*$") 0 + (current-indentation)))))) (if (<= (current-column) (current-indentation)) (indent-line-to column) (save-excursion (indent-line-to column)))) ;; The normal case. (funcall indent-line-function))) +(defun indent--default-inside-comment () + (unless (or (> (current-column) (current-indentation)) + (eq this-command last-command)) + (let ((ppss (syntax-ppss))) + (when (nth 4 ppss) + (indent-line-to + (save-excursion + (forward-line -1) + (skip-chars-forward " \t") + (when (< (1- (point)) (nth 8 ppss) (line-end-position)) + (goto-char (nth 8 ppss)) + (when (looking-at comment-start-skip) + (goto-char (match-end 0)))) + (current-column))) + t)))) + (defun indent-for-tab-command (&optional arg) "Indent the current line or region, or insert a tab, as appropriate. This function either inserts a tab, or indents the current line, @@ -123,7 +140,11 @@ prefix argument is ignored." (old-indent (current-indentation))) ;; Indent the line. - (funcall indent-line-function) + (or (not (eq (funcall indent-line-function) 'noindent)) + (indent--default-inside-comment) + (when (or (<= (current-column) (current-indentation)) + (not (eq tab-always-indent 'complete))) + (funcall (default-value 'indent-line-function)))) (cond ;; If the text was already indented right, try completion. @@ -169,37 +190,35 @@ Blank lines are ignored." (defvar indent-rigidly-map (let ((map (make-sparse-keymap))) - (define-key map [left] - (lambda (beg end) (interactive "r") (indent-rigidly beg end -1))) - - (define-key map [right] - (lambda (beg end) (interactive "r") (indent-rigidly beg end 1))) - - (define-key map [S-right] - (lambda (beg end) (interactive "r") - (let* ((current (indent-rigidly--current-indentation beg end)) - (next (indent--next-tab-stop current))) - (indent-rigidly beg end (- next current))))) - - (define-key map [S-left] - (lambda (beg end) (interactive "r") - (let* ((current (indent-rigidly--current-indentation beg end)) - (next (indent--next-tab-stop current 'prev))) - (indent-rigidly beg end (- next current))))) - map)) + (define-key map [left] 'indent-rigidly-left) + (define-key map [right] 'indent-rigidly-right) + (define-key map [S-left] 'indent-rigidly-left-to-tab-stop) + (define-key map [S-right] 'indent-rigidly-right-to-tab-stop) + map) + "Transient keymap for adjusting indentation interactively. +It is activated by calling `indent-rigidly' interactively.") (defun indent-rigidly (start end arg &optional interactive) - "Indent all lines starting in the region sideways by ARG columns. -Called from a program, takes three arguments, START, END and ARG. -You can remove all indentation from a region by giving a large negative ARG. -If used interactively and no prefix argument is given, use a transient -mode that lets you move the text with cursor keys." + "Indent all lines starting in the region. +If called interactively with no prefix argument, activate a +transient mode in which the indentation can be adjusted interactively +by typing \\\\[indent-rigidly-left], \\[indent-rigidly-right], \\[indent-rigidly-left-to-tab-stop], or \\[indent-rigidly-right-to-tab-stop]. +Typing any other key deactivates the transient mode. + +If called from a program, or interactively with prefix ARG, +indent all lines starting in the region forward by ARG columns. +If called from a program, START and END specify the beginning and +end of the text to act on, in place of the region. + +Negative values of ARG indent backward, so you can remove all +indentation by specifying a large negative ARG." (interactive "r\nP\np") (if (and (not arg) interactive) (progn - (message "Edit region indentation with , , \ -and .") - (set-temporary-overlay-map indent-rigidly-map t)) + (message + (substitute-command-keys + "Indent region with \\\\[indent-rigidly-left], \\[indent-rigidly-right], \\[indent-rigidly-left-to-tab-stop], or \\[indent-rigidly-right-to-tab-stop].")) + (set-transient-map indent-rigidly-map t)) (save-excursion (goto-char end) (setq end (point-marker)) @@ -215,13 +234,58 @@ and .") (indent-to (max 0 (+ indent (prefix-numeric-value arg))) 0)) (delete-region (point) (progn (skip-chars-forward " \t") (point)))) (forward-line 1)) - (move-marker end nil)))) + (move-marker end nil) + ;; Keep the active region in transient mode. + (when (eq (cadr overriding-terminal-local-map) indent-rigidly-map) + (setq deactivate-mark nil))))) + +(defun indent-rigidly--pop-undo () + (and (memq last-command '(indent-rigidly-left indent-rigidly-right + indent-rigidly-left-to-tab-stop + indent-rigidly-right-to-tab-stop)) + (consp buffer-undo-list) + (eq (car buffer-undo-list) nil) + (pop buffer-undo-list))) + +(defun indent-rigidly-left (beg end) + "Indent all lines between BEG and END leftward by one space." + (interactive "r") + (indent-rigidly--pop-undo) + (indent-rigidly + beg end + (if (eq (current-bidi-paragraph-direction) 'right-to-left) 1 -1))) + +(defun indent-rigidly-right (beg end) + "Indent all lines between BEG and END rightward by one space." + (interactive "r") + (indent-rigidly--pop-undo) + (indent-rigidly + beg end + (if (eq (current-bidi-paragraph-direction) 'right-to-left) -1 1))) + +(defun indent-rigidly-left-to-tab-stop (beg end) + "Indent all lines between BEG and END leftward to a tab stop." + (interactive "r") + (indent-rigidly--pop-undo) + (let* ((current (indent-rigidly--current-indentation beg end)) + (rtl (eq (current-bidi-paragraph-direction) 'right-to-left)) + (next (indent-next-tab-stop current (if rtl nil 'prev)))) + (indent-rigidly beg end (- next current)))) + +(defun indent-rigidly-right-to-tab-stop (beg end) + "Indent all lines between BEG and END rightward to a tab stop." + (interactive "r") + (indent-rigidly--pop-undo) + (let* ((current (indent-rigidly--current-indentation beg end)) + (rtl (eq (current-bidi-paragraph-direction) 'right-to-left)) + (next (indent-next-tab-stop current (if rtl 'prev)))) + (indent-rigidly beg end (- next current)))) (defun indent-line-to (column) "Indent current line to COLUMN. This function removes or adds spaces and tabs at beginning of line only if necessary. It leaves point at end of indentation." - (back-to-indentation) + (backward-to-indentation 0) (let ((cur-col (current-column))) (cond ((< cur-col column) (if (>= (- column (* (/ cur-col tab-width) tab-width)) tab-width) @@ -230,7 +294,7 @@ only if necessary. It leaves point at end of indentation." (indent-to column)) ((> cur-col column) ; too far right (after tab?) (delete-region (progn (move-to-column column t) (point)) - (progn (back-to-indentation) (point))))))) + (progn (backward-to-indentation 0) (point))))))) (defun current-left-margin () "Return the left margin to use for this line. @@ -481,18 +545,19 @@ column to indent to; if it is nil, use one of the three methods above." (save-excursion (setq end (copy-marker end)) (goto-char start) - (let ((pr (make-progress-reporter "Indenting region..." (point) end))) - (while (< (point) end) - (or (and (bolp) (eolp)) - (indent-according-to-mode)) + (let ((pr (unless (minibufferp) + (make-progress-reporter "Indenting region..." (point) end)))) + (while (< (point) end) + (or (and (bolp) (eolp)) + (indent-according-to-mode)) (forward-line 1) - (progress-reporter-update pr (point))) - (progress-reporter-done pr) + (and pr (progress-reporter-update pr (point)))) + (and pr (progress-reporter-done pr)) (move-marker end nil))))) ;; In most cases, reindenting modifies the buffer, but it may also ;; leave it unmodified, in which case we have to deactivate the mark ;; by hand. - (deactivate-mark)) + (setq deactivate-mark t)) (defun indent-relative-maybe () "Indent a new line like previous nonblank line. @@ -541,16 +606,17 @@ See also `indent-relative-maybe'." (move-marker opoint nil)) (tab-to-tab-stop)))) -(defcustom tab-stop-list - nil +(defcustom tab-stop-list nil "List of tab stop positions used by `tab-to-tab-stop'. -This should be a list of integers, ordered from smallest to largest. -It implicitly extends to infinity by repeating the last step (e.g. '(1 2 5) -is equivalent to '(1 2 5 8 11)). -If the list has less than 2 elements, `tab-width' is used as the \"last step\"." +This should be nil, or a list of integers, ordered from smallest to largest. +It implicitly extends to infinity through repetition of the last step. +For example, (1 2 5) is equivalent to (1 2 5 8 11 ...). If the list has +fewer than 2 elements, `tab-width' is used as the \"last step\". +A value of nil means a tab stop every `tab-width' columns." :group 'indent + :version "24.4" ; from explicit list to nil + :safe 'listp :type '(repeat integer)) -(put 'tab-stop-list 'safe-local-variable 'listp) (defvar edit-tab-stops-map (let ((map (make-sparse-keymap))) @@ -608,7 +674,7 @@ You can add or remove colons and then do \\\\[edit-tab-stops (setq tab-stop-list tabs)) (message "Tab stops installed")) -(defun indent--next-tab-stop (column &optional prev) +(defun indent-next-tab-stop (column &optional prev) "Return the next tab stop after COLUMN. If PREV is non-nil, return the previous one instead." (let ((tabs tab-stop-list)) @@ -631,6 +697,13 @@ If PREV is non-nil, return the previous one instead." (if (<= column last) -1 (/ (- column last 1) step)) (1+ (/ (- column last) step))))))))) +(defun indent-accumulate-tab-stops (limit) + "Get a list of tab stops before LIMIT (inclusive)." + (let ((tab 0) (tab-stops)) + (while (<= (setq tab (indent-next-tab-stop tab)) limit) + (push tab tab-stops)) + (nreverse tab-stops))) + (defun tab-to-tab-stop () "Insert spaces or tabs to next defined tab-stop column. The variable `tab-stop-list' is a list of columns at which there are tab stops. @@ -638,7 +711,7 @@ Use \\[edit-tab-stops] to edit them interactively." (interactive) (and abbrev-mode (= (char-syntax (preceding-char)) ?w) (expand-abbrev)) - (let ((nexttab (indent--next-tab-stop (current-column)))) + (let ((nexttab (indent-next-tab-stop (current-column)))) (delete-horizontal-space t) (indent-to nexttab))) @@ -647,7 +720,7 @@ Use \\[edit-tab-stops] to edit them interactively." The variable `tab-stop-list' is a list of columns at which there are tab stops. Use \\[edit-tab-stops] to edit them interactively." (interactive) - (let ((nexttab (indent--next-tab-stop (current-column)))) + (let ((nexttab (indent-next-tab-stop (current-column)))) (let ((before (point))) (move-to-column nexttab t) (save-excursion