8
\$\begingroup\$

Motivation

I recently picked up Emacs. As part of the process, I've started to configure the editor to fit my needs with Emacs Lisp. The Elisp indentation rules are still foreign to me, so I pretty much depend on Emacs' electric-indent-mode to work. There's always C-x h and C-M-\ to the rescue, though.

That being said, I recently came across a user who cannot use this functionality, as the Emacs user interface in its default state is apparently incompatible with their screen reader. Still, I think that Emacs' Lisp indentation works great, so I tried to make it more accessible. And since I also needed some experience with Lisp, why not write it in Elisp?

Emacs driven indentation script

The Emacs driven indentation script (Edis) is single script to indent files with Emacs' indentation logic. It has no requirement except an Emacs installation and should—in theory—work on all supported platforms and in most Emacs versions, although I only tested Linux and Emacs 26 so far.

Files must be given as command line arguments. It's a script, after all, and doesn't use any graphical interface:

/path/to/edis file1.elisp file2.elisp file3.elisp …

On Windows, a small wrapper is necessary, since it doesn't support shebangs, but that's probably just two lines of CMD or PowerShell.

Mistyped file names should get reported, but other than that, there shouldn't be any restriction on the number of files unless enforced by the OS, shell or Emacs. In theory, you can even use TRAMP to indent remote files, but I haven't tested that exhaustively (try edis /ssh:server:/path/to/file if you're interested).

#!/usr/bin/emacs --script
(defun edis-indent-file (filename)
  "Re-indents a given file"
  (interactive "fFile to indent")
  (cond 
   ((file-exists-p filename)
    (find-file filename)
    (indent-region (point-min) (point-max))
    (save-buffer))
   (t
    (message "File not found (need existing file): %s" filename))))

(mapc 'edis-indent-file argv)

The code has been indented with itself. As usual, it will respect file and global variables, so you can specify for example (setq lisp-indent-offset 2) in your init.el or use file local variables, for example:

;; -*- lisp-body-indent: 4 ; lisp-indent-offset: 2 -*-

This is the first Emacs Lisp code I've written so far that's outside my init.el (where I mostly use use-package, to be honest). Since Emacs is, after all, a text editor, all necessary tools seem to be at hand, so the code isn't that long.

I haven't read the complete Elisp manual yet and got the functions from the C-h k or quick searches in the manual, so I'm not sure whether the code is idiomatic Elisp or completely fails any good practice, so feel free to comment on any part of the code.

\$\endgroup\$
  • \$\begingroup\$ I have nothing to say on this. This is IMO perfect. \$\endgroup\$ – Ernest Friedman-Hill Dec 20 '18 at 16:19
  • 2
    \$\begingroup\$ @ErnestFriedman-Hill Explain why it is perfect in an answer and it might give you a +50 bounty. \$\endgroup\$ – Simon Forsberg Jan 8 at 14:56
2
\$\begingroup\$

One of the pitfalls with any language using formatting constructs you're not that familiar with, is that it becomes an unreadable mess. Your code though is properly formatted, properly indented (it would be poor style for an indentation script to be badly indented itself, wouldn't it?) and even self-documenting. On every line, it's perfectly clear where we are, what's going on and how it's done.

If we're really going to nitpick, the documentation of Emacs Lisp uses the following indentation style for conditionals:

(cond ((file-exists-p filename)
        (find-file filename)
        (indent-region (point-min) (point-max))
        (save-buffer))
      (t (message "File not found (need existing file): %s" filename))))

Which slightly differs from yours, and is more in line with the rest of the language. But I can understand a preference for either.

\$\endgroup\$

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.