fillcode

Fillcode is available on MELPA!

Fillcode is an Emacs minor mode that fills, or wraps, some parts of source code. It’s best described by example. Fillcode fills this:

public static void foo(int i, float f, String s) {

to this:

public static void foo(int i, float f,
                       String s) {

The motivation is described in my original call for filling code.

Fillcode can fill any parenthesized expression, including function prototypes, function calls, and conditional expressions. It only breaks lines at commas and binary operators, and correctly preserves embedded comments and string literals. It also normalizes existing whitespace and line breaks.

Fillcode is supported in GNU Emacs and XEmacs 21 through 24, and works with most programming language major modes, including Java, C, C++, Objective C, Perl, Python, shell, and SQL modes.

Fillcode fills when fill-paragraph (usually M-q) is called. If the major mode itself attempts to fill – inside a comment, for example – fillcode graciously steps back and does nothing.

If you provide a prefix argument, e.g. C-u M-q, fillcode will automatically insert a line break at the first open parenthesis or other appropriate point. This can be useful when the first open parenthesis is near fill-column.

You can load fillcode automatically by copying fillcode.el into /usr/share/emacs/site-lisp/, or any other directory in Emacs’ load-path. Then, add this to your .emacs file:

(require 'fillcode)

M-x fillcode-mode toggles fillcode on and off in the current buffer. To turn it on automatically whenever you open source code, add these lines to your .emacs file.

(add-hook 'c-mode-common-hook 'fillcode-mode)
(add-hook 'perl-mode-hook 'fillcode-mode)
(add-hook 'python-mode-hook 'fillcode-mode)
(add-hook 'shell-script-mode-hook 'fillcode-mode)
(add-hook 'sql-mode-hook 'fillcode-mode)

Fillcode is a work in progress. Here’s a list of issues:

  • It depends on the major mode’s indentation and parsing engines. These are less than perfect in some major modes.
  • It’s not entirely compatible with auto-fill-mode or filladapt-mode…yet.
  • It doesn’t break lines at =, the assignment operator.

As of version 0.8, 2011/9/6, fillcode is in the public domain. Before that, it was distributed under the GPL.

18 thoughts on “fillcode

  1. thanks for the feedback! ay, really, it doesn’t? i’ve been testing with python-mode 4.6.18.2, and it works ok.

    would you mind describing in more detail what doesn’t work with the python-mode in CVS?

  2. in python-mode, one problem with the original fillcode i posted was that it often filled more than just the single statement under point. i’ve posted a new version that is much better (and thus more polite) about determining where the current statement ends.

    thanks for the bug report!

  3. yeah, i do remember that. sigh. thanks for the info.

    i just downloaded and built CVS emacs, and it breaks the fillcode unit tests spectacularly. that’ll be a good place for me to start.

  4. Rather than defining a mode and using hooks you can just set fill-paragraph-function' to the desired "fillcode" function.
    See the command help on
    fill-paragraph’ at `C-h f fill-paragraph’.

  5. good point. that’s true for all major modes that respect fill-paragraph-function'.<p class="paragraph"/>unfortunately, cc-mode doesn't. it replacesfill-paragraph’ with c-fill-paragraph', which it binds M-q to.c-fill-paragraph’ ignores fill-paragraph-function' entirely. :/<p class="paragraph"/>so, for fillcode to work in cc-mode major modes, it has to do something like advisec-fill-paragraph’…which it does. still, you’re probably right, it doesn’t need a whole minor mode. i’ll consider removing that in the future.

  6. Thanks for this very nice emacs mode!

    I think I found one bug though – when filling this string:
      <code>for (iy = 0; iy < dLy; iy++)</code>
    it becomes
      <code>for (iy = 0; iy < dLy; iy+ +)</code>
    i.e. it separates the “+” signs. This is in cc-mode.

  7. thanks for the report, martin. a fix for that went in in 0.5 or 0.6. sorry for the delayed response!

  8. Thanks for this code! However, everytime I start fillcode-mode, I get the following errors:

    Warning: assignment to free variable fillcode-wrapped-fill-function'<br />
    <br />
    Warning: reference to free variable
    fillcode-wrapped-fill-function’

    I use fillcode 0.7.1

  9. @Martin, hmm. which version of emacs or xemacs are you using? also, they’re labelled warnings, not errors. does fillcode-mode still end up enabled and working?

  10. @ryan, sorry, yes, those are only warnings, but it makes my emacs start with split display with the warnings in one buffer. I use emacs-22.3-4.fc10.x86_64 and fillcode-mode 0.7.1.

    And yes, fillcode-mode does work.

    This is what I’ve got im my .emacs:
    (add-to-list ‘load-path “~/.emacs.d/site-lisp/”)
    (and (locate-library “fillcode”)
      (require ‘fillcode)
      (setq default-major-mode ‘text-mode)
      (add-hook ‘text-mode-hook ‘turn-on-auto-fill)
      )

  11. Any hints on how to get rid of these warnings? Any more info I can provide?

  12. @Martin,

    you can put the following line near the top of the fillcode.el file:
    (defvar fillcode-wrapped-fill-function nil)

    Geralt.

  13. It’s working under emacs-23 for me.  You can update the description.

  14. Debugger entered--Lisp error: (void-function py-in-literal)
      py-in-literal()
      funcall(py-in-literal)
      (or (funcall in-literal-fn) (eval (cons … ...)))
      (let ((in-literal-fn ...) (literal-start-tokens ...)) (or (funcall in-literal-fn) (eval ...)))
      fillcode-in-literal()
      (cond ((fillcode-in-literal) (forward-char)) ((eolp) (delete-indentation t)) ((looking-at ...) (delete-horizontal-space) (if … ...)) ((and … ...) (progn … ...)) ((and … ... ...) (progn … ...)) (t (forward-char)))
      fillcode-collapse-whitespace-forward()
      fillcode()
      call-interactively(fillcode)
      execute-extended-command(nil)
      call-interactively(execute-extended-command)

Leave a Reply

Your email address will not be published. Required fields are marked *