;;; motion-fns.el --- motion and insertion functions

;; Copyright (C) 1991-1999 Noah S. Friedman

;; Author: Noah Friedman <friedman@splode.com>
;; Maintainer: friedman@splode.com

;; $Id: motion-fns.el,v 1.2 1999/10/15 15:44:23 friedman Exp $

;; 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, 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, you can either send email to this
;; program's maintainer or write to: The Free Software Foundation,
;; Inc.; 59 Temple Place, Suite 330; Boston, MA 02111-1307, USA.

;;; Commentary:
;;; Code:

;;;###autoload
(defun narrow-to-defun ()
  "Restrict editing in this buffer to the current defun
as defined by the functions `beginning-of-defun' and `end-of-defun'.
The rest of the text becomes temporarily invisible and untouchable
but is not deleted; if you save the buffer in a file, the invisible
text is included in the file.
``\\[widen]'' makes all visible again.
See also `narrow-to-region'."
  (interactive)
  (save-excursion
    (let (end)
      (end-of-defun)
      (setq end (point))
      (beginning-of-defun)
      (narrow-to-region (point) end))))

;;;###autoload
(defun narrow-to-regexp (regexp)
  "Restrict editing in this buffer to the regular expression REGEXP.
The search for text matching the regular expression begins at point (not
from the beginning of the buffer), but the resulting narrowed region will
start at any following point matched by the regexp.  The regular expression
search is bounded by any narrowing currently in effect; to avoid this,
widen the buffer first.

See also: `widen', `narrow-to-region'"
  (interactive "sNarrow to regexp: ")
  (save-match-data
    (save-excursion
      (re-search-forward regexp))
    (widen)
    (narrow-to-region (match-beginning 0) (match-end 0))))

;;;###autoload
(defun narrow-to-sexp ()
  "Restrict editing in this buffer to the current sexp.
The rest of the text becomes temporarily invisible and untouchable
but is not deleted; if you save the buffer in a file, the invisible
text is included in the file.
``\\[widen]'' makes all visible again.
See also `narrow-to-region'."
  (interactive)
  (let (end)
    (save-excursion
      ;; It's better to go forward before going back, since point might
      ;; already be at the beginning of the sexp.  If at end, we go on to
      ;; the next sexp.
      (forward-sexp-safe 1)
      (setq end (point))
      (forward-sexp-safe -1)
      (narrow-to-region (point) end))))


;; forward-sexp calls scan-sexps, which returns an error if it hits the
;; beginning or end of the sexp.
;;;###autoload
(defun forward-sexp-safe (&optional count)
  "Move forward across one balanced expression (sexp).
With argument, do it that many times.  Negative arg -COUNT means
move backward across COUNT balanced expressions.
Return distance in buffer moved, or nil."
  (or count (setq count 1))
  (condition-case errlist
      (- (- (point) (progn
                      (let ((parse-sexp-ignore-comments t))
                        (forward-sexp count))
                      (point))))
    (error
     (if (string= (car (cdr errlist))
                  "Containing expression ends prematurely")
         nil
       (error "%s" (car (cdr errlist)))))))

;;;###autoload
(defun goto-longest-line ()
  "Go to longest line in buffer."
  (interactive)
  (let ((longest-line 0)
        (line 0)
        (length 0))
    (save-excursion
      (goto-char (point-min))
      (end-of-line)
      (setq length (current-column))
      (setq longest-line 0)
      (while (zerop (forward-line 1))
        (setq line (1+ line))
        (end-of-line)
        (cond ((> (current-column) length)
               (setq length (current-column))
               (setq longest-line line)))))
    (goto-line (1+ longest-line))))

;;;###autoload
(defun move-to-column-force (column)
  "Sets point at column COLUMN on the current line, appending spaces if
end-of-line precedes desired column.  To just move to a column or end
of line (whichever comes first), use move-to-column instead."
  (interactive)
  (let ((column-reached (move-to-column column)))
    (or (equal column column-reached)
        (insert
         (make-string
          (- column column-reached)
          (string-to-char " "))))))

(provide 'motion-fns)

;;; motion-fns.el ends here.
