legacy-dotfiles/emacs.d/nxhtml/util/wrap-to-fill.el
Tom Willemsen 94d2fc1815 Django, org
* Added nxhtml, mostly for django support.

  * Changed some org settings.
2011-03-07 09:04:49 +01:00

364 lines
14 KiB
EmacsLisp
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;;; wrap-to-fill.el --- Make a fill-column wide space for editing
;;
;; Author: Lennart Borgman (lennart O borgman A gmail O com)
;; Created: 2009-08-12 Wed
;; Version:
;; Last-Updated: x
;; URL:
;; Keywords:
;; Compatibility:
;;
;; Features that might be required by this library:
;;
;; None
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;; Commentary:
;;
;;
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;; Change log:
;;
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; 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 3, 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; see the file COPYING. If not, write to
;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth
;; Floor, Boston, MA 02110-1301, USA.
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;; Code:
(eval-when-compile (require 'mumamo))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;; Wrapping
;;;###autoload
(defgroup wrap-to-fill nil
"Customizing of `wrap-to-fill-column-mode'."
:group 'convenience)
;;;###autoload
(defcustom wrap-to-fill-left-marg nil
"Left margin handling for `wrap-to-fill-column-mode'.
Used by `wrap-to-fill-column-mode'. If nil then center the
display columns. Otherwise it should be a number which will be
the left margin."
:type '(choice (const :tag "Center" nil)
(integer :tag "Left margin"))
:group 'wrap-to-fill)
(make-variable-buffer-local 'wrap-to-fill-left-marg)
(defvar wrap-to-fill--saved-state nil)
;;(make-variable-buffer-local 'wrap-to-fill--saved-state)
(put 'wrap-to-fill--saved-state 'permanent-local t)
;;;###autoload
(defcustom wrap-to-fill-left-marg-modes
'(text-mode
fundamental-mode)
"Major modes where `wrap-to-fill-left-margin' may be nil."
:type '(repeat command)
:group 'wrap-to-fill)
;;ThisisaVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongWord ThisisaVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongWord
(defun wrap-to-fill-wider ()
"Increase `fill-column' with 10."
(interactive)
(setq fill-column (+ fill-column 10))
(wrap-to-fill-set-values-in-buffer-windows))
(defun wrap-to-fill-narrower ()
"Decrease `fill-column' with 10."
(interactive)
(setq fill-column (- fill-column 10))
(wrap-to-fill-set-values-in-buffer-windows))
(defun wrap-to-fill-normal ()
"Reset `fill-column' to global value."
(interactive)
;;(setq fill-column (default-value 'fill-column))
(kill-local-variable 'fill-column)
(wrap-to-fill-set-values-in-buffer-windows))
(defvar wrap-to-fill-column-mode-map
(let ((map (make-sparse-keymap)))
(define-key map [(control ?c) ?+] 'wrap-to-fill-wider)
(define-key map [(control ?c) ?-] 'wrap-to-fill-narrower)
(define-key map [(control ?c) ?0] 'wrap-to-fill-normal)
map))
;; Fix-me: Maybe make the `wrap-prefix' behavior an option or separate
;; minor mode.
;; Fix-me: better handling of left-column in mumamo buffers (and other
;; if possible).
;;;###autoload
(define-minor-mode wrap-to-fill-column-mode
"Use `fill-column' display columns in buffer windows.
By default the display columns are centered, but see the option
`wrap-to-fill-left-marg'.
Fix-me:
Note 1: When turning this on `visual-line-mode' is also turned on. This
is not reset when turning off this mode.
Note 2: The text properties 'wrap-prefix and 'wrap-to-fill-prefix
is set by this mode to indent continuation lines.
Key bindings added by this minor mode:
\\{wrap-to-fill-column-mode-map}"
:lighter " WrapFill"
:group 'wrap-to-fill
;; (message "wrap-to-fill-column-mode %s, cb=%s, major=%s, multi=%s" wrap-to-fill-column-mode (current-buffer)
;; major-mode mumamo-multi-major-mode)
(if wrap-to-fill-column-mode
(progn
;; Old values (idea from visual-line-mode)
(set (make-local-variable 'wrap-to-fill--saved-state) nil)
(dolist (var '(visual-line-mode
;;left-margin-width
;;right-margin-width
))
(push (list var (symbol-value var) (local-variable-p var))
wrap-to-fill--saved-state))
;; Hooks
(add-hook 'window-configuration-change-hook 'wrap-to-fill-set-values nil t)
;; Wrapping
(visual-line-mode 1)
(wrap-to-fill-set-values-in-buffer-windows))
;; Hooks
(remove-hook 'window-configuration-change-hook 'wrap-to-fill-set-values t)
;; Old values
(dolist (saved wrap-to-fill--saved-state)
(let ((var (nth 0 saved))
(val (nth 1 saved))
(loc (nth 2 saved)))
(cond
((eq var 'visual-line-mode)
(unless val (visual-line-mode -1)))
(t
(if loc
(set (make-local-variable var) val)
(kill-local-variable var))))))
(kill-local-variable 'wrap-to-fill--saved-state)
;; Margins
(dolist (win (get-buffer-window-list (current-buffer)))
(set-window-margins win left-margin-width right-margin-width))
;; Indentation
(let ((here (point))
(inhibit-field-text-motion t)
beg-pos
end-pos)
(mumamo-with-buffer-prepared-for-jit-lock
(save-restriction
(widen)
(goto-char (point-min))
(while (< (point) (point-max))
(setq beg-pos (point))
(setq end-pos (line-end-position))
(when (equal (get-text-property beg-pos 'wrap-prefix)
(get-text-property beg-pos 'wrap-to-fill-prefix))
(remove-list-of-text-properties
beg-pos end-pos
'(wrap-prefix)))
(forward-line))
(remove-list-of-text-properties
(point-min) (point-max)
'(wrap-to-fill-prefix)))
(goto-char here))))
(wrap-to-fill-font-lock wrap-to-fill-column-mode))
(put 'wrap-to-fill-column-mode 'permanent-local t)
(defcustom wrap-to-fill-major-modes '(org-mode
html-mode
nxhtml-mode)
"Major modes where to turn on `wrap-to-fill-column-mode'"
;;:type '(repeat major-mode)
:type '(repeat command)
:group 'wrap-to-fill)
(defun wrap-to-fill-turn-on-in-buffer ()
"Turn on fun for globalization."
(when (catch 'turn-on
(dolist (m wrap-to-fill-major-modes)
(when (derived-mode-p m)
(throw 'turn-on t))))
(wrap-to-fill-column-mode 1)))
(define-globalized-minor-mode wrap-to-fill-column-global-mode wrap-to-fill-column-mode
wrap-to-fill-turn-on-in-buffer
:group 'wrap-to-fill)
;; Fix-me: There is a confusion between buffer and window margins
;; here. Also the doc says that left-margin-width and dito right may
;; be nil. However they seem to be 0 by default, but when displaying a
;; buffer in a window then window-margins returns (nil).
(defvar wrap-to-fill-timer nil)
(make-variable-buffer-local 'wrap-to-fill-timer)
(defun wrap-to-fill-set-values ()
(when (timerp wrap-to-fill-timer)
(cancel-timer wrap-to-fill-timer))
(setq wrap-to-fill-timer
(run-with-idle-timer 0 nil 'wrap-to-fill-set-values-in-timer
(selected-window) (current-buffer))))
(put 'wrap-to-fill-set-values 'permanent-local-hook t)
(defun wrap-to-fill-set-values-in-timer (win buf)
(condition-case err
(when (buffer-live-p buf)
(wrap-to-fill-set-values-in-buffer-windows buf))
(error (message "ERROR wrap-to-fill-set-values-in-timer: %s"
(error-message-string err)))))
(defun wrap-to-fill-set-values-in-timer-old (win buf)
(when (and (window-live-p win) (buffer-live-p buf)
(eq buf (window-buffer win)))
(condition-case err
(with-current-buffer buf
(when wrap-to-fill-column-mode
(wrap-to-fill-set-values-in-window win)))
(error (message "ERROR wrap-to-fill-set-values: %s"
(error-message-string err))))))
(defun wrap-to-fill-set-values-in-buffer-windows (&optional buffer)
"Use `fill-column' display columns in buffer windows."
(let ((buf-windows (get-buffer-window-list (or buffer
(current-buffer))
nil
t)))
(dolist (win buf-windows)
(if wrap-to-fill-column-mode
(wrap-to-fill-set-values-in-window win)
(set-window-buffer nil (current-buffer))))))
(defvar wrap-old-win-width nil)
(make-variable-buffer-local 'wrap-old-win-width)
;; Fix-me: compensate for left-margin-width etc
(defun wrap-to-fill-set-values-in-window (win)
(with-current-buffer (window-buffer win)
(when wrap-to-fill-column-mode
(let* ((win-width (window-width win))
(win-margs (window-margins win))
(win-full (+ win-width
(or (car win-margs) 0)
(or (cdr win-margs) 0)))
(extra-width (- win-full fill-column))
(fill-left-marg (unless (memq major-mode wrap-to-fill-left-marg-modes)
(or (when (> left-margin-width 0) left-margin-width)
wrap-to-fill-left-marg)))
(left-marg (if fill-left-marg
fill-left-marg
(- (/ extra-width 2) 1)))
;; Fix-me: Why do I have to subtract 1 here...???
(right-marg (- win-full fill-column left-marg 1))
(need-update nil)
)
;; (when wrap-old-win-width
;; (unless (= wrap-old-win-width win-width)
;; (message "-")
;; (message "win-width 0: %s => %s, win-full=%s, e=%s l/r=%s/%s %S %S %S" wrap-old-win-width win-width win-full extra-width left-marg right-marg (window-edges) (window-inside-edges) (window-margins))
;; ))
(setq wrap-old-win-width win-width)
(unless (> left-marg 0) (setq left-marg 0))
(unless (> right-marg 0) (setq right-marg 0))
(unless nil;(= left-marg (or left-margin-width 0))
;;(setq left-margin-width left-marg)
(setq need-update t))
(unless nil;(= right-marg (or right-margin-width 0))
;;(setq right-margin-width right-marg)
(setq need-update t))
;;(message "win-width a: %s => %s, win-full=%s, e=%s l/r=%s/%s %S %S %S" wrap-old-win-width win-width win-full extra-width left-margin-width right-margin-width (window-edges) (window-inside-edges) (window-margins))
(when need-update
;;(set-window-buffer win (window-buffer win))
;;(run-with-idle-timer 0 nil 'set-window-buffer win (window-buffer win))
;;(dolist (win (get-buffer-window-list (current-buffer)))
;; Fix-me: check window width...
(set-window-margins win left-marg right-marg)
;;)
;;(message "win-width b: %s => %s, win-full=%s, e=%s l/r=%s/%s %S %S %S" wrap-old-win-width win-width win-full extra-width left-marg right-marg (window-edges) (window-inside-edges) (window-margins))
)
))))
;; (add-hook 'post-command-hook 'my-win-post-command nil t)
;; (remove-hook 'post-command-hook 'my-win-post-command t)
(defun my-win-post-command ()
(message "win-post-command: l/r=%s/%s %S %S %S" left-margin-width right-margin-width (window-edges) (window-inside-edges) (window-margins))
)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Font lock
(defun wrap-to-fill-fontify (bound)
(save-restriction
(widen)
(while (< (point) bound)
(let ((this-bol (if (bolp) (point)
(1+ (line-end-position)))))
(unless (< this-bol bound) (setq this-bol nil))
(when this-bol
(goto-char (+ this-bol 0))
(let (ind-str
ind-str-fill
(beg-pos this-bol)
(end-pos (line-end-position)))
(when (equal (get-text-property beg-pos 'wrap-prefix)
(get-text-property beg-pos 'wrap-to-fill-prefix))
;; Find indentation
(skip-chars-forward "[:blank:]")
(setq ind-str (buffer-substring-no-properties beg-pos (point)))
;; Any special markers like -, * etc
(if (and (< (1+ (point)) (point-max))
(memq (char-after) '(?- ;; 45
? ;; 8211
?*
))
(eq (char-after (1+ (point))) ?\ ))
(setq ind-str-fill (concat " " ind-str))
(setq ind-str-fill ind-str))
;;(setq ind-str-fill (concat " " ind-str))
(mumamo-with-buffer-prepared-for-jit-lock
(put-text-property beg-pos end-pos 'wrap-prefix ind-str-fill)
(put-text-property beg-pos end-pos 'wrap-to-fill-prefix ind-str-fill))))))
(forward-line 1))
;; Note: doing it line by line and returning t gave problem in mumamo.
(when nil ;this-bol
(set-match-data (list (point) (point)))
t)))
(defun wrap-to-fill-font-lock (on)
;; See mlinks.el
(let* ((add-or-remove (if on 'font-lock-add-keywords 'font-lock-remove-keywords))
(fontify-fun 'wrap-to-fill-fontify)
(args (list nil `(( ,fontify-fun ( 0 'font-lock-warning-face t ))))))
(when fontify-fun
(when on (setq args (append args (list t))))
(apply add-or-remove args)
(font-lock-mode -1)
(font-lock-mode 1))))
(provide 'wrap-to-fill)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; wrap-to-fill.el ends here