Closed jaredramirez closed 5 years ago
Hi! First, thank you for this great writeup! :)
It seems like a lot of work to maintain a fork of of the Elm compiler.
Yes, that might be true in the future, I don't know that yet. However, our changes to the compiler are minimal as of now:
.cabal
file) to make it export all modules of the compiler as a library, so we can depend on it in this projecttryWithError
).compileModule
). But since this was more of a change compared to points 1 and 2, this change was just copied into the language server codebase.So our fork basically doesn't have any actual code changes, except for tryWithError
1. We do have forked code (3 functions) from the compiler in the language server itself.2
I think that it might get more complicated to adapt to compiler code changes in the future, because the more features the language server has, the more we'll need to interface with the compiler. But I think you overestimate how much work this actually is.
Additionally, it seems hard to eventually support both 0.19 and 0.20 down the line if this project uses a compiler fork
it seems to me that attempting to find the user installed version of Elm and getting diagnostics from that would be more effective
I think that ideally each elm compiler ships with a language server. It certainly won't be this implementation, but its goal was primarily to assess whether something like that would even be feasible and how beneficial sharing parts with the compiler is. I personally view this as more of an experiment than the official implementation. If you squint your eyes a little, you can see how the json-report interface is something similar to a language server already today.
It seems that collaborating on one project is more beneficial to the community though, which is why I'm writing this issue. If interested, this project can use that as a basis for the implementation.
As of now, to me it seems like we're in experimentation phase and just try out different approaches. Merging seems to me like premature abstraction :D
A little bit of a Sidenote: I think its important to understand the motivations for this project to understand my stance: There are many things that the elm compiler can already do, that would be extremely useful for an IDE:
Hint: Seems like a record field typo. Maybe pge should be page?
There is a datatype in the elm compiler that looks like this:
data Report =
Report
{ _title :: String
, _region :: R.Region
, _sgstns :: [String]
, _message :: D.Doc
}
The _sgstns
(suggestions) field is exactly the information we need! We hacked on this feature at Munihac this year and got it working. It currently lives in the code-actions
branch, waiting to get cleaned up a little.
By now the question "Why don't we implement these features using the json-report interface?" should be screaming in the back of one's mind. Obviously some of those features don't have the necessary interface yet, but might have in the future!
I think that, if one were to implement all those features into the json-report interface, we would end up with something that is close to as complete and difficult to maintain for different elm versions, as implementing the language server protocol for the respective features, or even something that is basically a re-implementation of it.
So I went on quite a tangent with this answer, but all in all: I didn't use the json interface for diagnostics, because I wanted to test using the datastructures directly and wanted to use even more datastructures directly in the future.
Footnote 1: You can take a look at the diff between our fork and the actual compiler code here: https://github.com/elm/compiler/compare/elm:a936e95...elm-tooling:5354f1f
Footnote 2: These functions live in the Language.Elm Module.
customCompile
is adapted, so it doesn't run code generation while compiling, but only type checking.compileModule
is adapted so it uses customCompile
is adapted from what the compiler executes on
elm make, so it uses our own
compileModule` and generates our own datastructures that capture the result of compilation, instead of writing compilation artifacts to disk (no .elmi/.elmo/index.html/elm.js files).Hey, thanks for the super detailed response!
You pretty much addresses all of my questions/concerns, and then some! I appreciate you taking the time to outline your thought process and motivations. I completely understand why your taking this approach. I'm super looking forward to seeing this project develop!
Thanks again for your time!
Hey, first off I'm psyched that this project is being worked on! I had a question (or comment) about how this project decided to report diagnostics. If my understanding is correct, it looks like this project uses a library version fork of the Elm compiler and uses that to type check the user's code. This is pretty cool, but I'm not sure that it's the best way to do this. My reasons for thinking this are
1) It seems like a lot of work to maintain a fork of of the Elm compiler. This is especially true if there ends up being something like an
0.19.1
to address a bug that is being discussed here. Additionally, it seems hard to eventually support both 0.19 and 0.20 down the line if this project uses a compiler fork.2) Elm includes a flag to get these syntax and type errors. If one runs
elm make src/Main.elm
, and the error something likethen one can run
elm make src/Main.elm --report=json
and the output will beThen, one only has to parse the json to get the error and report it back to the user.
Because of the challenges of maintaining a fork and the fact the you can get compile errors from
elm make
, it seems to me that attempting to find the user installed version of Elm and getting diagnostics from that would be more effective. Other benefits of this approach are1) The language server could prefer local installations. If a user used 0.19 in one project and 0.20 installed in another (both installed in maybe
node_modules
), then the language server could report errors seamlessly in both. Additionally, it can always fallback to looking at a global installation.2) This project only has to maintain a fork of the elm parser, which is simpler than maintaining a fork of the compiler. I think it's fair to say that generally speaking the elm syntax doesn't change drastically between releases, so maintain a fork of just the compiler may end up being more straightforward.
I would also like to point out that this seems to be the approach taken by [elm-format] (https://github.com/avh4/elm-format), though their goal/use case is somewhat different.
And lastly, I have been working on my own implementation of an elm language server, and the approach I've outlined in this issue has worked well so far. It seems that collaborating on one project is more beneficial to the community though, which is why I'm writing this issue. If interested, this project can use that as a basis for the implementation.
Please let me know your thoughts on this, it's super possible that there are reasons for keeping a fork of the compiler that I haven't thought of! And I'm super down to work on this refactor if it's decided that this is the way to go.