This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-10-12
Channels
- # announcements (13)
- # aws (18)
- # babashka (60)
- # babashka-sci-dev (83)
- # beginners (32)
- # biff (18)
- # calva (22)
- # cider (8)
- # clj-on-windows (101)
- # clojure (59)
- # clojure-bay-area (2)
- # clojure-europe (36)
- # clojure-india (4)
- # clojure-nl (3)
- # clojure-norway (5)
- # clojure-spec (4)
- # clojure-uk (1)
- # clojurescript (5)
- # conjure (1)
- # core-async (10)
- # cursive (7)
- # data-science (5)
- # datahike (10)
- # datalog (11)
- # datomic (3)
- # docker (3)
- # figwheel-main (2)
- # gratitude (3)
- # improve-getting-started (1)
- # introduce-yourself (5)
- # jobs (3)
- # joyride (12)
- # leiningen (1)
- # lsp (67)
- # malli (27)
- # off-topic (36)
- # random (1)
- # rdf (1)
- # re-frame (17)
- # reagent (21)
- # reitit (4)
- # releases (4)
- # remote-jobs (2)
- # ring (2)
- # sci (35)
- # shadow-cljs (28)
- # sql (3)
- # squint (9)
- # tools-deps (11)
Is there a way to export the data that the lsp server generates given a codebase? I'd like to visualize the info contained in the call hierarchy with graphviz
the new clojure-lsp dump
command maybe? https://github.com/clojure-lsp/clojure-lsp/issues/744#issuecomment-1257075337
@UKFSJSM38 I got a dump of the analysis via the cli, but it only contains the data for the module level
dependency graph, right? Not for the function level
one (but maybe it's in the clj-kondo analysis). I would like to query the call hierarchy for the functions.
That would be possible only via the analysis data, but it may be interesting to support call hierarchy or something like that, but maybe that would be a different command, not a dump one since you would want for specific function
If the info is in the analysis data, where should I look to reconstruct the call graph for a function? I'm not sure about what the data in the dump covers.
Alternatively, is there a way of getting the raw data of the call hierarchy (like, the outgoing
function) directly from the repl? Could you explain how?
The call hierarchy is not available via the API yet, but something I never considered to support, I may add support soon, only available during editor usage unfortunately. About the analysis data, it's 99% clj-kondo analysis, which you can understand deeply here:, https://github.com/clj-kondo/clj-kondo/blob/master/analysis/README.md
Thank you, that seems awesome. What I meant before is: if I include clojure-lsp
in my dependencies and then require clojure-lsp.feature.call-hierarchy
, is there a simple way for me to call incoming
or outgoing
directly?
Yeah, that would hacky work if you call the analyze! function from the API first :)
The support of call hierarchy would basically wrap those things in a single function with better UX too
In this call to ongoing
, where should I grab components
?
(defn outgoing [uri row col {:keys [db*] :as components}] ...)
BTW @UA7E6DU04 what you would expect of return about a function clojure-lsp.api/definition
or clojure-lsp.api/incoming-call-hierarchy
?
Hmm, let's see, ideally what I want out of this is a graph, and I think that's the right data choice. The kind of data that is displayed in emacs via lsp is so redundant to be almost inusable I would say. What do you think?
maybe for definition?
{:uri "file:///home/foo/project/src/foo.clj"
:row 2
:col 4
:external-file false}
Yes, for call hierarhcy a graph similar to the dependency-graph
of the dump command sounds good to me
yes, that definition could be good. If I can also grab the form it's probably useful too
so that a tool could directly choose to present the informations without querying the data again. If not the entire form, I think I would appreciate a :range
if possible
hum, you mean?
{:uri "file:///home/foo/project/src/foo.clj"
:row 2
:col 4
:external-file false
:var-definition-form "(defn foo []\n (+ 1 2))"}
not sure if that would work for all/most cases, need to do a double check, but I can see how convenient it could be
something like that yes (I guess the :range
is a good secondary choice too, especially if we provide a convenience function to return the text afterwards)
Yes, I think we can just return the clj-kondo analysis definition which has all of that including range and data about the function name, args, doc etc
For the graph, I'm a bit torn myself: I would like to illustrate a case study of sorts:
cool, I will start with the definition as sounds like a good first case to support and learn about the API. LMK if you have any output examples about the call hierarchy
about the call of it, do you think (api/definition {:from 'my.ns/my-function})
is a good usage?
Could be, yes, I wonder why the wrapper instead of e.g. (api/definition 'my.ns/my-function)
oh, all clojure-lsp api functions can receive extra things like setting or project-root, receive a map is easier to support and avoid breaking changes
ok, I created my graph use-case on paper, and I'll write it here now. It's not directly about graph hierarchy, but it is about exposing the right tools so that the user can do the kind of analysis I'm describing
(defn foo []
(let [a (bar)]
a))
(defn quux [z]
(let [b (foo)
c (zorg1 b)
d (zorg2 z)]
(baz c d)))
consider this setup ^. Now suppose that I'm doing a refactoring, and I have to change the internals of foo
. I want to "follow the changes" to see which other parts of the code I should amend. Now, if we do a call graph, we see that quux
calls foo
, zorg1
, zorg2
and baz
, but crucially, if I modify foo
, I would only need to amend zorg1
and baz
, while zorg2
can be left alone
essentially because the flow of the changes never impact what zorg2
was doing. Now, in this contrived example it seems that we're gaining a little, but in an actual codebase proportionally only a few places have to actually be changed.
Ideally I would want the api to expose enough info to make this kind of reasoning possible, even when, strictly speaking, it falls outside the scope of a call hierarchy. But I wouldn't know what's the right balance. What do you think? Do you see the appeal of the kind of analysis I'm suggesting?
The answer I would want in that case, is "the dataflow is foo -> zorg1 -> baz
(in this example it's not branched but in the general case it's a graph)
Yes, I understand how convenient that would be, but not simple for static analysis, this is something that start to touch the runtime analysis, not sure there is a data structure using current kondo analysis that we could easily (and more importantly, safely) know that
yeah, I think clojure-lsp could present all call hierarchy like does on editor, nothing that much more than that
I agree that it's not in the scope of clojure-lsp to do the analysis I've described, my suggestion was that, if it proves to be easy, we could return, as the result of the "proper" call hierarchy, enough enrichment to be able to build other tools on top.
I would not want to go into run-time analysis, that's totally another set of problems that's better solved by other means ๐
> Why do you think the issue I'm describing would be unsafe? Thinking about that now, we would need to actually build the function and usage call hierarchy, not only var-definitions call-hierarchy, since we would need to check each local-usage and see if it's used on other places in that same function. I'm not saying it's not possible, but sounds harder Yes, I do think we could research and see if it's possible, I'd just not spend that much time as things tend to become complex when we want to offer things that are more easily available via runtime.
Oh I totally agree that just exposing the "proper" call-hierarchy is the correct first step. Moreover, the case I described would start with examining quux
as the proper parent of foo
. Maybe we could return all the information that clj-kondo
exposes about quux
, so that one is free to do its own analysis? Oh, I guess the new definition
is probably the place to include the detailed data, no?
So ideally a user would call the hierarchy function, discover that my.module/quux -> my.module/foo
and then call (api/definition 'my.module/quux)
to continue with the flow analysis
I think so, we actually have a command that does that, return the kondo analysis of the current point: lsp-clojure-cursor-info
I didn't know ๐ฎ. I see using that in emacs on a function call, I get back the file and position of the function definition. Does clj-kondo do more analysis of the body of the function?
Yes, it has the locals and local-usages which are the local vars, args and bindings
Yeah, I created that function for debugging purposes but I can see how it would be nice to have on API
I'll spend some time until next release thinking on those things to try to offer more features via API
I just realized (api/definition {:from 'my.ns/my-function})
doesn't make sense at all as you want usually a definition from a call or some var usage, so you don't have a proper symbol available
on the other hand, one could just go to definition
in the editor, and invoke the hierarchy analysis from there. What extra functionalities would we get calling from var usage?
In a ideal future, I'd like to offer most editors features in the API, so people could use it as a REPL dev dep instead of in your Editor as LSP
In case anyone wondered if clojure-lsp could already be used in Fleet, the new IntelliJ VSCode-ish thing: https://twitter.com/borkdude/status/1580189060991455232
Oh, that's sad, I was even interested on creating a plugin focused on LSP support or/and help in the clojure-sp integration
Yeah, I wonder how different will be from intellij, how easy will be to customize it
These things are hard to guess, but here's hoping that it will start seriously competing with VS Code! Big Tech are not good at behaving well when they get too dominant in an area. Fleet could make interesting bets that benefits VS Code users if the bets succeed (or fail).