Migrate to monaco editor - #70
Conversation
|
Do you think it might be relevant to have a package for Monaco, and a second once for CodeMirror, and let the user pick the one they want? |
…guage server - `Yasqe` now extends `EventEmitter` instead of `CodeMirror` - Use a wasm language server for diagnostics, syntax highlight, autocompletion, code actions, etc - In the `dev/index.html` implement a demo using the Qlue-LS language server - Delete code in yasqe related to built-in autocomplete and grammar (since this now handled by the language server)
…ints to default list of endpoints, add space between iri and label in completion suggestions, enable to configure the light/dark theme for monaco editor
… qlue-ls language server, documentation to use yasgui defined in markdown files at /docs
…s fine, now ESM imports are supported in plain HTML file `<script>` tags), because monaco-editor only works in ESM
…azuko/yasgui/style.css`, fix issue with wasm bundling in prod
… level to info in prod, fix raw response in dark theme
…ponse JSON from v5 to v6
…n classic mode - no textmate, VSCode extension host, oniguruma - Bundle size goes from 15MB to 11MB - disable large sourcemaps in packages build
…vitepress index footer more visible
…blp.org/sparql - dblp is much faster for completion queries, and contain generic qualitative data about publications - improve yasr plugins docs - comment out skipped tests for clarity
4e14f4e to
3956efb
Compare
…refixes.json file
Note that for each language server we will need a connector to each editor (right now just 2x2), with maybe some caveats to overcome and wrapping to do. Then users will be coming with issues for the combination of editors X language servers We will need to make sure Yasqe monaco and CodeMirror surface the same API to Yasgui (which might limit us) So possible but some additional work, not sure if it is worth it. I would be down to go for it if there are request, but I suggest people first try the 2 versions in practice (monaco from my fork deployment, and local deployment of the codemirror branch) before deciding if it is worth to pursue I would say
|
…tepress website, add public endpoint URLs to the list
|
I'll give it a spin today, indeed the monaco version looks quite nice already! |
- allows arbitrarily nested partials (previous implementation partiality was going 2 levels deep) - function signatures are preserved, dropping the `onLanguageClientReady` cast. - add `DeepPartial`/`DeepReadonly` into `yasgui-utils`, drop `ts-essentials` dependency
…s/functions for various language servers - enable to provide sane defaults and make configuring the language servers easier without adding dependencies - added `languageServers/qlueLs.ts` with helpers for the qlue-ls language server - updated `dev/` and vitepress deployments to use these helpers
…f the footer instead of floating top right
|
I have added a We can try it there: https://vemonet.github.io/Yasgui/codemirror It is indeed faster to load (almost instant with codemirror for me) I moved a lot of Yasqe to the The LS-CodeMirror connector is a bit verbose because:
There is still a lot to improve (especially regarding the language server implementation), but that works! I would like to see how would look a connector for swls with @ajuvercr, once we have this we can think more seriously about how we want to deal with these language servers |
|
It was really easy to add swls to this setup, and I'm quite impressed by your general approach @vemonet . I've added a single commit to migrate-to-monaco-editor-swls but please don't look at my worker code, I'm fixing this to be more in line with Qlue-ls as that is elegantly implemented.
|
- error messahe from LSP (e.g. completion timeout) are now shown in a notification popup on the bottom right of the editor - fix Yasr filters and search box display - use same color schema for codemirror and monaco semantic token highlighting - add button to switch editors in the editors pages in website
… docs and add titles to yasr rendering options
…r-endpoint preference Replace the single language server config with a `languageServers` array on both editors. The first entry activates on load; with two or more, a switcher lets the user pick one and Yasgui remembers the choice per endpoint - Each entry: `label`, `description`, connection field (`worker` for Monaco, `client` for CodeMirror, resolved lazily), plus per-server `onReady` and `onEndpointChange` hooks that fire only for the active server. `configSchema`/ `configCallback` are reserved for a future config UI (not yet implemented) - Switcher UI: Monaco right-click context-menu actions; CodeMirror dropdown button (label + dimmed description) in the toolbar - Editor API: `getLanguageServers`, `getActiveLanguageServerIndex`, `setLanguageServer` (serialized so init + restore don't race), `getLanguageClient`, `notifyEndpointChange`, and a `languageServerChange` event; all added to `IYasqe` - Yasgui persists `languageServerByEndpoint` and applies it on endpoint change, firing the active server `onEndpointChange`
|
It could be interesting to enable to have multiple language servers made available to the user to choose from directly in the UI. We let the user switch language server at the click of a button in Yasqe, this way they can use the best language server for each endpoint. Then we store language servers preference per endpoint Typically qlue-ls completion works well for Qlever endpoints, but can be a bit unstable on large virtuoso like dbpedia. In this case the user can use swls So instead of just passing 1 language server, consumer pass a list of language servers Then we need also to think of a nice way to get a configuration UI for the language servers directly from Yasgui (ideally, without requiring each deployment to setup config panels for each LS). We could use a generic form that takes a JSON-schema describing the language server config to render the config UI, and have a callback that enables to deal with the generated JSON config file (to apply it to the LS). Would need to see how swls does settings, to find the right approach I have implemented the array of language servers in this PR, sorry @ajuvercr there will be a little change to do, but the previous worker should work as it was, you just need to provide it in a list of objects, with per server onReady and onEndpointChange hooks, e.g. (do it directly in const yasqe = new Yasqe(el, { ...conf, languageServers: [
{
label: "swls",
description: "Ontology-based completions",
worker: createSwlsWorker,
onReady: (client: any) => {
swls.configureSettings(client, settings);
swls.configureBackend(client, yasgui?.getTab()?.getEndpoint() ?? DEMO_ENDPOINT);
},
onEndpointChange: (client: any, endpoint: string) => qlueLs.configureBackend(client, endpoint),
},
]})If only 1 language servers it will just be used, no way to change it. If 2+ you get a dropdown list, and language server preference stored per endpoint. A question I have is: how should we present the menu to switch language server in monaco editor?
|
|
For reference, @ajuvercr implemented a prototype for adding @jitsedesmet's Traqula using this LSP architecture: https://github.com/ajuvercr/Yasgui/blob/migrate-to-monaco-editor-traqula/dev/traqula.worker.ts |
Co-authored-by: ajuvercr <29926645+ajuvercr@users.noreply.github.com>
… with a callback to enable applying those settings to different language servers
- fix diagnostics and syntax highlight for swls - upgrade qlue-ls to 2.8.2 which supports rangeless edits
…ic tokens provided by language server
…arql-studio|sparql-editor-monaco|sparql-results - Rename packages - Update references in the docs - update logo to use svg, similar logo but without the YAS gui text
- make more changes related to yasgui -> sparql-studio name change - add ? button on each editor demo page - add diagnostic gutter to monaco - in monaco move share URL button to right click menu, and available through shortcut cmd/ctrl+s
…s from yasqe/yasr.html to editor/results.html
|
I merged in @ajuvercr implementations for swls and traqula, thanks a lot!
Regarding the renaming a few questions are left:
|
|
Very nice @vemonet! So do I understand correctly that the deployment on https://sparql.studio/ has all 3 language servers enabled by default?
I would not keep the yasgui classes.
I would also use a new name for this. |
yes, qlue-ls and traqula supports 1.2 queries, swls I don't know
Doing this would mean a lot of changes in the current styling approach, making it more complex (from my experience css-in-js can be messy). To be fair I am saying that will "break compatibility", but that's not going to be that dramatic For studio and editor, that will not change much. Just that people who already deployed yasgui and customized CSS using For results, that might create styling issues if some external plugins we use are styling stuff using Some we might as well just make the move and add fixes later if really needed |
…/sparqlResults - Rename `window.yasgui` & cie to `window.sparqlStudio` - Rename CSS classes (`.yasgui* -> `.sparqlStudio*`) - add `postcss-nested` to flatten nested CSS - Merge the editor.html and results.html dev pages in a "Editor & Results" page (`editor_results.html`)

Description
I looked into building an LSP-independent editor, which means a lot of breaking changes to the API: instead of just having Yasqe as object to configure everything related to language checks (lint/formatting/diagnostics, completion), we will now have Yasqe that will just handle display, and the LSP (external dependency) will handle the language checks, and will be passed to Yasqe
Important
Tl;dr: Monaco editor is better with LSP than CodeMirror 6 and look nicer, but larger bundle (~11MB vs 1.2MB, still loads fast in production for me though)
Monaco editor with the qlue-ls language server is deployed on my fork: https://vemonet.github.io/Yasgui
@ajuvercr would you be interested to help with implementing Yasgui with swls? I have created a
swls.htmlindev/to test it. We can have a call to check this togetherMigration to CodeMirror 6
I checked migrating to CodeMirror v6 with language servers, I have a prototype working with qlue-ls here, and most features available (diagnostics, code actions, completion, syntax highlight, format): https://github.com/rdfjs/Yasgui/tree/migrate-to-codemirror6
npm i && npm run devThe official CodeMirror LSP-client is missing a few features (released really recently in summer 2025), such as no support for semantic tokens highlight, no support for pull notifications (which qlue-ls is using), so we need to reimplement these on top of the codemirror lsp-client for each LS: https://github.com/rdfjs/Yasgui/blob/migrate-to-codemirror6/dev/qlueLs.ts
Migration to the Monaco editor
In term of looks and feels CodeMirror 6 is decent, but I still prefer Monaco/VSCode. Monaco has custom ctrl+f search, and custom right click menu built-in
The limitations we are hitting with
@codemirror/lsp-clientare absent from the Monaco editor, we have full LSP support out of the box (with qlue-ls at least) without having to do to much middleware. Which makes sense because afaik the LSP came with VSCode (microsoft development)I managed to configure vite to properly package the Monaco wasm workers. Fully replaced the CodeMirror in Yasqe by Monaco editor (configurable, with sane defaults), it is language server agnostic, the LS needs to be passed at Yasgui/Yasqe creation.
If the language server provides semantic highlight then it will be used. If no language server is provided, syntax highlighting will still work, but no diagnostics or completion.
I deployed it on my fork to make the whole thing was properly working:
The dark part is that to get the Monaco wasm workers resolved properly in Yasqe/Yasgui nested packages we need to inline all workers in the file, resulting in a final yasgui.js of 11MB (instead of 1.2MB previously with codemirror), 2.7MB gzipped, without the Language server (add a few MBs more, but separated, so less impactful)
For Yasgui deployer UX, in the future we might want to consider having packages with a preloaded/preconfigured language server for convenience, e.g.
@rdfjs/sparql-studio-qluelsand@rdfjs/sparql-studio-swlsFor now, I focused on implementing using the qlue-ls language server, but it would be interesting if @ajuvercr can add the equivalent needed to use swls (
swls.html+swls.tsindev/folder)This way we better understand the final API we need to support different language servers
Conclusion
If we want to go down the language server road, then I think it would be better to go with Monaco editor over CodeMirror:
The main drawback is a large bundle size (11MB vs 1.2MB), but that can be improved, and does not seems that impactful
There is also value in taking different approaches. Matdata fork currently still uses CodeMirror 5, and I think he is more interested in CodeMirror 6 than Monaco. If people wants to use a maintained CodeMirror based Yasgui editor, they can use the
@matdata/Yasguipackage, and we cover the Monaco crowdAdding a configurable LSP will anyway increase complexity for final user who deploy Yasgui. But we can’t make an omelet without breaking eggs, a more capable system often brings some complexity, especially if we can to keep modularity. And anyway deployment complexity is mitigated by coding agents that can easily wire the different components for the devs using Yasgui
@ludovicm67 @rubensworks @ktk
Changes
Yasqenow extendsEventEmitterinstead ofCodeMirrordev/index.htmlimplement a demo using the Qlue-LS language server/docs@zazuko/yasguiand@zazuko/yasgui/style.cssChecklist
npx changeset add) if this change warrants a release