From 914178a578762a659efffe9e6eaf507c9e989e9f Mon Sep 17 00:00:00 2001 From: yuhan0 Date: Sat, 18 Apr 2020 14:07:00 +0800 Subject: [PATCH 1/9] refactor clojure-space-for-delimiter-p --- clojure-mode.el | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/clojure-mode.el b/clojure-mode.el index 4abc7015..3d3cd51e 100644 --- a/clojure-mode.el +++ b/clojure-mode.el @@ -457,20 +457,11 @@ The command will prompt you to select one of the available sections." See `paredit-space-for-delimiter-predicates' for the meaning of ENDP and DELIM." (or endp - (not (memq delim '(?\" ?{ ?\( ))) - (not (or (derived-mode-p 'clojure-mode) + (not (memq delim '(?\" ?\{ ?\())) ;; always insert for [ + (not (or (derived-mode-p 'clojure-mode) ;; FIXME why does this check exist (derived-mode-p 'cider-repl-mode))) - (save-excursion - (backward-char) - (cond ((eq (char-after) ?#) - (and (not (bobp)) - (or (char-equal ?w (char-syntax (char-before))) - (char-equal ?_ (char-syntax (char-before)))))) - ((and (eq delim ?\() - (eq (char-after) ??) - (eq (char-before) ?#)) - nil) - (t))))) + (not (looking-back "\\_<#\\??")))) ;; auto-gensym syntax foo# + (defconst clojure--collection-tag-regexp "#\\(::[a-zA-Z0-9._-]*\\|:?\\([a-zA-Z0-9._-]+/\\)?[a-zA-Z0-9._-]+\\)" "Collection reader macro tag regexp. From 937cfddc800a646e1caa86c1b3122083e4932d7e Mon Sep 17 00:00:00 2001 From: yuhan0 Date: Sat, 18 Apr 2020 14:08:38 +0800 Subject: [PATCH 2/9] Prevent paredit from inserting spaces after ' quote --- clojure-mode.el | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/clojure-mode.el b/clojure-mode.el index 3d3cd51e..7b94b6e4 100644 --- a/clojure-mode.el +++ b/clojure-mode.el @@ -456,11 +456,12 @@ The command will prompt you to select one of the available sections." "Prevent paredit from inserting useless spaces. See `paredit-space-for-delimiter-predicates' for the meaning of ENDP and DELIM." - (or endp - (not (memq delim '(?\" ?\{ ?\())) ;; always insert for [ - (not (or (derived-mode-p 'clojure-mode) ;; FIXME why does this check exist - (derived-mode-p 'cider-repl-mode))) - (not (looking-back "\\_<#\\??")))) ;; auto-gensym syntax foo# + (and (not (eq (char-before) ?')) + (or endp + (not (memq delim '(?\" ?\{ ?\())) ;; always insert for [ + (not (or (derived-mode-p 'clojure-mode) ;; FIXME why does this check exist + (derived-mode-p 'cider-repl-mode))) + (not (looking-back "\\_<#\\??"))))) ;; auto-gensym syntax foo# (defconst clojure--collection-tag-regexp "#\\(::[a-zA-Z0-9._-]*\\|:?\\([a-zA-Z0-9._-]+/\\)?[a-zA-Z0-9._-]+\\)" From c8bc55242656d1bd72f8a339fa421d34b5c914ab Mon Sep 17 00:00:00 2001 From: yuhan0 Date: Sat, 18 Apr 2020 14:13:48 +0800 Subject: [PATCH 3/9] Simplify logic --- clojure-mode.el | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/clojure-mode.el b/clojure-mode.el index 7b94b6e4..69e6af84 100644 --- a/clojure-mode.el +++ b/clojure-mode.el @@ -452,16 +452,13 @@ The command will prompt you to select one of the available sections." (interactive) (browse-url clojure-style-guide-url)) -(defun clojure-space-for-delimiter-p (endp delim) +(defun clojure-space-for-delimiter-p (endp _delim) "Prevent paredit from inserting useless spaces. See `paredit-space-for-delimiter-predicates' for the meaning of ENDP and DELIM." - (and (not (eq (char-before) ?')) - (or endp - (not (memq delim '(?\" ?\{ ?\())) ;; always insert for [ - (not (or (derived-mode-p 'clojure-mode) ;; FIXME why does this check exist - (derived-mode-p 'cider-repl-mode))) - (not (looking-back "\\_<#\\??"))))) ;; auto-gensym syntax foo# + (and (not endp) + ;; don't insert after ' or # that is part of auto-gensym or reader conditional syntax + (not (looking-back "\\_<\\(?:'+\\|#\\??\\)" (point-at-bol))))) (defconst clojure--collection-tag-regexp "#\\(::[a-zA-Z0-9._-]*\\|:?\\([a-zA-Z0-9._-]+/\\)?[a-zA-Z0-9._-]+\\)" From e24b994f8465a0efcf7cec7a065c6d0ae8aed767 Mon Sep 17 00:00:00 2001 From: yuhan0 Date: Sat, 18 Apr 2020 15:04:55 +0800 Subject: [PATCH 4/9] Add tests for paredit interaction --- Cask | 3 +- .../clojure-mode-external-interaction-test.el | 90 +++++++++++++++++++ 2 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 test/clojure-mode-external-interaction-test.el diff --git a/Cask b/Cask index d6771c81..abcd75fd 100644 --- a/Cask +++ b/Cask @@ -5,4 +5,5 @@ (development (depends-on "s") - (depends-on "buttercup")) + (depends-on "buttercup") + (depends-on "paredit")) diff --git a/test/clojure-mode-external-interaction-test.el b/test/clojure-mode-external-interaction-test.el new file mode 100644 index 00000000..5e3d854c --- /dev/null +++ b/test/clojure-mode-external-interaction-test.el @@ -0,0 +1,90 @@ +;;; clojure-mode-external-interaction-test.el --- Clojure Mode interactions with external packages test suite -*- lexical-binding: t; -*- + +;; Copyright (C) 2014-2020 Bozhidar Batsov + +;; This file is not part of GNU Emacs. + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see . + +;;; Code: + +(require 'clojure-mode) +(require 'buttercup) +(require 'paredit) + +(describe "Interactions with Paredit" + ;; reuse existing when-refactoring-it macro + (describe "it should insert a space" + (when-refactoring-it "before lists" + "foo" + "foo ()" + (paredit-mode) + (paredit-open-round)) + (when-refactoring-it "before vectors" + "foo" + "foo []" + (paredit-mode) + (paredit-open-square)) + (when-refactoring-it "before maps" + "foo" + "foo {}" + (paredit-mode) + (paredit-open-curly)) + (when-refactoring-it "before strings" + "foo" + "foo \"\"" + (paredit-mode) + (paredit-doublequote)) + (when-refactoring-it "after gensym" + "foo#" + "foo# ()" + (paredit-mode) + (paredit-open-round)) + (when-refactoring-it "after symbols ending with '" + "foo'" + "foo' ()" + (paredit-mode) + (paredit-open-round))) + (describe "should not insert a space" + (when-refactoring-it "for anonymous fn syntax" + "foo #" + "foo #()" + (paredit-mode) + (paredit-open-round)) + (when-refactoring-it "for hash sets" + "foo #" + "foo #{}" + (paredit-mode) + (paredit-open-curly)) + (when-refactoring-it "for regexes" + "foo #" + "foo #\"\"" + (paredit-mode) + (paredit-doublequote)) + (when-refactoring-it "for quoted collections" + "foo '" + "foo '()" + (paredit-mode) + (paredit-open-round)) + (when-refactoring-it "for reader conditionals" + "foo #?" + "foo #?()" + (paredit-mode) + (paredit-open-round)))) + + +(provide 'clojure-mode-external-interaction-test) + + +;;; clojure-mode-external-interaction-test.el ends here From 7d1e57c88824ebe1d2d92d1c70d30206688f825d Mon Sep 17 00:00:00 2001 From: yuhan0 Date: Sat, 18 Apr 2020 15:05:41 +0800 Subject: [PATCH 5/9] Add delete-trailing-whitespace tests --- test/clojure-mode-external-interaction-test.el | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/test/clojure-mode-external-interaction-test.el b/test/clojure-mode-external-interaction-test.el index 5e3d854c..41b1aebb 100644 --- a/test/clojure-mode-external-interaction-test.el +++ b/test/clojure-mode-external-interaction-test.el @@ -84,6 +84,24 @@ (paredit-open-round)))) +(describe "Interactions with delete-trailing-whitespace" + (when-refactoring-it "should not delete trailing commas" + "(def foo + \\\"foo\\\": 1, + \\\"bar\\\": 2} + +(-> m + (assoc ,,, + :foo 123))" + "(def foo + \\\"foo\\\": 1, + \\\"bar\\\": 2} + +(-> m + (assoc ,,, + :foo 123))" + (delete-trailing-whitespace))) + (provide 'clojure-mode-external-interaction-test) From edada8e8f89b06363404f612ed80aadc939c3636 Mon Sep 17 00:00:00 2001 From: yuhan0 Date: Sat, 18 Apr 2020 15:24:07 +0800 Subject: [PATCH 6/9] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e7357327..86379da8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ ### Bugs fixed +* [#565](https://github.com/clojure-emacs/clojure-mode/issues/565): Fix extra spaces being inserted after quote in paredit-mode. * [#544](https://github.com/clojure-emacs/clojure-mode/issues/544): Fix docstring detection when string contains backslash. * [#547](https://github.com/clojure-emacs/clojure-mode/issues/547): Fix font-lock regex for character literals for uppercase chars and other symbols. * [#556](https://github.com/clojure-emacs/clojure-mode/issues/556): Fix renaming of ns aliases containing regex characters. From 3a1fb9892089b7ae437f09e4bde0604ea9e7dff2 Mon Sep 17 00:00:00 2001 From: yuhan0 Date: Sat, 18 Apr 2020 16:16:32 +0800 Subject: [PATCH 7/9] Make paredit-space-for-delimiter-predicates local to clojure buffers --- clojure-mode.el | 1 + 1 file changed, 1 insertion(+) diff --git a/clojure-mode.el b/clojure-mode.el index 69e6af84..880ba6ed 100644 --- a/clojure-mode.el +++ b/clojure-mode.el @@ -514,6 +514,7 @@ replacement for `cljr-expand-let`." (let ((keymap (or keymap clojure-mode-map))) (define-key keymap "{" #'paredit-open-curly) (define-key keymap "}" #'paredit-close-curly)) + (make-local-variable 'paredit-space-for-delimiter-predicates) (add-to-list 'paredit-space-for-delimiter-predicates #'clojure-space-for-delimiter-p) (add-to-list 'paredit-space-for-delimiter-predicates From cbe3f1dd8ac100bae672cb6f9f1dfea4c45cd26e Mon Sep 17 00:00:00 2001 From: yuhan0 Date: Sat, 18 Apr 2020 16:34:33 +0800 Subject: [PATCH 8/9] Refactor clojure-no-space-after-tag Consolidate into single predicate, make collection-tag-regexp obsolete --- clojure-mode.el | 38 ++++++++------------------------ test/clojure-mode-syntax-test.el | 9 -------- 2 files changed, 9 insertions(+), 38 deletions(-) diff --git a/clojure-mode.el b/clojure-mode.el index 880ba6ed..994c8bc6 100644 --- a/clojure-mode.el +++ b/clojure-mode.el @@ -452,14 +452,17 @@ The command will prompt you to select one of the available sections." (interactive) (browse-url clojure-style-guide-url)) -(defun clojure-space-for-delimiter-p (endp _delim) +(defun clojure-space-for-delimiter-p (endp delim) "Prevent paredit from inserting useless spaces. See `paredit-space-for-delimiter-predicates' for the meaning of ENDP and DELIM." (and (not endp) - ;; don't insert after ' or # that is part of auto-gensym or reader conditional syntax - (not (looking-back "\\_<\\(?:'+\\|#\\??\\)" (point-at-bol))))) - + ;; don't insert after opening quotes, auto-gensym syntax, or reader tags + (not (looking-back + (if (member delim clojure-omit-space-between-tag-and-delimiters) + "\\_<\\(?:'+\\|#.*\\)" + "\\_<\\(?:'+\\|#\\)") + (point-at-bol))))) (defconst clojure--collection-tag-regexp "#\\(::[a-zA-Z0-9._-]*\\|:?\\([a-zA-Z0-9._-]+/\\)?[a-zA-Z0-9._-]+\\)" "Collection reader macro tag regexp. @@ -468,29 +471,8 @@ collection literal (e.g. '[]' or '{}'), as reader macro tags. This includes #fully.qualified/my-ns[:kw val] and #::my-ns{:kw val} as of Clojure 1.9.") -(defun clojure-no-space-after-tag (endp delimiter) - "Prevent inserting a space after a reader-literal tag. - -When a reader-literal tag is followed be an opening delimiter -listed in `clojure-omit-space-between-tag-and-delimiters', this -function returns t. - -This allows you to write things like #db/id[:db.part/user] -and #::my-ns{:some \"map\"} without inserting a space between -the tag and the opening bracket. - -See `paredit-space-for-delimiter-predicates' for the meaning of -ENDP and DELIMITER." - (if endp - t - (or (not (member delimiter clojure-omit-space-between-tag-and-delimiters)) - (save-excursion - (let ((orig-point (point))) - (not (and (re-search-backward - clojure--collection-tag-regexp - (line-beginning-position) - t) - (= orig-point (match-end 0))))))))) +(make-obsolete-variable 'clojure--collection-tag-regexp nil "5.12.0") +(make-obsolete #'clojure-no-space-after-tag #'clojure-space-for-delimiter-p "5.12.0") (declare-function paredit-open-curly "ext:paredit" t t) (declare-function paredit-close-curly "ext:paredit" t t) @@ -517,8 +499,6 @@ replacement for `cljr-expand-let`." (make-local-variable 'paredit-space-for-delimiter-predicates) (add-to-list 'paredit-space-for-delimiter-predicates #'clojure-space-for-delimiter-p) - (add-to-list 'paredit-space-for-delimiter-predicates - #'clojure-no-space-after-tag) (advice-add 'paredit-convolute-sexp :after #'clojure--replace-let-bindings-and-indent))) (defun clojure-mode-variables () diff --git a/test/clojure-mode-syntax-test.el b/test/clojure-mode-syntax-test.el index af00c1a7..f3699f67 100644 --- a/test/clojure-mode-syntax-test.el +++ b/test/clojure-mode-syntax-test.el @@ -75,15 +75,6 @@ (backward-prefix-chars) (expect (bobp)))))) -(describe "clojure-no-space-after-tag" - (it "should allow allow collection tags" - (dolist (tag '("#::ns" "#:ns" "#ns" "#:f.q/ns" "#f.q/ns" "#::")) - (with-clojure-buffer tag - (expect (clojure-no-space-after-tag nil ?{) :to-be nil))) - (dolist (tag '("#$:" "#/f" "#:/f" "#::f.q/ns" "::ns" "::" "#f:ns")) - (with-clojure-buffer tag - (expect (clojure-no-space-after-tag nil ?{)))))) - (describe "fill-paragraph" (it "should work within comments" From e3271a4d227ae4f9d22ec085d13ddf85672c809d Mon Sep 17 00:00:00 2001 From: yuhan0 Date: Sat, 18 Apr 2020 16:52:01 +0800 Subject: [PATCH 9/9] Add tests for paredit reader tags --- .../clojure-mode-external-interaction-test.el | 32 +++++++++++++++++-- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/test/clojure-mode-external-interaction-test.el b/test/clojure-mode-external-interaction-test.el index 41b1aebb..8451abe1 100644 --- a/test/clojure-mode-external-interaction-test.el +++ b/test/clojure-mode-external-interaction-test.el @@ -23,7 +23,7 @@ (require 'buttercup) (require 'paredit) -(describe "Interactions with Paredit" +(describe "Interactions with Paredit:" ;; reuse existing when-refactoring-it macro (describe "it should insert a space" (when-refactoring-it "before lists" @@ -56,7 +56,7 @@ "foo' ()" (paredit-mode) (paredit-open-round))) - (describe "should not insert a space" + (describe "it should not insert a space" (when-refactoring-it "for anonymous fn syntax" "foo #" "foo #()" @@ -81,7 +81,33 @@ "foo #?" "foo #?()" (paredit-mode) - (paredit-open-round)))) + (paredit-open-round))) + (describe "reader tags" + (when-refactoring-it "should insert a space before strings" + "#uuid" + "#uuid \"\"" + (paredit-mode) + (paredit-doublequote)) + (when-refactoring-it "should not insert a space before namespaced maps" + "#::my-ns" + "#::my-ns{}" + (paredit-mode) + (paredit-open-curly)) + (when-refactoring-it "should not insert a space before namespaced maps 2" + "#::" + "#::{}" + (paredit-mode) + (paredit-open-curly)) + (when-refactoring-it "should not insert a space before namespaced maps 3" + "#:fully.qualified.ns123.-$#.%*+!" + "#:fully.qualified.ns123.-$#.%*+!{}" + (paredit-mode) + (paredit-open-curly)) + (when-refactoring-it "should not insert a space before tagged vectors" + "#tag123.-$#.%*+!" + "#tag123.-$#.%*+![]" + (paredit-mode) + (paredit-open-square)))) (describe "Interactions with delete-trailing-whitespace"