Skip to content

Handle newlines between forms for inf-clojure-eval-buffer #188

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 17, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 29 additions & 5 deletions inf-clojure.el
Original file line number Diff line number Diff line change
Expand Up @@ -683,16 +683,40 @@ HOST is the host the process is running on, PORT is where it's listening."
(interactive "shost: \nnport: ")
(inf-clojure (cons host port)))

(defun inf-clojure--forms-without-newlines (str)
"Remove newlines between toplevel forms.
STR is a string of contents to be evaluated. When sending
multiple forms to a socket repl, each newline triggers a prompt.
So we replace all newlines between top level forms but not inside
of forms."
(condition-case nil
(with-temp-buffer
(progn
(clojurec-mode)
(insert str)
(whitespace-cleanup)
(goto-char (point-min))
(while (not (eobp))
(while (looking-at "\n")
(delete-char 1))
(unless (eobp)
(clojure-forward-logical-sexp))
(unless (eobp)
(forward-char)))
(buffer-substring-no-properties (point-min) (point-max))))
(scan-error str)))

(defun inf-clojure-eval-region (start end &optional and-go)
"Send the current region to the inferior Clojure process.
Sends substring between START and END. Prefix argument AND-GO
means switch to the Clojure buffer afterwards."
(interactive "r\nP")
;; drops newlines at the end of the region
(let ((str (replace-regexp-in-string
"[\n]+\\'" ""
(buffer-substring-no-properties start end))))
(inf-clojure--send-string (inf-clojure-proc) str))
(let* ((str (buffer-substring-no-properties start end))
;; newlines over a socket repl between top level forms cause
;; a prompt to be returned. so here we dump the region into a
;; temp buffer, and delete all newlines between the forms
(formatted (inf-clojure--forms-without-newlines str)))
(inf-clojure--send-string (inf-clojure-proc) formatted))
(when and-go (inf-clojure-switch-to-repl t)))

(defun inf-clojure-eval-string (code)
Expand Down
122 changes: 76 additions & 46 deletions test/inf-clojure-tests.el
Original file line number Diff line number Diff line change
Expand Up @@ -48,76 +48,106 @@
(expect (inf-clojure--kw-to-symbol "::keyword") :to-equal "keyword")
(expect (inf-clojure--kw-to-symbol nil) :to-equal nil)))

(describe "completion bounds at point" ()
(describe "completion bounds at point"
(it "computes bounds for plain-text"
(ict-with-assess-buffers
((a (insert "plain-text")))
(with-current-buffer a
(expect (ict-bounds-string (inf-clojure-completion-bounds-of-expr-at-point))
:to-equal "plain-text"))))
(ict-with-assess-buffers
((a (insert "plain-text")))
(with-current-buffer a
(expect (ict-bounds-string (inf-clojure-completion-bounds-of-expr-at-point))
:to-equal "plain-text"))))

(it "computes bounds for @deref"
(ict-with-assess-buffers
((a (insert "@deref")))
(with-current-buffer a
(expect (ict-bounds-string (inf-clojure-completion-bounds-of-expr-at-point))
:to-equal "deref"))))
(ict-with-assess-buffers
((a (insert "@deref")))
(with-current-buffer a
(expect (ict-bounds-string (inf-clojure-completion-bounds-of-expr-at-point))
:to-equal "deref"))))

(it "computes bounds for ^:keyword"
(ict-with-assess-buffers
((a (insert "^:keyword")))
(with-current-buffer a
(expect (ict-bounds-string (inf-clojure-completion-bounds-of-expr-at-point))
:to-equal ":keyword"))))
(ict-with-assess-buffers
((a (insert "^:keyword")))
(with-current-buffer a
(expect (ict-bounds-string (inf-clojure-completion-bounds-of-expr-at-point))
:to-equal ":keyword"))))

(it "computes bounds for ::keyword"
(ict-with-assess-buffers
((a (insert "::keyword")))
(with-current-buffer a
(expect (ict-bounds-string (inf-clojure-completion-bounds-of-expr-at-point))
:to-equal "::keyword"))))
(ict-with-assess-buffers
((a (insert "::keyword")))
(with-current-buffer a
(expect (ict-bounds-string (inf-clojure-completion-bounds-of-expr-at-point))
:to-equal "::keyword"))))

(it "computes bounds for [^:keyword (combined break chars and keyword)"
(ict-with-assess-buffers
((a (insert "[^:keyword")))
(with-current-buffer a
(expect (ict-bounds-string (inf-clojure-completion-bounds-of-expr-at-point))
:to-equal ":keyword"))))
(ict-with-assess-buffers
((a (insert "[^:keyword")))
(with-current-buffer a
(expect (ict-bounds-string (inf-clojure-completion-bounds-of-expr-at-point))
:to-equal ":keyword"))))

(it "computes no bounds for point directly after a break expression"
(ict-with-assess-buffers
((a (insert "@")))
(with-current-buffer a
(expect
(ict-bounds-string (inf-clojure-completion-bounds-of-expr-at-point))
:not :to-be nil))))
(ict-with-assess-buffers
((a (insert "@")))
(with-current-buffer a
(expect
(ict-bounds-string (inf-clojure-completion-bounds-of-expr-at-point))
:not :to-be nil))))

(it "computes bounds for [symbol"
(ict-with-assess-buffers
((a (insert "[symbol")))
(with-current-buffer a
(expect (ict-bounds-string (inf-clojure-completion-bounds-of-expr-at-point))
:to-equal "symbol"))))
(ict-with-assess-buffers
((a (insert "[symbol")))
(with-current-buffer a
(expect (ict-bounds-string (inf-clojure-completion-bounds-of-expr-at-point))
:to-equal "symbol"))))

(it "computes bounds for (@deref (multiple break chars)"
(ict-with-assess-buffers
((a (insert "(@deref")))
(with-current-buffer a
(expect (ict-bounds-string (inf-clojure-completion-bounds-of-expr-at-point))
:to-equal "deref")))))
(ict-with-assess-buffers
((a (insert "(@deref")))
(with-current-buffer a
(expect (ict-bounds-string (inf-clojure-completion-bounds-of-expr-at-point))
:to-equal "deref")))))

(describe "inf-clojure--sanitize-command"
(it "sanitizes the command correctly"
(expect (inf-clojure--sanitize-command "(doc println)") :to-equal "(doc println)\n"))
(expect (inf-clojure--sanitize-command "(doc println)") :to-equal "(doc println)\n"))

(it "trims newline at the right of a command"
(expect (inf-clojure--sanitize-command "(doc println)\n\n\n\n") :to-equal "(doc println)\n"))
(expect (inf-clojure--sanitize-command "(doc println)\n\n\n\n") :to-equal "(doc println)\n"))

(it "returns empty string when the command is empty"
(expect (inf-clojure--sanitize-command " ") :to-equal ""))
(expect (inf-clojure--sanitize-command " ") :to-equal ""))

(it "only removes whitespace at the end of the command - fix 152"
(expect (inf-clojure--sanitize-command "1 5") :to-equal "1 5\n")))
(expect (inf-clojure--sanitize-command "1 5") :to-equal "1 5\n")))

(describe "inf-clojure--forms-without-newlines"
(it "removes newlines between toplevel forms"
(expect (inf-clojure--forms-without-newlines
"(def foo 3)\n\n\n(def bar 4)")
:to-equal "(def foo 3)\n(def bar 4)"))
(it "doesn't remove newlines inside forms or strings"
(expect (inf-clojure--forms-without-newlines
"

(defn foo []

:foo)


(def thing \"this

is a string\")

(defn bar [])")
;; note no leading newline, newlines inside defn remain,
;; newlines inside string remain
:to-equal "(defn foo []

:foo)
(def thing \"this

is a string\")
(defn bar [])")))


(describe "inf-clojure--update-feature"
(it "updates new forms correctly"
Expand Down