12

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

protrusion

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?

Sean Allred
  • 6,861
  • 16
  • 85
  • 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 07: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
  • Well, no, I'm trying to understand how exactly the protrusion feature is supposed to work for something that's not fully justified text. – wasamasa Oct 24 '15 at 18:02
  • 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
  • You need to write a custom predicate function for variable `fill-nobreak-predicate`. In order to get the right behaviour, I think you'll need to establish exactly how function `fill-move-to-break-point` behaves when calling `(fill-nobreak-p)`. – phils Nov 30 '16 at 20:39
  • @phils is correct. To be able to do this, we need to allow moving forward in `fill-move-to-break-point` which currently doesn't happen. – narendraj9 Sep 06 '18 at 06:45

1 Answers1

3

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.
      rtn)))

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!

Tina Russell
  • 380
  • 2
  • 10