5

Q: how can I use truncate-lines in only part of a buffer?

As a general rule, I prefer continuation lines to truncating lines. However, it would be nice to truncate only certain kinds of lines in a given buffer.

In an ideal world, I would like to truncate headings in org-mode (and outline-mode more generally) but not use truncate-lines in the entry bodies. Is that possible with a minimum of fuss, or would it require a major replumbing of the internals?

Dan
  • 32,584
  • 6
  • 98
  • 168
  • 5
    Very closely related: http://emacs.stackexchange.com/q/7432/115. But the premise is the same. The end result was that you cannot specify truncation states separately for parts of the same buffer. – Kaushal Modi Oct 10 '15 at 12:24

2 Answers2

2

As wasamasa already pointed out word-wrapping only a part of the buffer requires most probably some re-plumping. The following demonstrates an idea. It works with truncated lines and puts a newline with indent before the word reaching fill-column.

I am aware that this is not perfect. Some things that are not handled:

  • word wrapping does not adapt to window-body-width
  • it does also not adapt to changes of fill-column; one could advice set-fill-column with jit-lock-redisplay
  • no special point motion (e.g. forward-line jumps over the visual lines)
  • other jit-lock handlers might interfere with visline-mode

If you want to try this stuff load it. There is an org-visline-mode function at the end of this code which installs the filter for org headlines and switches on visline-mode in org-mode-hook.

(defvar-local visline-predicate-functions nil
  "List of predicate functions that are run at the beginning of each line which is visually word-wrapped by `visline-mode'.
You should add your handlers before running `visline-mode'.
The predicate functions are called without arguments.")

(defmacro visline-expand-region (start end)
  "Expand region between START and END such that START is at the beginning of a line and END at the end of a line."
  (declare (debug (sexp sexp)))
  `(progn
     (setq ,start (save-excursion (goto-char ,start) (beginning-of-line) (point)))
     (setq ,end (save-excursion (goto-char ,end) (end-of-line) (point)))))

(defun visline-clear (start end)
  "Remove visual linebreaks in the region from START to END."
  (with-silent-modifications
    (while (setq start (text-property-any start end 'visline t))
      (remove-text-properties start (1+ start) '(visline t display "\n")))))

(defsubst visline-put (pos indent)
  "Put a visual linebreak at the character following position POS."
  (add-text-properties pos (1+ pos) (list 'visline t 'display (concat "\n" (make-string indent ?\ )))))

(defun visline-fill-line ()
  "Word-wrap current line with the help of visual linebreaks."
  (beginning-of-line)
  (forward-to-indentation 0)
  (let* ((indent (current-column))
     (last-col indent)
     last-posn
     (last-virtual-newline indent)
     fitting-line)
    (while (null (eolp))
      (setq last-col (current-column))
      (setq last-posn (point))
      (forward-char)
      (skip-chars-forward "^[[:space:]]\n")
      (when (and (> (- (current-column) last-virtual-newline) fill-column)
         (> last-col indent))
    (visline-put last-posn indent)
    (setq last-virtual-newline (+ last-col indent))))))

(defun visline-handler (start end)
  "Visually word-wrap region between START and END."
  (with-silent-modifications
    (save-excursion
      (visline-expand-region start end)
      (visline-clear start end)
      (goto-char start)
      (while (< (point) end)
    (when (run-hook-with-args-until-failure 'visline-predicate-functions)
      (visline-fill-line))
    (forward-line)))))

(define-minor-mode visline-mode
  "Word-wrap via text-properties"
  :keymap nil
  (if visline-mode
      (jit-lock-register 'visline-handler) ;; `jit-lock-register' also re-fontifies
    (jit-lock-unregister 'visline-handler)
    (with-silent-modifications
      (visline-clear (point-min) (point-max)))))

(defun org-visline-dont-wrap-headlines ()
  "Return only t if we are not on a headline."
  (null (eq (char-after) ?*)))

(defun org-visline-mode ()
  "Switches `visline-mode' on in `org-mode'.
Usage:
 (require 'visline)
 (add-hook 'org-mode-hook 'org-visline-mode)"
  (add-hook 'visline-predicate-functions 'org-visline-dont-wrap-headlines)
  (visline-mode t))

(provide 'visline)

(add-hook 'org-mode-hook 'org-visline-mode)
Tobias
  • 32,569
  • 1
  • 34
  • 75
0

Given that there is no special text property controlling the truncation behaviour of text, I doubt this is possible. You could however work around by enabling truncation in an Org buffer and hard wrapping text under a heading, that way headings (and overly large tables) would show up as truncated, but the hard-wrapped text wouldn't.

wasamasa
  • 21,803
  • 1
  • 65
  • 97