From 74a6fac31914d32f524e52894d95ee45085dbaf9 Mon Sep 17 00:00:00 2001 From: Andrea Richiardi Date: Mon, 22 Jan 2018 14:24:44 -0800 Subject: [PATCH 1/5] Add @ (deref) and ^ to the expression breaking chars They were both missing and therefore the inf-clojure was not able to identify completions bounds correctly. --- inf-clojure.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inf-clojure.el b/inf-clojure.el index b1956e8..8c5befd 100644 --- a/inf-clojure.el +++ b/inf-clojure.el @@ -1344,7 +1344,7 @@ you might want to use in your customization." :safe #'functionp :package-version '(inf-clojure . "2.1.0")) -(defconst inf-clojure-clojure-expr-break-chars " \t\n\"\'`><,;|&{()[]") +(defconst inf-clojure-clojure-expr-break-chars " \t\n\"\'`><,;|&{()[]@\\^") (defun inf-clojure-completion-bounds-of-expr-at-point () "Return bounds of expression at point to complete." From 213f6bd0241dad1fadcb2bb0e4a9d782a864b4e5 Mon Sep 17 00:00:00 2001 From: Andrea Richiardi Date: Mon, 22 Jan 2018 16:25:41 -0800 Subject: [PATCH 2/5] Avoid computing completion bounds when no valid chars are at point For instance we want to avoid using substring-no-properties while typing ^| (where | is point) because it will error out. --- inf-clojure.el | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/inf-clojure.el b/inf-clojure.el index 8c5befd..127ff9c 100644 --- a/inf-clojure.el +++ b/inf-clojure.el @@ -1352,9 +1352,11 @@ you might want to use in your customization." (save-excursion (let ((end (point))) (skip-chars-backward (concat "^" inf-clojure-clojure-expr-break-chars)) - (let ((first-char (substring-no-properties (thing-at-point 'symbol) 0 1))) - (when (string-match-p "[^0-9]" first-char) - (cons (point) end))))))) + (let ((chars (thing-at-point 'symbol))) + (when (> (length chars) 0) + (let ((first-char (substring-no-properties chars 0 1))) + (when (string-match-p "[^0-9]" first-char) + (cons (point) end))))))))) (defun inf-clojure-completion-expr-at-point () "Return expression at point to complete." From dbe2839dd2f1f14b4466be9cfcd220608630806f Mon Sep 17 00:00:00 2001 From: Andrea Richiardi Date: Fri, 26 Jan 2018 12:36:37 -0800 Subject: [PATCH 3/5] Extract keyword words for completion The patch copies functionality from cider so that now inf-clojure can detect and extract keywords (colons included) when a symbol at point is not found. --- inf-clojure.el | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/inf-clojure.el b/inf-clojure.el index 127ff9c..382f223 100644 --- a/inf-clojure.el +++ b/inf-clojure.el @@ -1344,19 +1344,38 @@ you might want to use in your customization." :safe #'functionp :package-version '(inf-clojure . "2.1.0")) -(defconst inf-clojure-clojure-expr-break-chars " \t\n\"\'`><,;|&{()[]@\\^") +(defconst inf-clojure-clojure-expr-break-chars "^[] \"'`><,;|&{()[@\\^]" + "Regexp are hard. + +This regex has been built in order to match the first of the +listed chars. There are a couple of quirks to consider: + +- the ] is always a special in elisp regex so you have to put it + directly AFTER [ if you want to match it as literal. +- The ^ needs to be escaped with \\^. + +Tests and `re-builder' are your friends.") + +(defun inf-clojure--kw-to-symbol (kw) + "Convert the keyword KW to a symbol. + +This guy was taken from CIDER, thanks folks." + (when kw + (replace-regexp-in-string "\\`:+" "" kw))) (defun inf-clojure-completion-bounds-of-expr-at-point () "Return bounds of expression at point to complete." (when (not (memq (char-syntax (following-char)) '(?w ?_))) (save-excursion - (let ((end (point))) - (skip-chars-backward (concat "^" inf-clojure-clojure-expr-break-chars)) - (let ((chars (thing-at-point 'symbol))) - (when (> (length chars) 0) - (let ((first-char (substring-no-properties chars 0 1))) - (when (string-match-p "[^0-9]" first-char) - (cons (point) end))))))))) + (let* ((end (point)) + (skipped-back (skip-chars-backward inf-clojure-clojure-expr-break-chars)) + (start (+ end skipped-back)) + (chars (or (thing-at-point 'symbol) + (inf-clojure--kw-to-symbol (buffer-substring start end))))) + (when (> (length chars) 0) + (let ((first-char (substring-no-properties chars 0 1))) + (when (string-match-p "[^0-9]" first-char) + (cons (point) end)))))))) (defun inf-clojure-completion-expr-at-point () "Return expression at point to complete." From ff633530fc187b67f41370067bd23c1a5f2dd6a9 Mon Sep 17 00:00:00 2001 From: Andrea Richiardi Date: Mon, 22 Jan 2018 15:55:23 -0800 Subject: [PATCH 4/5] Add test harness (finally?) This patch add ert test harness and some tests around the inf-clojure-completion-bounds-of-expr-at-point function. --- .gitignore | 12 ++++ .travis.yml | 17 ++++++ Cask | 11 ++++ test/inf-clojure-tests.el | 114 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 154 insertions(+) create mode 100644 .gitignore create mode 100644 .travis.yml create mode 100644 Cask create mode 100644 test/inf-clojure-tests.el diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c724233 --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ +*~ +*\#*\# +*.\#* +*.elc +.cask +elpa* +.depend +TAGS +.DS_STORE +dist +.vagrant/ +.dir-locals?.el diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..57ec6dd --- /dev/null +++ b/.travis.yml @@ -0,0 +1,17 @@ +language: generic +sudo: false +before_install: + - curl -fsSkL https://gist.github.com/rejeep/ebcd57c3af83b049833b/raw > x.sh && source ./x.sh + - evm install $EVM_EMACS --use --skip + - cask +env: + - EVM_EMACS=emacs-24.3-travis + - EVM_EMACS=emacs-24.4-travis + - EVM_EMACS=emacs-24.5-travis + - EVM_EMACS=emacs-25.1-travis + - EVM_EMACS=emacs-25.2-travis + - EVM_EMACS=emacs-25.3-travis +script: + - emacs --version + - cask install + - cask exec buttercup -L . diff --git a/Cask b/Cask new file mode 100644 index 0000000..d2a5667 --- /dev/null +++ b/Cask @@ -0,0 +1,11 @@ +(source gnu) +(source melpa) + +(package-file "inf-clojure.el") + +(files "*.el" (:exclude ".dir-locals.el")) + +(development + (depends-on "clojure-mode") + (depends-on "buttercup") + (depends-on "assess")) diff --git a/test/inf-clojure-tests.el b/test/inf-clojure-tests.el new file mode 100644 index 0000000..994801c --- /dev/null +++ b/test/inf-clojure-tests.el @@ -0,0 +1,114 @@ +;;; inf-clojure-tests.el --- Tests for Inf-Clojure -*- lexical-binding: t; -*- +;; +;; Copyright © 2014-2018 Bozhidar Batsov + +;; Authors: Bozhidar Batsov +;; Andrea Richiardi +;; URL: http://github.com/clojure-emacs/inf-clojure +;; Keywords: processes, clojure +;; Package-Requires: ((emacs "24.4") (clojure-mode "5.3")) + +;; This file is part of GNU Emacs. + +;; GNU Emacs 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. + +;; GNU Emacs 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 GNU Emacs. If not, see . + +;;; Commentary: +;; +;; Code completion using alexander-yakushev/compliment. + +;;; Code: + +;; Tests for inf-clojure.el + +(message "Running tests on Emacs %s" emacs-version) + +(require 'buttercup) +(require 'assess) +(require 'inf-clojure) + +(cl-defmacro ict-with-assess-buffers ((&rest varlist) &body body) + `(assess-with-temp-buffers (,@varlist) + (clojure-mode) + (inf-clojure-minor-mode) + ,@body)) + +(defun ict-bounds-string (bounds) + (buffer-substring (car bounds) (cdr bounds))) + +(describe "inf-clojure--kw-to-symbol" + (it "returns symbol form of the given keyword" + (expect (inf-clojure--kw-to-symbol "symbol") :to-equal "symbol") + (expect (inf-clojure--kw-to-symbol ":clj.core/str") :to-equal "clj.core/str") + (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" () + (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")))) + + (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")))) + + (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")))) + + (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")))) + + (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")))) + + (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)))) + + (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")))) + + (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"))))) + +;;; inf-clojure-tests.el ends here From 12ce769ad3920b6596370daf5714f1c47133e019 Mon Sep 17 00:00:00 2001 From: Andrea Richiardi Date: Fri, 26 Jan 2018 12:41:29 -0800 Subject: [PATCH 5/5] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4864593..87b78fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ * [#128](https://github.com/clojure-emacs/inf-clojure/pull/128): Expose `inf-clojure-apropos` as `C-c C-S-a` in `inf-clojure-mode` (the REPL). * [#125](https://github.com/clojure-emacs/inf-clojure/pull/125): Avoid throwing an error for frequent operations like completion. * [#130](https://github.com/clojure-emacs/inf-clojure/pull/130): Support loading directory locals in our buffers. +* [#129](https://github.com/clojure-emacs/inf-clojure/pull/129): Improve the completion bounds detection (now with keywords). ### Bugs Fixed