Skip to content

Fix for #83 #85

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
Jul 3, 2017
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
### Bugs Fixed

* [#77](https://github.com/clojure-emacs/inf-clojure/pull/77): Fix request "Eval expression:" if arglists return is `nil`.
* [#83](https://github.com/clojure-emacs/inf-clojure/pull/85): No such namespace: complete.core in lumo REPL.

## 2.0.0 (2017-05-01)

Expand Down
122 changes: 79 additions & 43 deletions inf-clojure.el
Original file line number Diff line number Diff line change
Expand Up @@ -940,17 +940,22 @@ prefix argument PROMPT-FOR-SYMBOL, it prompts for a symbol name."
(inf-clojure-symbol-at-point))))
(comint-proc-query (inf-clojure-proc) (format (inf-clojure-var-source-form) var))))

;;;; Response parsing
;;;; ================

(defvar inf-clojure--redirect-buffer-name " *Inf-Clojure Redirect Buffer*")

;; Originally from:
;; https://github.com/glycerine/lush2/blob/master/lush2/etc/lush.el#L287
(defun inf-clojure-results-from-process (process command &optional beg-string end-string)
"Send COMMAND to PROCESS.
(defun inf-clojure--process-response (command process &optional beg-string end-string)
"Send COMMAND to PROCESS and return the response.
Return the result of COMMAND starting with BEG-STRING and ending
with END-STRING if non-nil. If BEG-STRING is nil, the result
string will start from (point) in the results buffer. If
END-STRING is nil, the result string will end at (point-max) in
the results buffer. It cuts out the output from
`inf-clojure-prompt` onwards unconditionally."
(let ((work-buffer " *Inf-Clojure Redirect Work Buffer*"))
the results buffer. It cuts out the output from and including
the `inf-clojure-prompt`."
(let ((work-buffer inf-clojure--redirect-buffer-name))
(save-excursion
(set-buffer (get-buffer-create work-buffer))
(erase-buffer)
Expand All @@ -963,29 +968,68 @@ the results buffer. It cuts out the output from
;; Collect the output
(set-buffer work-buffer)
(goto-char (point-min))
;; Skip past the command, if it was echoed
(and (looking-at command)
(forward-line))
(let* ((beg (if beg-string
(progn (search-forward beg-string nil t) (match-beginning 0))
(point)))
(end (if end-string
(search-forward end-string nil t)
(point-max)))
(buffer-string (buffer-substring-no-properties beg end)))
(when (and buffer-string (string-match inf-clojure-prompt buffer-string))
(substring buffer-string 0 (match-beginning 0)))))))
(let* ((beg (or (when (and beg-string (search-forward beg-string nil t))
(match-beginning 0))
(point-min)))
(end (or (when end-string
(search-forward end-string nil t))
(point-max)))
(prompt (when (search-forward inf-clojure-prompt nil t)
(match-beginning 0))))
(buffer-substring-no-properties beg (or prompt end))))))

(defun inf-clojure--nil-string-match-p (string)
"Return true iff STRING is not nil.
This function also takes into consideration weird escape
character and matches if nil is anywhere within the input
string."
(string-match-p "\\Ca*nil\\Ca*" string))

(defun inf-clojure--some (data)
"Return DATA unless nil or includes \"nil\" as string."
(cond
((null data) nil)
((and (stringp data)
(inf-clojure--nil-string-match-p data)) nil)
(t data)))

(defun inf-clojure--read-or-nil (response)
"Read RESPONSE and return it as data.

If response is nil or includes the \"nil\" string return nil
instead.

Note that the read operation will always return the first
readable sexp only."
;; The following reads the first LISP expression
(inf-clojure--some
(when response
(ignore-errors (read response)))))

(defun inf-clojure--process-response-match-p (match-p proc form)
"Eval MATCH-P on the response of sending to PROC the input FORM.
Note that this function will add a \n to the end (or )f the string
for evaluation, therefore FORM should not include it."
(when-let ((response (inf-clojure--process-response form proc)))
(funcall match-p response)))

(defun inf-clojure--some-response-p (proc form)
"Return true iff PROC's response after evaluating FORM is not nil."
(inf-clojure--process-response-match-p
(lambda (string)
(not (inf-clojure--nil-string-match-p string)))
proc form))

;;;; Commands
;;;; ========

(defun inf-clojure-arglists (fn)
"Send a query to the inferior Clojure for the arglists for function FN.
See variable `inf-clojure-arglists-form'."
(let* ((arglists-snippet (format (inf-clojure-arglists-form) fn))
(arglists-result (inf-clojure-results-from-process (inf-clojure-proc) arglists-snippet))
(arglists-data (when arglists-result (read arglists-result))))
(cond
((null arglists-data) nil)
((stringp arglists-data) arglists-data)
((listp arglists-data) arglists-result))))
(thread-first
(format (inf-clojure-arglists-form) fn)
(inf-clojure--process-response (inf-clojure-proc) "(" ")")
(inf-clojure--some)))

(defun inf-clojure-show-arglists (prompt-for-symbol)
"Show the arglists for function FN in the mini-buffer.
Expand Down Expand Up @@ -1051,26 +1095,18 @@ See variable `inf-clojure-buffer'."
(or proc
(error "No Clojure subprocess; see variable `inf-clojure-buffer'"))))

(defun inf-clojure--list-or-nil (data)
"Return DATA if and only if it is a list."
(when (listp data) data))

(defun inf-clojure-completions (expr)
"Return a list of completions for the Clojure expression starting with EXPR."
(let* ((proc (inf-clojure-proc))
(comint-filt (process-filter proc))
(kept "")
completions)
(set-process-filter proc (lambda (_proc string) (setq kept (concat kept string))))
(unwind-protect
(let ((completion-snippet
(format
(inf-clojure-completion-form) (substring-no-properties expr))))
(process-send-string proc completion-snippet)
(while (and (not (string-match inf-clojure-prompt kept))
(accept-process-output proc 2)))
(setq completions (read kept))
;; Subprocess echoes output on Windows and OS X.
(when (and completions (string= (concat (car completions) "\n") completion-snippet))
(setq completions (cdr completions))))
(set-process-filter proc comint-filt))
completions))
(when (not (string-blank-p expr))
(thread-first
(format (inf-clojure-completion-form) (substring-no-properties expr))
(inf-clojure--process-response (inf-clojure-proc) "(" ")")
(inf-clojure--read-or-nil)
(inf-clojure--list-or-nil))))

(defconst inf-clojure-clojure-expr-break-chars " \t\n\"\'`><,;|&{(")

Expand Down Expand Up @@ -1232,7 +1268,7 @@ to suppress the usage of the target buffer discovery logic."
"Return MATCH-P on the result of sending FORM to PROC.
Note that this function will add a \n to the end of the string
for evaluation, therefore FORM should not include it."
(funcall match-p (inf-clojure-results-from-process proc form nil)))
(funcall match-p (inf-clojure--process-response form proc nil)))

;;;; Lumo
;;;; ====
Expand Down