-
Notifications
You must be signed in to change notification settings - Fork 68
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
Add Separate Export for LSP Services #1258
Conversation
We need to eliminate the internal dependencies to the lsp subfolder. This is only possible by splitting |
76f4875
to
d04fdf8
Compare
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.
Thanks for this first spike!
I'm thinking about a different approach to structure the services and modules:
- Introduce
LangiumCoreServices
andLangiumLspServices
for the split, incl. respective shared services and default modules - Keep
LangiumServices
andLangiumSharedServices
intact, i.e. the union of core and LSP (implying that these need to be defined in thelsp
subfolder)
Rationale:
- Reduce the impact of the change in terms of breaking existing code (just change the import)
- Splitting core and LSP services is not something that many users will do, but rather a special feature for those using Langium as a library in the browser
- We should keep things simple for the most common case, but make the more special cases possible
@msujew WDYT?
@spoenemann I'm on board with the core vs. lsp services 👍 . I was also wondering if we wanted to do something with an explicit 'core' set of services, I like that. In addition retaining the structure of |
Also renamed the |
eb4810a
to
5950b8e
Compare
Just a note, there's a single test failure after the last rebase on top of the new
Several other 'langium' imports in the domainmodel example seem to have a similar issue, but strangely not others like requirements or statemachine, which look like they should trigger the same issue. The plan is to keep looking into this more next week to resolve. |
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.
Very good progress @montymxb!
I have a few detail remarks/wishes and one major thing: The workspace initialization should not got into the LSP related part.
I think special attention need to be paid to the stuff in promise-util.ts
that need to be separated, too, doesn't it?
84101a4
to
7de1f83
Compare
CI looks good sans lint. Local linting & gitpod linting looks good despite this, so this action triggered lint is still outstanding 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.
Great, you've made good progress on this. We needsome better abstraction layers for some of these services, but otherwise this looks quite good.
Thanks for the feedback @msujew . I'm catching up on some things right now, and then should be coming back to reply & update in a day or two. |
a2f66ee
to
09e88e3
Compare
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.
Seeing the amount of additional complexity that is necessary to separate LSP from Core, I am no longer convinced that the benefits of the separation justify its costs.
What's the use case for the separation? Using Langium in a browser app to parse and process text (without editor support), with a minimal bundle size. That's a rather specific case.
Can we offer an alternative solution for that use case? For example, a recommended bundling configuration where imports from vscode-languageserver
are replaced by some mocks?
Let's discuss this in January when everyone's back from vacations.
Edit: I resolved my detail comments below – there's no need to address them before we clarify how to proceed in general.
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.
Excellent work @montymxb!!
I have some remarks to simplify some things, and I agree with Miro, that the LSP services should expect LangiumServices
instead of LangiumCoreServices
, but in general I'm very in favor of this contribution!
packages/generator-langium/templates/core/src/language/language-id-module.ts
Outdated
Show resolved
Hide resolved
Thanks for the feedback @sailingKieler . Added some notes back to what you've mentioned. |
Hey @msujew, I added another commit contributing packages/langium/src/utils/cancellation.ts just containing I added it to Technically, the results will be of the same size as with copying the code. |
@msujew yes, this is very crucial for us at Mermaid. This is our current bundle breakdown. And this is the breakdown of our parser package. VSCode related packages make up around 1/3rd of the bundle. |
c6132de
to
15bc2ec
Compare
I did another refinement, now there's no I also double-checked on exporting I have one more commit in the pipeline replacing all type imports of |
@sidharthv96 Thanks for the info! Good to know that we're on the right track on this. |
Good question - no idea. I assume at the same time that vscode switches over to ESM, which might take a while. I think the new approach is just fine. |
Why was Or do I miss something? |
As you can see in https://github.com/eclipse-langium/langium/pull/1258/files#diff-9ef9cc03a159c7e21b4350faa99ddd28f97e4f27c934a51508e14531e4f4987bL49-L58 the |
Are there any migration docs in the works, that I can refer to and try to make changes in our parser? |
@sidharthv96 the changes of this will mainly require you to update/refactor In addition, to take advantage of this restructuring, you have to rework the preparations in your langium config module, precisely replace the calls of However, the changes of #1320 will most likely induce more manual migration effort. |
15bc2ec
to
2137ca4
Compare
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.
This is now in a really good shape, good work! 💪
The poll results don't suggest that this effort is needed: at the time of writing, none of the 26 participants selected "Parsing only". However, we have statements from @sidharthv96 (#1258 (comment)) and @jindong-zhannng (#1346 (comment)) confirming that there are at least some applications where bundle size is crucial. I see this as a sufficient sign that we can proceed, provided that the changes are not too disruptive for other users.
I think we found good solutions to avoid raising the overall complexity for "normal" Langium users. We still need to write a migration guide, but in most cases it's just about updating imports (which is necessary for other v3 changes, too).
@sailingKieler please have a look at my questions and remarks below. In addition, I found imports from 'vscode-languageserver'
in the following source files, which should be changed to type
imports from 'vscode-languageserver-types'
:
- ast-utils.ts
- cst-utils.ts
- jsdoc.ts
2137ca4
to
532b64c
Compare
…cuments.ts for convenience * the overhead is just very few kilobytes * changed all imports of 'TextDocument' to point to langium
…jsonrpc/lib/common/cancellation.js';"; updated related imports aims at providing cancellation related types and symbols with smallest possible overhead while avoiding code clones
…dded linting rule preventing imports from 'vscode-jsonrpc'
532b64c
to
4f6c951
Compare
* Everything else of that package (at the time contributing) is also defined | ||
* in 'vscode-languageserver-protocol' or 'vscode-languageserver-types'. | ||
*/ | ||
export { TextDocument } from 'vscode-languageserver-textdocument'; |
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 now limited the re-export of vscode-languageserver-textdocument
to TextDocument
, as duplicate definitions are accessible via import ... from 'vscode-languageserver-protocol'
for all other definitions exported by vscode-languageserver-textdocument
.
…-languageserver-types' in langium's core modules (non-lsp, non-grammar)
4f6c951
to
64ab0b4
Compare
@@ -232,13 +233,13 @@ export function getDiagnosticRange<N extends AstNode>(info: DiagnosticInfo<N, st | |||
export function toDiagnosticSeverity(severity: 'error' | 'warning' | 'info' | 'hint'): DiagnosticSeverity { | |||
switch (severity) { | |||
case 'error': | |||
return DiagnosticSeverity.Error; | |||
return 1; // according to vscode-languageserver-types/lib/esm/main.js#DiagnosticSeverity.Error |
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 now replaced the constants like DiagnosticSeverity.Information
from vscode-languageserver-types
by their values, and left an info on their original definition.
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.
Not a big fan of this - users that don't want to include vscode-languageserver-types
in their build, are now only allowed to use the numbers themselves (or have to redeclare the enum themselves). We should offer the enum ourselves.
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.
Actually this peace of code is only used to convert the Langium notion of severity
being defined as 'error' | 'warning' | 'info' | 'hint'
into the LSP notion while composing LSP diagnostics, right?
Our code is just converting the values according to the protocol definition, and therefore I don't see why Langium should export copies of those definitions.
Do you have concrete use cases in mind? Why should users care about those constants?
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.
Ah, right I forgot. Alright, that's fine then 👍
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 ship it! 🚀
export interface InitializableService { | ||
initialize(params: InitializeParams): void | ||
initialized(params: InitializedParams): MaybePromise<void> | ||
} |
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.
Looking at this again, I'd rather remove this interface: we already have onInitialize
and onInitialized
events in the LanguageServer service, which are the recommended ways to hook into the LSP lifecycle. The interface is only used by two core framework classes which require to invert the dependency. The interface is not necessary because LanguageServer hard-codes the calls to these classes anyway.
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.
Hi there, thanks for your work!
I'm currently facing an issue regarding the ServiceRegistry#getServices
, see the comment below.
|
||
/** | ||
* Retrieve the language-specific services for the given URI. In case only one language is | ||
* registered, it may be used regardless of the URI format. | ||
*/ | ||
getServices(uri: URI): LangiumServices; | ||
getServices(uri: URI): LangiumCoreServices; |
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.
How can I access the LSP services if this method only returns LangiumCoreServices
?
I'm currently trying to run two language servers in the same document, one of which is the Langium language server and the other not.
The Langium language server is the default one, and if the user typed some specific text, it would use the other language server suggestions.
Anyway, the approach I'm taking is to create two modes; according to mode, the language server would use either the language server or the other language server methods to suggest, but now I can't use the language server since I can't directly access the LSP services.
Here is an example:
export class LangiumMode implements LanguageMode {
private getServices({ uri }: TextDocument): LangiumServices /* error in 3.0.0 */ {
return this.shared.ServiceRegistry.getServices(URI.parse(uri));
}
public doComplete(
document: TextDocument,
params: CompletionParams,
cancelToken?: CancellationToken | undefined,
): MaybePromise<CompletionList | undefined> {
return this.getServices(document).lsp.CompletionProvider?.getCompletion(
this.textDocumentToLangiumDocument(document),
params,
cancelToken,
);
}
// ...
}
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.
for me it worked to downcast
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.
@Yokozuna59 A quick answer: Look #1166 (comment) and below.
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 see, thanks @cdietrich @sailingKieler.
Closes #1166 by providing a separate
langium/lsp
export for LSP-related services for Langium.Note, this is a breaking change planned for introduction later in v3.0.0.
Changes (not exhaustive):
LangiumServicesWithLSP
andLangiumSharedServicesWithLSP
to make it pretty clear how to extend existing applications with the new type signaturesOpen for refactors and changes based on feedback, and can go from there.
createServicesForGrammarWithLSP
is marked with a TODO that is a effectively an RFC. Looking for feedback to see if I should generalize the approach a bit more to work withcreateServicesForGrammar
, or leave it as is.