radian-software / apheleia

🌷 Run code formatter on buffer contents without moving point, using RCS patches and dynamic programming.
MIT License
558 stars 75 forks source link

Buffer not being replaced when formatting with lisp function? #203

Open nafiz1001 opened 1 year ago

nafiz1001 commented 1 year ago

Context

I've decided to write a lisp function for formatting with spotless because I think the list format wouldn't allow "-PspotlessIdeHook=" and filepath to be concatenated together. But when I tried this method it would insert the formatted code right below the original code.

  (cl-defun spotlessApply+ (&key buffer scratch callback &allow-other-keys)
    (let* ((filepath (buffer-file-name buffer))
       (process-connection-type nil)
       (stderr-buffer (generate-new-buffer "*spotlessApply stderr*"))
       (sentinel (lambda (p e) (progn
                     (funcall callback)
                     (kill-buffer stderr-buffer))))
       (spotless-process (make-process
                  :name "spotlessApply"
                  :buffer scratch
                  :command `(,(concat default-directory "gradlew")
                     "spotlessApply"
                     ,(concat "-PspotlessIdeHook=" filepath)
                     "-PspotlessIdeHookUseStdOut"
                     "--quiet")
                  :sentinel sentinel
                  :stderr stderr-buffer)))))
  (push '(spotless . spotlessApply+)
    apheleia-formatters)

;; temporarily set default-directory to root of project
  (defun shou/fix-apheleia-project-dir (orig-fn &rest args)
    (let ((default-directory (vc-root-dir)))
      (apply orig-fn args)))
  (advice-add 'apheleia-format-buffer :around #'shou/fix-apheleia-project-dir)

Example

Before:

package com.watchtower.server;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class ServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ServerApplication.class, args); String hello = "world";
    }
}

After:

package com.watchtower.server;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class ServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ServerApplication.class, args); String hello = "world";
    }
}
package com.watchtower.server;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class ServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ServerApplication.class, args);
        String hello = "world";
    }
}

But when I run the cli manually, it only produces the formatted code.

mohkale commented 1 year ago

Note: I plan to fix the inability to concatenate filepath in the work for #212.

raxod502 commented 1 year ago

The scratch buffer starts with the file contents populated in it. You need to modify it in place, or erase it first. (Though if you erase it first then your formatter won't work when chained after another formatter.) If you just insert the formatted contents, you'll end up with two copies, as reported here.

mohkale commented 1 year ago

Note: I don't think it's very straightforward to fix the filepath concatenation issue sadly, however you can use (apheleia-formatters-local-buffer-file-name) to access the filepath in most situations. There's some nuances around remote files but most of the time that should work fine for you.

nafiz1001 commented 1 year ago

Note: I don't think it's very straightforward to fix the filepath concatenation issue sadly, however you can use (apheleia-formatters-local-buffer-file-name) to access the filepath in most situations. There's some nuances around remote files but most of the time that should work fine for you.

Thanks your idea worked. At least for my use-case :)

(defun shou/fix-apheleia-project-dir (orig-fn &rest args)
    (let ((default-directory (vc-root-dir)))
      (apply orig-fn args)))
  (advice-add 'apheleia-format-buffer :around #'shou/fix-apheleia-project-dir)
  (push '(spotless . ((concat default-directory "gradlew")
              "spotlessApply"
              (concat "-PspotlessIdeHook=" (apheleia-formatters-local-buffer-file-name))
              "-PspotlessIdeHookUseStdIn"
              "-PspotlessIdeHookUseStdOut"
              "--quiet"))
    apheleia-formatters)
  (setf (alist-get 'java-mode apheleia-mode-alist)
    '(spotless))