abo-abo / lispy

Short and sweet LISP editing
http://oremacs.com/lispy/
1.2k stars 132 forks source link

dot being escaped in ClojureC (.cljc) mode by lispy-tab #548

Open emallson opened 3 years ago

emallson commented 3 years ago

Small example:

(defn button-value
  [field]
  #?(:cljs (:buttonValue field)
     :clj (when (= (display-type field) :radio)
            (as-> field f
              (.getObject f)
              (.getItem f COSName/AP)
              (.getItem f COSName/N)
              (.keySet f)
              (map (fn [cos] (.getName cos)) f)
              (some #(when-not (= % "Off") %) f)))))

becomes

(defn button-value
  [field]
  #?(:cljs (:buttonValue field)
     :clj (when (= (display-type field) :radio)
            (as-> field f
              (\.getObject f)
              (\.getItem f COSName/AP)
              (\.getItem f COSName/N)
              (\.keySet f)
              (map (fn [cos] (\.getName cos)) f)
              (some #(when-not (= % "Off") %) f)))))

Seems related to #537, but my inexpert redef of lispy--read to use lispy-clojure-modes at that same location did not seem to work.

Dot is (correctly) not escaped in either clojure or clojurescript mode.

I am using lispy at commit 0a9dcfdfbc and lispyville at 0f13f26cd6 via straight. This occurs when formatting via lispyville and when using lispy-tab directly.

Dima-369 commented 2 years ago

This also happens in Emacs Lisp and is rather annoying for macros like let-alist on the latest master:

(let-alist '((foo . 3))
  .foo)

After (lispy--normalize-1):

(let-alist '((foo . 3))
  \.foo)

I think it is because (prin1-to-string '.foo) returns \.foo. I tried to pass t for the NOESCAPE argument of (prin1-to-string) but it breaks (lispy-comment) and will probably have other issues as well.

Dima-369 commented 2 years ago

I came up with this defun which I run automatically after (lispy--normalize-1):

It iterates through the sexp and removes the trailing \ characters from symbols starting with a dot like \.foo. It works fine for me so far.

(defun dima-lispy-remove-leading-slash ()
  "Remove leading \ character from formatting dot symbols.

This is required for `let-alist'."
  (interactive)
  (let ((end (save-excursion
               (end-of-defun)
               (left-char)
               (point))))
    (save-excursion
      (lispy-beginning-of-defun)
      (let ((start (point)))
        (while (<= (point) end)
          (forward-symbol 1)
          (let ((sym (symbol-name (symbol-at-point))))
            ;; ignore single dot for cons
            (when (and (>= (length sym) 2) (string-prefix-p "." sym))
              (call-interactively #'lispy-mark-symbol)
              (delete-region (region-beginning) (region-end))
              (deactivate-mark)
              (when (looking-back "\\\\" 1)
                (left-char)
                (delete-char 1))
              (insert sym)
              ;; update end because the defun is shorter now
              (let ((current (point)))
                (end-of-defun)
                (left-char)
                (setq end (point))
                (goto-char current)))))))))