Programmatically generated Rust type definitions for the Language Server Protocol.
All types are generated by the LSP Metamodel, and will be up-to-date on the latest LSP changes.
* If you notice that this is not the case, please file an issue!
Every type implements serde's Serialize and Deserialize traits adhering to
the protocol, as well as Debug, Clone, and PartialEq. Additionally, the
generator will derive all of the following traits on every enum/struct that
supports them:
CopyDefaultEqHash
Special types Position and Range also derive Ord and PartialOrd, and
string enumerations derive From<String> and Display.
All structures generate ::new() constructors for convenience. For the same
reason, string enumerations supporting custom values will also provide ::new()
constructors, taking a &'static str.
All "or" types in the spec (e.g. bar: string | integer | null) are represented
as untagged enums, with intuitive naming based on the context that the "or"
type is defined in. Every "or" type enum implements From so it can be
seamlessly converted from its member types. E.g., for the above example, you can
do:
// This...
let bar: Bar = 123.into();
// ...or this...
let bar: Bar = String::from("baz").into();
// ...or this.
let bar: Bar = ().into();Unlike the original lsp-types
crate, this one is able to encode properties as null or undefined (not
present). This is important because the spec does differentiate the two from
each other.
For example, for the following property which can be null or undefined:
interface InitializeParams extends WorkDoneProgressParams {
// ...
/**
* The workspace folders configured in the client when the server starts.
* This property is only available if the client supports workspace folders.
* It can be `null` if the client supports workspace folders but none are
* configured.
*
* @since 3.6.0
*/
workspaceFolders?: WorkspaceFolder[] | null;
}The generated Rust struct will be:
pub struct InitializeParams {
// ...
/// The workspace folders configured in the client when the server starts.
///
/// This property is only available if the client supports workspace folders.
/// It can be `null` if the client supports workspace folders but none are
/// configured.
///
/// @since 3.6.0
#[serde(default, deserialize_with = "deserialize_some")]
#[serde(skip_serializing_if = "Option::is_none")]
pub workspace_folders: Option<WorkspaceFolders>,
}...where WorkspaceFolders is an enum:
pub enum WorkspaceFolders {
WorkspaceFolderList(Vec<WorkspaceFolder>),
#[serde(rename = "null")]
Null,
}So undefined is represented as workspace_folders = None, and null is
represented as workspace_folders = Some(WorkspaceFolders::Null).
Note
If a property can only be one of undefined or null, not both, None will
be used in both cases to denote those values, for convenience.
Structures with string literal properties will have those properties omitted
from their generated Rust types. E.g., for the following DeleteFile
definition:
/**
* Delete file operation
*/
export interface DeleteFile {
/**
* This is a delete operation.
*/
kind: 'delete';
/**
* The file to delete.
*/
uri: DocumentUri;
/**
* Delete options.
*/
options?: DeleteFileOptions;
/**
* An optional annotation identifier describing the operation.
*
* @since 3.16.0
*/
annotationId?: ChangeAnnotationIdentifier;
}The generated Rust struct looks like the following:
/// Delete file operation
pub struct DeleteFile {
/// The file to delete.
pub uri: Uri,
/// Delete options.
#[serde(skip_serializing_if = "Option::is_none")]
pub options: Option<DeleteFileOptions>,
/// An optional annotation identifier describing the operation.
///
/// @since 3.16.0
#[serde(skip_serializing_if = "Option::is_none")]
pub annotation_id: Option<ChangeAnnotationIdentifier>,
}Note the kind property is not present. However, when serializing, it will
always be present with a value of "delete". Deserializing only succeeds when
the field is present and has a "delete" value.
lsp-types controversially
switched to fluent-uri
for better spec correctness, at the cost of decreased interoperability and
poorer DX. Previously, the url crate was used, which is significantly more
battle-tested, but isn't spec-compliant in all cases.
This library deliberately puts the URI encoding decision in the hands of the
downstream consumer. Developers migrating from the original lsp-types crate
will notice that the URI type is just a newtype wrapper over a String,
allowing them to internally represent URIs however they wish.
This crate also uses feature flags to allow downstream consumers to tell it to
prefer a specific URI representation. The url feature instructs the library to
deserialize URIs as url::Url (matching lsp-types <=0.95.0), and the
fluent-uri feature instructs it to deserialize them as fluent_uri::Uri. Note
that the two features are mutually exclusive, and by default just the String
wrapper will be used.
Changes that are backwards compatible from a protocol perspective (e.g.
foo: integer | string -> foo: integer | string | boolean) are still breaking
from the point of view of this library. In the above example, an extra enum
variant would be added to the Foo type, which is a breaking change. Thus the
library will be perpetually kept at zerover versioning,
like the original lsp-types crate.