sysml-lsp speaks the Language Server Protocol, plus the methods on this
page. They are not part of the protocol, so a client must ask for them by name,
and the server announces that it serves them by advertising, in the initialize
result:
{ "capabilities": { "experimental": {
"openSysmlRender": true, "openSysmlRenderDocument": true, "openSysmlStdlibContent": true } } }openSysmlRender covers the view-rendering methods, openSysmlRenderDocument
the document-rendering ones, and openSysmlStdlibContent the request that serves
the bundled standard library's text.
A client that does not see that capability must not send these methods. That is how a new client and an older server stay compatible.
Everything here is read-only: it renders what a document says and never writes
to it. The renderings are the same ones %view and sysml -view
produce, from the same renderer.
Whether the server judges a document as conforming SysML v2 (reporting notation
only OpenSysML accepts as an error instead of a warning) is controlled by a boolean
setting, strictConformance. It is read from initialize's initializationOptions
and from workspace/didChangeConfiguration, in any of the three shapes clients
nest settings in:
{ "strictConformance": true }
{ "sysml": { "strictConformance": true } }
{ "sysml.strictConformance": true }A payload that does not mention it leaves the mode alone, and a value that is not
a boolean is ignored rather than read as either answer. Changing it republishes
the diagnostics of every open document, so the editor never keeps the other
mode's verdict. A client that cannot send settings can start the server with
-strict instead. Both correspond to the CLI's -strict and the REPL's %strict;
the guide explains what the mode
changes.
Renders one view of a document.
{
"textDocument": { "uri": "file:///tmp/kit.sysml" },
"view": "KitViews::widgetTree",
"form": "mermaid"
}| Field | Meaning |
|---|---|
textDocument.uri |
The document to render. It must be one the session holds — an open document, or a workspace file the server read. |
view |
The qualified name of a view the document declares, a pseudo-view (below), or omitted. |
form |
mermaid, text or markdown. Omitted writes the machine form of the rendering's kind: markdown for a table, mermaid for every other kind. |
Omitting view renders the view the document declares. If the document declares
several, the request is ambiguous and fails, naming them
(declares 6 views (KitViews::widgetActions, …); name the one to render) rather
than picking one. If it declares none, the request fails and points at the pseudo-views.
A form the rendering kind cannot be written in (Mermaid for a table, Markdown for a
diagram) is refused, and the reply names the form the kind does use. A form that is
not one of the three is refused, and the reply names all three.
Pseudo-views. A document that is still being written usually declares no view,
so a rendering can be requested as if one had been declared:
view |
Renders |
|---|---|
#tree |
Everything the document declares, as a tree |
#interconnection |
…as an interconnection diagram |
#state |
…as a state diagram |
#action |
…as an action flow |
#sequence |
…as a message sequence |
#table |
…as an element table |
#state:Kit::WidgetStates |
One element the document declares, here as a state diagram |
A pseudo-view adds nothing to the model and nothing to the symbol index: the
exposed set is passed to the renderer directly, and the result says so in
stated, as no view declared; rendering Kit::WidgetStates directly.
The result, for {"view": "KitViews::widgetTree"} over a document declaring
part def Widget { part cog : Cog; part gear : Cog; connect cog to gear; }:
{
"view": "KitViews::widgetTree",
"kind": "tree",
"stated": "",
"form": "mermaid",
"artifact": "%% KitViews::widgetTree — tree rendering\nflowchart TD\n n0[\"part def Kit::Widget\"]\n n1[\"part cog (Cog)\"]\n n0 --- n1\n …",
"nodes": [
{
"id": "n0",
"kind": "part def",
"name": "Kit::Widget",
"detail": "",
"origin": {
"uri": "file:///tmp/kit.sysml",
"range": { "start": { "line": 1, "character": 1 }, "end": { "line": 6, "character": 1 } },
"selectionRange": { "start": { "line": 1, "character": 10 }, "end": { "line": 1, "character": 16 } }
}
},
{
"id": "n1",
"kind": "part",
"name": "cog",
"detail": "Cog",
"parent": "n0",
"origin": { "uri": "file:///tmp/kit.sysml", "range": { "…": "…" } }
}
],
"edges": [{ "from": "n0", "to": "n1", "label": "", "kind": "connection" }],
"notices": [],
"version": 7
}| Field | Meaning |
|---|---|
view |
The view rendered, by qualified name; empty for a pseudo-view. |
kind |
tree, interconnection, state, action, sequence or table. |
stated |
How the kind was decided — the rendering the view names, the standard view definition it specializes, or that no view was declared. Empty when the view took the default. |
artifact |
What to draw or show: a Mermaid diagram, the text form, or a Markdown table. |
nodes, edges |
What the artifact is made of, so a client can map a click on it back to the source. A node's parent is the node containing it, when one does. An edge's kind is connection, transition, succession or flow. |
rows, columns |
A table rendering's cells, in place of nodes and edges. |
origin |
Where the element was declared, as a document URI, the range of the whole declaration and, when the declaration names one, the selectionRange of the identifier alone. A client highlights the element whose range holds the cursor and navigates to its selectionRange, as textDocument/definition does. Absent for an element with no locatable declaration: a standard library symbol the index served from its cache, or a step a lowering sequenced without a declaration of its own, carries none rather than a bogus range. |
notices |
What the rendering could not represent, as the text form reports it. |
version |
The version of the document the rendering was made from, so a client can tell a rendering of the text it is showing from a stale one. |
A view that asks for a rendering this implementation does not produce (geometry,
textual) fails with the reason, e.g.
KitViews::widgetGeometry: geometry rendering (view def GeometryView) is not supported.
Lists the views a document declares, which is what fills a diagram panel's view picker.
{ "textDocument": { "uri": "file:///tmp/kit.sysml" } }{
"views": [
{ "name": "KitViews::widgetParts", "kind": "interconnection", "supported": true },
{ "name": "KitViews::widgetSequence", "kind": "sequence", "supported": true },
{
"name": "KitViews::widgetGeometry",
"kind": "geometry",
"supported": false,
"reason": "KitViews::widgetGeometry: geometry rendering (view def GeometryView) is not supported"
}
],
"pseudoViews": ["#action", "#interconnection", "#sequence", "#state", "#table", "#tree"]
}Views are listed in qualified-name order. An unsupported one stays in the listing,
with supported: false and the reason, so a client can say why it cannot be
drawn instead of hiding it. pseudoViews lists the supported #<kind> specs
in sorted order; a client can use it to offer pseudo-views without duplicating
the server's list of supported kinds.
Lists the document definitions the workspace holds (the part defs
specializing DocumentQueries::Document), which is what fills a Render
Document command's picker. It takes no parameters.
{
"documents": [
{ "name": "Observatory::MassReport", "uri": "file:///tmp/observatory.sysml" }
]
}Documents are listed in qualified-name order; uri is the file that declares each
one. Standard-library documents are not listed: the listing covers what the
workspace's own files declare.
Renders one document definition to Markdown: the document is compiled to a plan,
its queries are executed against the workspace model, and the result is written
the way the REPL's %render-document and sysml -render-document write it. It is
the same pipeline, run against the same workspace the diagnostics are computed from.
{ "name": "Observatory::MassReport" }{ "name": "Observatory::MassReport", "markdown": "# Telescope Mass Report\n…" }name is the qualified name of a document definition, as opensysml/documents
lists it. If the name resolves to nothing, names an element that is not a
document, or names a document whose planning or query execution fails, the
request fails with the typed error's message (for example Observatory::Subsystem is not a document: one is a part def specializing DocumentQueries::Document)
rather than crashing or answering with partial output.
The server bundles the standard library, so a definition, reference, hover or
rendering origin may land in a library file no client has on disk. Such a
location is reported under the sysml-stdlib scheme, whose path is the file's
path within the library, percent-encoded:
{ "uri": "sysml-stdlib:///Kernel%20Libraries/Kernel%20Data%20Type%20Library/ScalarValues.kerml",
"range": { "start": { "line": 19, "character": 1 }, "end": { "line": 20, "character": 1 } } }That is where ScalarValues.kerml declares datatype Integer specializes Rational;.
Positions are in UTF-16 code units of the bundled text, as they are for workspace files. This request serves that text, so a client can show the location:
{ "uri": "sysml-stdlib:///Kernel%20Libraries/Kernel%20Data%20Type%20Library/ScalarValues.kerml" }{ "text": "standard library package ScalarValues {\n\tdoc\n\t/*\n…" }A URI of another scheme, or one naming no library file, fails with an
invalid-params error. A client that opens the document may then send it the
ordinary requests — hover, definition, references, document symbols, semantic
tokens — against the sysml-stdlib: URI; the server answers from the bundled
text, so navigation continues from one library file into another. References
list the workspace's uses of a library element and, with the declaration asked
for, its library declaration; uses inside the library itself are not enumerated.
textDocument/didOpen and didClose for such a URI are accepted and change
nothing: the text a client sends is ignored in favour of the bundled one, and
closing removes nothing from the library. textDocument/didChange is refused
with an invalid-request error — reported to the user through window/showMessage
as well — and is never applied: the library is read-only.
The VS Code extension registers a content provider for the scheme that calls this
request, so Ctrl+click on a library name opens the file in a read-only
editor. Another client needs the same: a provider for sysml-stdlib documents
that fetches their text with opensysml/stdlibContent.
{ "textDocument": { "uri": "file:///tmp/kit.sysml" }, "version": 8 }Sent after the analysis that publishes the document's diagnostics, so a client sees the diagnostics of a version before the notification for it. It is debounced on the same window the cross-document diagnostics sweep uses, so a burst of keystrokes costs one notification rather than one per keystroke.
It carries no rendering: the client responds with a fresh opensysml/render if it
is showing the document, and does nothing if it is not. This keeps a large
diagram off the wire for a panel nobody is looking at.
The protocol is JSON-RPC over stdio, so the methods can be driven without an
editor: send initialize, then textDocument/didOpen, then:
→ opensysml/render { "textDocument": { "uri": "file:///tmp/kit.sysml" }, "view": "#tree" }
← { "view": "", "kind": "tree",
"stated": "no view declared; rendering /tmp/kit.sysml directly",
"form": "mermaid",
"artifact": "%% — tree rendering (no view declared; …)\nflowchart TD\n n0[\"part def Kit::Widget\"]\n…",
"nodes": [ … ], "edges": [ … ], "notices": [], "version": 1 }
The VS Code extension's diagram panel is the reference client; see the editors guide.