In typography, there's a practice called 'protrusion' (or hanging punctuation) that allows certain symbols to hang off the end of the margin:


I'd like to do the same thing for my text documents.

Can I change fill-paragraph (and friends?) to ignore end-of-line punctuation (.?!:;,'"-) when it fills the paragraph?

  • I'm not sure whether you can really call protrusion (subtle shifting of trailing punctuation) of justified text comparable to ignoring trailing punctuation when hard-wrapping text (which doesn't justify text by default, making the effect essentially invisible). Perhaps you'd like to add that this applies to the justified variant of fill-paragraph? – wasamasa Oct 24 '15 at 7:28
  • @wasamasa Protrusion still exists for flush left text blocks. – Sean Allred Oct 24 '15 at 13:19
  • Does it apply to the left edge of the text then? – wasamasa Oct 24 '15 at 13:26
  • @wasamasa Unless you're dealing with an RTL language and editor (which, while supported, I feel is out-of-scope), it doesn't make sense. If you have a flush right block and you 'run out of room' on the left margin (i.e., column 0), you can't exactly put the punctuation in column -1. (I suppose you could shift the right margin to (1+ fill-column), but that would change the filling and you could get caught in a loop.) – Sean Allred Oct 24 '15 at 13:47
  • 1
    @wasamasa In terms of implementation: unfill. jump to fill-column. if point is looking at a single character of punctuation and then whitespace, skip forward. else if in the middle of a word, skip backward. newline, repeat. – Sean Allred Oct 24 '15 at 18:40

Aha, I have the solution! Put this somewhere in your .emacs/.emacs.d/init.el file:

(define-advice current-fill-column (:filter-return (rtn) protrusion)
  "Advice to allow hanging punctuation when filling text."
  ;; Get the character after the proposed cutoff point
  (let ((end-char (char-after (1+ rtn))))
    (if (and end-char
             ;; Check if character is in the “punctuation” syntax table…
             (or (eq (char-syntax end-char) ?.)
                 ;; …or is any of these characters (feel free to add more)
                 (memq end-char (string-to-list ".,!?;:-"))))
        ;; If so, return the original value, plus one.
        (1+ rtn)
      ;; Otherwise, do nothing and return the original value.

I’ve tested this with fill-paragraph, and it should work for all the fill functions (since they all use current-fill-column when processing each line). I hope you like it! 😇

| improve this answer | |

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.