-
-
Notifications
You must be signed in to change notification settings - Fork 648
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
Show available nrepl ports when connecting #3392
Show available nrepl ports when connecting #3392
Conversation
f4c4d9b
to
ad5bc9d
Compare
@vemv I seem to have managed to make things work via I had to select the right process id via ps + grep + awk and then feed all the ids separated by comma to lsof to extract the current working directory of the processes. It is a mouthful to write down and a pretty long shell command: I would be grateful for an opinion about how to make it more readable :) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like a great start to me!
Added some suggestions.
I would be grateful for an opinion about how to make it more readable
It looks reasonable to me, perhaps I'm not a fan of awk but I don't have have an immediate suggestion. Can always be refined later.
cider.el
Outdated
(defun cider--running-other-nrepl-paths () | ||
"Retrieve project paths of other running nREPL servers." | ||
(let* ((take-non-lein-nrepl-pids | ||
"ps u | grep java | grep -v leiningen | grep nrepl.cmdline | awk '{print $2}' | tr '\012' ,") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what does | tr '\012'
accomplish?
- This works on my macos machine
ps u | grep java | grep -v leiningen | awk '{print $2}'
- adding
| tr '\012'
doesn't:
$ ps u | grep java | grep -v leiningen | awk '{print $2}' | tr '\012'
usage: tr [-Ccsu] string1 string2
tr [-Ccu] -d string1
tr [-Ccu] -s string1
tr [-Ccu] -ds string1 string2
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tr '\012' ,
is replacing newlines with commas
in linux, running this in the terminal
echo "hi
hello" | tr '\012' ,
produces this
hi,hello,
It seems that lsof
can take a comma separated list of process ids in the -p option, which was nice for our use case.
Maybe on MacOS the character for new line is not parsed as in Linux, I am substituting that with paste -s -d,
, which seems also less cryptic (that changes both newlines or spaces in commas)
(lambda (b) (string-prefix-p "*cider-repl" (buffer-name b))) | ||
(buffer-list)))) | ||
|
||
(defun cider--running-nrepl-paths () |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nrepl-extract-ports
will be called over each element of cider--running-nrepl-paths
.
defun nrepl-extract-ports
is based on (expand-file-name "repl-port" dir)
. That won't work over all possible invocations. It also represents redundant work, to some degree.
I'd suggest that when possible, return a (list dir port)
instead of just a dir
.
So that we can make this change:
(defun cider-locate-running-nrepl-ports (&optional dir)
"Locate ports of running nREPL servers.
When DIR is non-nil also look for nREPL port files in DIR. Return a list
of list of the form (project-dir port)."
(let* ((paths (cider--running-nrepl-paths))
(proj-ports (apply #'append
(mapcar (lambda (d)
+ (if (listp d)
+ d ;; (directory port) pair was passed, nothing to do
+ ;; directory was passed, use old behavior:
(mapcar (lambda (p)
(list (file-name-nondirectory (directory-file-name d)) p))
(and d (nrepl-extract-ports (cider--file-path d))))))
(cons (clojure-project-dir dir) paths)))))
(seq-uniq (delq nil proj-ports))))
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
uhm. I see the optimization here. A note though: we have to return a (list d)
and we still have to apply (file-name-nondirectory (directory-file-name d))
, to get just the directory name.
This also makes the seq-uniq needing a predicate for handling equality between paths and pairs (path-port).
So it feels we are trading too much on readability for what the optimization gives to us, no?
To get more, I could make also the other nREPL search return ports and I indeed had a thought while implementing that if I use lsof, I could get ports as well but it seemed less readable to further complicate the shell command.
Should this maybe be tackled in another issue to avoid the added code complexity for now?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(here the patch with the change if you want to see how the code would look like
opt.txt
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this maybe be tackled in another issue to avoid the added code complexity for now?
Yes this sounds reasonable, your PR already is a great improvement 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Almost there - thanks for the iteration!
cider.el
Outdated
(defun cider--running-other-nrepl-paths () | ||
"Retrieve project paths of running nREPL servers other than Lein ones." | ||
(let* ((take-non-lein-nrepl-pids | ||
"ps u | grep java | grep -v leiningen | grep nrepl.cmdline | awk '{print $2}' | paste -s -d,") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like it almost works on macos - here's a sample session:
~/orchard (master) $ ps u | grep java | grep -v leiningen | grep nrepl.cmdline | awk '{print $2}'
72926
~/orchard (master) $ ps u | grep java | grep -v leiningen | grep nrepl.cmdline | awk '{print $2}' | paste -s -d,
usage: paste [-s] [-d delimiters] file ...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
uhm I made the redirection explicit following this https://www.reddit.com/r/linuxquestions/comments/y96jbk/why_cant_i_pipe_awk_into_paste_macos/?rdt=44305
sorry for the multiple attempts
cider.el
Outdated
(concat | ||
"lsof -a -d cwd -p $(" | ||
take-non-lein-nrepl-pids | ||
") -n -Fn | awk '/^n/ {print substr($0,2)}'")) ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can confirm this works on macos:
~/orchard (master) $ lsof -a -d cwd -p $(ps u | grep java | grep -v leiningen | grep nrepl.cmdline | awk '{print $2}') -n -Fn | awk '/^n/ {print substr($0,2)}'
/Users/vemv/orchard
It doesn't have the paste -s -d,
part, which may have to be added/tweaked.
(lambda (b) (string-prefix-p "*cider-repl" (buffer-name b))) | ||
(buffer-list)))) | ||
|
||
(defun cider--running-nrepl-paths () |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this maybe be tackled in another issue to avoid the added code complexity for now?
Yes this sounds reasonable, your PR already is a great improvement 👍
cider.el
Outdated
|
||
(defun cider--running-other-nrepl-paths () | ||
"Retrieve project paths of running nREPL servers other than Lein ones." | ||
(let* ((take-non-lein-nrepl-pids |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's guard this and similar code with (when-not (memq system-type '(cygwin windows-nt))
…ing-local-nrepl-paths CIDER misses nREPLs that didn't start via Leiningen. The plan is to enhance cider--running-nrepl-paths to have multiple sources of paths. I found out that given a path, cider-locate-running-nrepl-ports can find the right port via nrepl-extract-ports. This also adds the paths created by running cider-jack-in via Emacs.
This uses lsof in combination with ps and grep to find paths of java processes that may be nREPL. Again we rely on nrepl-extract-ports in cider-locate-running-nrepl-ports to get rid of invalid paths.
Co-authored-by: vemv <[email protected]>
…indows Some of the commands we run via shell are incompatible with the Windows prompt, for example there is no lsof command in Windows.
4c0699e
to
0ec5789
Compare
@@ -1810,17 +1810,56 @@ of list of the form (project-dir port)." | |||
(cons (clojure-project-dir dir) paths))))) | |||
(seq-uniq (delq nil proj-ports)))) | |||
|
|||
(defun cider--running-nrepl-paths () | |||
"Retrieve project paths of running nREPL servers. | |||
(defun cider--windows-p () |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we even need this helper? I mean - nothing modern is going to return ms-dos
and I think cygwin
provides the common Unix commands.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure myself, I wanted to add the guard because we didn't test there and there may be chance the functions don't work there. I can definitely remove ms-dos, I added it only for completeness.
cider.el
Outdated
(setq paths (cons (match-string 1) paths))))) | ||
paths))) | ||
|
||
(defun cider--running-other-nrepl-paths () |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think "other" in this name might be a big confusing, as you won't understand without the docstring that it means "other than Lein". Perhaps "non-lein"?
CHANGELOG.md
Outdated
@@ -21,6 +21,7 @@ | |||
- [#3236](https://github.com/clojure-emacs/cider/issues/3236): `cider-repl-set-ns` no longer changes the repl session type from `cljs:shadow` to `clj`. | |||
- [#3383](https://github.com/clojure-emacs/cider/issues/3383): `cider-connect-clj&cljs`: don't render `"ClojureScript REPL type:" for JVM repls. | |||
- [#3331](https://github.com/clojure-emacs/cider/issues/3331): `cider-eval`: never jump to spurious locations, as sometimes conveyed by nREPL. | |||
- [#3390](https://github.com/clojure-emacs/cider/issues/3390) Enhance cider-connect to show all nREPLs available ports, instead of only Leinengen ones. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't forget the :
here. Also - Leiningen. :-)
…non-lein-nrepl-paths
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One last detail, I believe 🙌
"Retrieve project paths of running nREPL servers other than Lein ones." | ||
(unless (cider--windows-p) | ||
(let* ((take-non-lein-nrepl-pids | ||
"ps u | grep java | grep -v leiningen | grep nrepl.cmdline | awk '{print $2}' | paste -s -d, -") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I verified that lsof -a -d cwd -p $(ps u | grep java | grep -v leiningen | grep nrepl.cmdline | awk '{print $2}' | paste -s -d, -) -n -Fn | awk '/^n/ {print substr($0,2)}'
can run OK on macOS - it can return either nothing or ports.
However, your code should handle the case where nothing is returned. Else the lsof
call will fail.
For that, I'd suggest running take-non-lein-nrepl-pids
as an individual shell-command-to-string-call. Abort the defun if it returned nothing / empty string. Else, it's safe to proceed.
Under this approach, $()
is no longer needed.
"Retrieve project paths of running nREPL servers. | ||
Search for lein or java processes including nrepl.command nREPL" | ||
(let ((paths (append | ||
(cider--running-lein-nrepl-paths) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if we could have some generic error handling. It wouldn't be too surprising to hear that someone was running a very particular *nix, such that cider-connect is failing for them due to the ps u | grep java | grep -v leiningen | grep nrepl.cmdline | awk | ...
call.
Needless to say, cider-connect is too important to fail because of a feature that in the end is a "nice to have".
Maybe, wrap each call in a condition-case
, and additionally, filter the results by file-directory-p
(to avoid including any error-like messages)?
(I wrote something intended for another PR, deleted. Please ignore) |
I'll reopen this one from scratch, preserving attribution.
I would not want to create a frustrating "feedback loop" - we all know what it's to be there! Thanks - V |
it was alright, I suspect it would have made sense for me to just add the local dir paths and leave the other bit for a second PR. |
Improve cider-connect to show all available ports of running nREPLs.
Fixes #3390
See recording for a peek :)
simplescreenrecorder-2023-08-03_23.00.23.mp4
Before submitting the PR make sure the following things have been done (and denote this
by checking the relevant checkboxes):
eldev test
)eldev lint
) which is based onelisp-lint
and includescheckdoc
, check-declare, packaging metadata, indentation, and trailing whitespace checks.