gnu-emacs-sources
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

mindent 1.10 - fixes a minor bug with mouse indentation


From: Ian Zimmerman
Subject: mindent 1.10 - fixes a minor bug with mouse indentation
Date: 21 Aug 2004 09:14:46 -0700
User-agent: Gnus/5.09 (Gnus v5.9.0) Emacs/21.3

;;; mindent.el --- simple non-syntax sensitive indentation

;; This file 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, or (at your option)
;; any later version.

;; This file 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 GNU Emacs; see the file COPYING.  If not, write to
;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.

;; Copyright (C) Ian Zimmerman, February 2002

;; $Id: mindent.el,v 1.10 2004/08/21 16:12:02 itz Exp $

(defvar mindent-comment-predicate (lambda () nil)
  "A predicate function called to determine if the point is in a comment.
By default, always returns nil.")

(make-variable-buffer-local 'mindent-comment-predicate)

(defun mindent-bind (kmap &optional newline)
  "Add mindent bindings to KMAP; return KMAP.
If optional NEWLINE is not nil, rebind that key sequence to 
`mindent-newline-and-indent'."
  (define-key kmap "\M-p" 'mindent-backward-dwim)
  (define-key kmap "\M-n" 'mindent-forward-dwim)
  (define-key kmap "\M-i" 'mindent-indent-relative)
  (define-key kmap "\M-\C-z" 'mindent-indent-to-char)
  (define-key kmap "\M-s" 'mindent-indent-as-line-starting)
  (if newline (define-key kmap newline 'mindent-newline-and-indent))
  (define-key kmap [?\C-c mouse-3] 'mindent-indent-to-mouse)
  (define-key kmap [?\C-c C-mouse-3] 'mindent-indent-as-mouse-line)
  (define-key kmap [?\C-c mouse-1] 'mindent-indent-region-to-mouse)
  (define-key kmap [?\C-c C-mouse-1] 'mindent-indent-region-as-mouse-line)
  kmap)  

(defsubst mindent-setup (comment-predicate)
  (setq mindent-comment-predicate comment-predicate)
  (make-local-variable 'indent-line-function)
  (setq indent-line-function 'mindent-indent-line)
  (make-local-variable 'indent-region-function)
  (setq indent-region-function 'mindent-indent-region))

(defun mindent-newline-and-indent (&optional p)
  "Like \\<global-map>\\[newline-and-indent], but indent P spaces more.
If P is an integer, indent the new line P spaces relative to the current
line."
  (interactive "P")
  (let ((i (current-indentation))
        (offset (get-text-property (point) 'mindent-offset)))
    (newline-and-indent)
    (when (integerp p) (setq i (+ i p)))
    (when offset
      (setq i (+ i offset))
      (let ((end (next-single-property-change (point) 'mindent-offset))
            (start (save-excursion (beginning-of-line) (point))))
        (remove-text-properties start end '(mindent-offset nil))))
    (indent-line-to i)))

(defun mindent-backward-to-same-indent (&optional n)
  "Move point back  N lines with less or same indentation."
  (interactive "p")
  (beginning-of-line 1)
  (if (< n 0) (mindent-forward-to-same-indent (- n))
    (while (> n 0)
      (let ((i (current-indentation)))
        (forward-line -1)
        (while (or (> (current-indentation) i)
                   (funcall mindent-comment-predicate)
                   (looking-at
                    (concat "[ \t]*\\(\n\\|" comment-start-skip "\\)")))
          (forward-line -1)))
      (setq n (1- n))))
  (back-to-indentation))

(defun mindent-forward-to-same-indent (&optional n)
  "Move point forward N lines with less or same indentation."
  (interactive "p")
  (beginning-of-line 1)
  (if (< n 0) (mindent-backward-to-same-indent (- n))
    (while (> n 0)
      (let ((i (current-indentation)))
        (forward-line 1)
        (while (or (> (current-indentation) i)
                   (funcall mindent-comment-predicate)
                   (looking-at
                    (concat "[ \t]*\\(\n\\|" comment-start-skip "\\)")))
          (forward-line 1)))
      (setq n (1- n))))
  (back-to-indentation))

(defun mindent-backward-to-less-indent (&optional n)
  "Move point back  N lines with stricly less indentation."
  (interactive "p")
  (beginning-of-line 1)
  (if (< n 0) (mindent-forward-to-less-indent (- n))
    (while (> n 0)
      (let ((i (current-indentation)))
        (forward-line -1)
        (while (or (>= (current-indentation) i)
                   (funcall mindent-comment-predicate)
                   (looking-at
                    (concat "[ \t]*\\(\n\\|" comment-start-skip "\\)")))
          (if (bobp) (error "Beginning of buffer"))
          (forward-line -1)))
      (setq n (1- n))))
  (back-to-indentation))

(defun mindent-forward-to-less-indent (&optional n)
  "Move point forward N lines with strictly less indentation."
  (interactive "p")
  (beginning-of-line 1)
  (if (< n 0) (mindent-backward-to-less-indent (- n))
    (while (> n 0)
      (let ((i (current-indentation)))
        (forward-line 1)
        (while (or (>= (current-indentation) i)
                   (funcall mindent-comment-predicate)
                   (looking-at
                    (concat "[ \t]*\\(\n\\|" comment-start-skip "\\)")))
          (if (eobp) (error "End of buffer"))
          (forward-line 1)))
      (setq n (1- n))))
  (back-to-indentation))

(defun mindent-forward-dwim (&optional arg)
  "Move point forward to a line with indentation similar to current line.
The precise semantics of this command depend on the optional ARG,
and on the variable `last-command'.  If ARG is nil, an integer, or the
symbol `-' *and* `last-command' is not `mindent-forward-to-less-indent',
this command behaves like `mindent-forward-to-same-indent'.  Otherwise
it acts like `mindent-forward-to-less-indent' with an argument that is
the number of times the universal prefix argument was given."
  (interactive "P")
  (if (and (not (eq last-command 'mindent-forward-to-less-indent))
           (or (null arg)
               (integerp arg)
               (and (symbolp arg) (eq arg '-))))
      (mindent-forward-to-same-indent (prefix-numeric-value arg))
    (let ((real-arg
           (if (null arg) 1
             (truncate (log (prefix-numeric-value arg) 4)))))
      (mindent-forward-to-less-indent real-arg)
      (setq this-command 'mindent-forward-to-less-indent))))

(defun mindent-backward-dwim (&optional arg)
  "Move point backward to a line with indentation similar to current line.
The precise semantics of this command depend on the optional ARG,
and on the variable `last-command'.  If ARG is nil, an integer, or the
symbol `-' *and* `last-command' is not `mindent-backward-to-less-indent',
this command behaves like `mindent-backward-to-same-indent'.  Otherwise
it acts like `mindent-backward-to-less-indent' with an argument that is
the number of times the universal prefix argument was given."
  (interactive "P")
  (if (and (not (eq last-command 'mindent-backward-to-less-indent))
           (or (null arg)
               (integerp arg)
               (and (symbolp arg) (eq arg '-))))
      (mindent-backward-to-same-indent (prefix-numeric-value arg))
    (let ((real-arg
           (if (null arg) 1
             (truncate (log (prefix-numeric-value arg) 4)))))
      (mindent-backward-to-less-indent real-arg)
      (setq this-command 'mindent-backward-to-less-indent))))      

(defun mindent-internal-indent-once (&optional bol-ok)
  "Indent to the next available indentation point.
Indentation points are the columns where the previous nonblank line
has a blank character, followed by a nonblank character.
Additionally, if BOL-OK is set, a nonblank character in column 0
is considered an indentation point."
  (let* ((here (current-column))
         (indp
          (save-excursion
            (if (not (re-search-backward "\\(.\\|\n\\)\n" nil t)) 0
              (beginning-of-line)
              (while (and (not (bobp))
                          (or (funcall mindent-comment-predicate)
                              (looking-at (concat "[ \t]*\\(\n\\|"
                                                  comment-start-skip
                                                  "\\)"))))
                (forward-line -1))
              (end-of-line)
              (let ((endp (point)))
                (move-to-column here)
                (unless (and bol-ok (bolp) (looking-at "\\S "))
                  (re-search-forward "\\s \\S " endp 'move)
                  (backward-char 1))
                (current-column))))))
    (indent-line-to indp)))

(defun mindent-internal-indent (n &optional bol-ok)
  "Go forward N indentation points, or as many as possible.
Assume point is exactly on left margin to start with."
  (cond
   ((= n 0) nil)
   ((> n 0)
    (mindent-internal-indent-once bol-ok)
    (mindent-internal-indent (- n 1)))))

(defsubst mindent-maybe-reindent (goal)
  (if (<= (current-column) (current-indentation)) (indent-line-to goal)
    (save-excursion (indent-line-to goal))))

(defun mindent-unindent-line (n)
  "Unindent current line N levels.
That is, find the Nth stricly less indented line preceding
this one and reindent to it."
  (interactive "p")
  (let ((indp
         (save-excursion
           (mindent-backward-to-less-indent n)
           (current-indentation))))
    (mindent-maybe-reindent indp)))

(defun mindent-indent-line ()
  "Indent the current line the same as last nonblank one."
  (interactive)
  (let ((indp
         (cond
          ((save-excursion
             (not (re-search-backward "\\(.\\|\n\\)\n" nil t))) 0)
          ((and
            (funcall mindent-comment-predicate)
            (not
             (save-excursion
               (let ((p (point)))
                 (beginning-of-line)
                 (re-search-forward comment-start-skip p t))))
            (save-excursion
              (forward-line -1)
              (beginning-of-line)
              (or (and (funcall mindent-comment-predicate)
                       (looking-at "[ \t]*"))
                  (looking-at (concat "[ \t]*" comment-start-skip))))
           (save-excursion
             (goto-char (match-end 0))
             (current-column))))
          (t
           (save-excursion
             (re-search-backward "\\(.\\|\n\\)\n")
             (beginning-of-line)
             (while (and (not (bobp))
                         (or (funcall mindent-comment-predicate)
                             (looking-at (concat "[ \t]*\\(\n\\|"
                                                 comment-start-skip
                                                 "\\)"))))
               (forward-line -1))
             (current-indentation))))))
    (mindent-maybe-reindent indp)))

(defun mindent-indent-relative (n)
  "Indent current line relative to the Nth indentation point.
Indentation points are the columns where the previous nonblank line
has a blank character, followed by a nonblank character.
With negative N, unindent current line N levels.
In transient mark mode, indents the entire region as above."
  (interactive "p")
  (cond
   ((and transient-mark-mode mark-active)
    (let ((start (min (point) (mark)))
          (end (max (point) (mark))))
      (mindent-indent-region-relative n start end)))
   ((< n 0)
    (mindent-unindent-line (- n)))
   ((> (current-column) (current-indentation))
    (save-excursion
      (back-to-indentation)
      (mindent-internal-indent n)))
   (t
    (back-to-indentation)
    (mindent-internal-indent n))))

(defun mindent-indent-to-char (c n)
  "Indent current line to the Nth occurrence of C on the previous line.
In transient mark mode, indents the entire region to such occurrence."
  (interactive "cIndent to character: \np")
  (if (and transient-mark-mode mark-active)
      (let ((start (min (point) (mark)))
            (end (max (point) (mark))))
        (mindent-indent-region-to-char c n start end))
    (let* ((search-string
            (if (or (char-equal c ?-) (char-equal c ?^) (char-equal c ?\\ ))
                (concat "^\\" (char-to-string c))
              (concat "^" (char-to-string c))))
           (start-column (current-indentation))
           (goal (save-excursion
                   (forward-line -1)
                   (end-of-line)
                   (let ((limit (point)))
                     (move-to-column start-column)
                     (while (> n 0)
                       (skip-chars-forward search-string limit)
                       (setq n (1- n))
                       (if (and (> n 0) (< (point) limit))
                           (forward-char 1)))
                     (current-column)))))
      (mindent-maybe-reindent goal))))

(defun mindent-indent-to-mouse (ev)
  "Indent current line to column where mouse was clicked."
  (interactive "@e")
  (let ((indp (car (posn-col-row (event-start ev)))))
    (mindent-maybe-reindent indp)))

(defun mindent-indent-as-mouse-line (ev)
  "Indent current line just like line where mouse was clicked."
  (interactive "e")
  (let ((indp
         (save-excursion
           (mouse-set-point ev)
           (current-indentation))))
    (mindent-maybe-reindent indp)))

(defun mindent-indent-as-line-starting (c n)
  "Indent current line just like the Nth preceding line starting with C."
  (interactive "cIndent as line starting with: \np")
  (unless (zerop n)
    (let* ((direction (if (> n 0) -1 1))
           (num (abs n))
           (indp
            (save-excursion
              (beginning-of-line 1)
              (while (> num 0)
                (forward-line direction)
                (setq num (1- num))
                (while (or (not (looking-at
                                 (concat
                                  "[ \t]*"
                                  (regexp-quote (char-to-string c)))))
                           (funcall mindent-comment-predicate)
                           (looking-at
                            (concat "[ \t]*\\(\n\\|"
                                    comment-start-skip
                                    "\\)")))
                  (if (or (bobp) (eobp)) (error "No such line"))
                  (forward-line direction)))
              (back-to-indentation)
              (current-column))))
      (mindent-maybe-reindent indp))))

;; functions that reindent entire regions
(defun mindent-compute-block-indent (pos)
  "Given a position POS, compute the amount of space needed to indent
the current line so that it is indented to the column which is the
current columns at POS.  The result can be negative, if unindenting is
necessary to get to POS."
  (let ((goal
         (save-excursion
           (goto-char pos)
           (current-column))))
    (- goal (current-indentation))))

(defun mindent-unindent-region (n start end)
  "Unindent region N levels.
That is, find the Nth stricly less indented line preceding
the first on in the region, and reindent to it."
  (interactive "p\nr")
  (save-excursion
    (goto-char start)
    (let* ((p (save-excursion
                (mindent-backward-to-less-indent n) (point)))
           (offset (mindent-compute-block-indent p)))
      (indent-code-rigidly start end offset))))

(defun mindent-indent-region (start end)
  "Indent current region as a block to the level of preceding line."
  (interactive "r")
  (save-excursion
    (goto-char start)
    (let* ((indp
            (save-excursion
              (forward-line -1)
              (back-to-indentation)
              (point)))
           (offset (mindent-compute-block-indent indp)))
      (indent-code-rigidly start end offset))))

(defun mindent-indent-region-relative (n start end)
  "Indent current region relative to the Nth indentation point.
Indentation points are the columns where the previous nonblank line
has a blank character, followed by a nonblank character.
With negative N, unindent current region N levels."
  (interactive "p\nr")
  (if (< n 0) (mindent-unindent-region (- n) start end)
    (save-excursion
      (goto-char start)
      (let* ((here (current-indentation))
             (indp
              (save-excursion
                (if (not (re-search-backward "\\(.\\|\n\\)\n" nil t))
                    (point-min)
                  (beginning-of-line)
                  (while (and (not (bobp))
                              (or (funcall mindent-comment-predicate)
                                  (looking-at (concat "[ \t]*\\(\n\\|"
                                                      comment-start-skip
                                                      "\\)"))))
                    (forward-line -1))
                  (end-of-line)
                  (let ((endp (point)))
                    (move-to-column here)
                    (re-search-forward "\\s \\S " endp 'move n)
                    (backward-char 1)
                    (point)))))
             (offset (mindent-compute-block-indent indp)))
        (indent-code-rigidly start end offset)))))

(defun mindent-indent-region-to-char (c n start end)
  "Indent current region to the Nth occurrence of C on the previous line."
  (interactive "cIndent to character: \np\nr")
  (save-excursion
    (goto-char start)
    (let* ((search-string
            (if (or (char-equal c ?-)
                    (char-equal c ?^)
                    (char-equal c ?\\ ))
                (concat "^\\" (char-to-string c))
              (concat "^" (char-to-string c))))
           (start-column (current-indentation))
           (goal (save-excursion
                   (forward-line -1)
                   (end-of-line)
                   (let ((limit (point)))
                     (move-to-column start-column)
                     (while (> n 0)
                       (skip-chars-forward search-string limit)
                       (setq n (1- n))
                       (if (and (> n 0) (< (point) limit))
                           (forward-char 1)))
                     (current-column))))
           (offset (- goal start-column)))
      (indent-code-rigidly start end offset))))

(defun mindent-indent-region-to-mouse (ev start end)
  "Indent current region to column where mouse was clicked."
  (interactive "@e\nr")
  (save-excursion
    (goto-char start)
    (let ((c (progn (back-to-indentation) (current-column)))
          (goal (car (posn-col-row (event-start ev)))))
      (indent-code-rigidly start end (- goal c)))))

(defun mindent-indent-region-as-mouse-line (ev start end)
  "Indent current region just like line where mouse was clicked."
  (interactive "e\nr")
  (save-excursion
    (goto-char start)
    (let ((indp
           (save-excursion
             (mouse-set-point ev)
             (back-to-indentation)
             (point))))
      (indent-code-rigidly
       start end
       (mindent-compute-block-indent indp)))))

(provide 'mindent)

;;; mindent.el ends here


reply via email to

[Prev in Thread] Current Thread [Next in Thread]