Fork me on GitHub
#emacs
<
2019-06-03
>
yuhan06:06:56

Anyone know of a command / package for normalising whitespace in Clojure code or lisps in general? (foo bar ) =>`(foo bar)`

ag18:06:27

M-x replace-regexp SPC+ RET SPC RET

yuhan19:06:35

That doesn't do the job of removing whitespace before closing delimiters though, or inserting spaces between forms eg. ([a][b]) => ([a] [b])

yuhan06:06:42

cljfmt (via cider-format) requires a running REPL process and doesn't affect inter-symbol whitespace

orestis15:06:59

Oh I’d love to have that too.

felipebarros18:06:35

Yeah, neither parinfer-fix or whitespace-cleanup from whitespace package clean inside forms.

felipebarros18:06:26

I use delete-horizontal-space a lot though, often with multiple cursors. Maybe a simple macro can do the job?

felipebarros18:06:15

Here it is bound to M-\.

felipebarros19:06:17

My Emacs regexp skills are failing me, but I believe you just need to ignore the first set of empty spaces (indentation), delete-horizontal-space on everything else and enter a single space or move to the end of the whitespace, one character back and delete-horizontal-space with C-u 1 M-\.

yuhan19:06:24

hmm, it looks like fixup-whitespace does the job for a particular point, the problem now is to iterate it through the form and handle edge cases, eg. not affecting whitespace in strings/comments

felipebarros19:06:29

Actually I mixed two ways to solve the problem. With regexup substitution you only need to target the second group of two or more whitespaces and set them to one.

felipebarros19:06:42

Nice! Wasn't aware of fixup-whitespace. I may even bind it to something.

felipebarros19:06:50

C-u C-M-| perl -pe 's/(\S)(\s)\s*/$1$2/g' RET

yuhan20:06:26

(defun fixup-defun-whitespace ()
  "Normalise all whitespace between forms in defun, and group closing parens.
Does not affect strings/comments"
  (interactive)
  (let* ((bnds (bounds-of-thing-at-point 'defun))
         (beg (car bnds)) (end (cdr bnds)))
    (save-excursion
      (goto-char end)
      (while (> (point) beg)
        (search-backward-regexp "[([{ \t\r\n]" beg)
        (unless (or (nth 8 (syntax-ppss)) ;; in a string or comment
                    (nth 4 (syntax-ppss)))
          (let ((s (buffer-substring (point-at-bol) (point))))
            (cond
             ;; indentation, skip
             ((string-match-p "^[ \t]*\\'" s)
              (forward-line 0))
             ;; closing paren on separate line
             ((string-match-p "^[ \t]*[])}]" s)
              (forward-line -1)
              (end-of-line)
              ;; don't join if prev line is a comment
              (unless (nth 8 (syntax-ppss))
                (delete-char 1)
                (fixup-whitespace)
                (forward-line 1)))
             (t
              (fixup-whitespace))))))
      (goto-char beg)
      (indent-sexp)
      (when (derived-mode-p 'clojure-mode)
        (call-interactively 'clojure-align)))))

👏 12
yuhan20:06:26

here's what I hacked together - although I'd be surprised if something like it doesn't already exist out there