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?

  • 5
    Very closely related: 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. Oct 10 '15 at 12:24

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)))
     (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."
    (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."
  (forward-to-indentation 0)
  (let* ((indent (current-column))
     (last-col indent)
     (last-virtual-newline indent)
    (while (null (eolp))
      (setq last-col (current-column))
      (setq last-posn (point))
      (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."
      (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)

(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)
      (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'.
 (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)

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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.