Skip to content

Commit

Permalink
xml.extension.jars to add LemMinX extension jars
Browse files Browse the repository at this point in the history
Adds a new setting `xml.extension.jars`, where you can list jars to contribute
to the LemMinX classpath. You can use this feature to test LemMinX
extensions in VSCode.

Closes redhat-developer#251

Signed-off-by: David Thompson <[email protected]>
  • Loading branch information
datho7561 authored and angelozerr committed Oct 9, 2020
1 parent b44ceb9 commit 4f002c9
Show file tree
Hide file tree
Showing 7 changed files with 67 additions and 42 deletions.
37 changes: 2 additions & 35 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,41 +93,8 @@ Since 0.13.0:

## Custom XML Extensions

The [LemMinX - XML Language Server](https://github.com/eclipse/lemminx) can be extended to support custom completion, hover, validation, rename, etc by using the [Java Service Provider Interface (SPI)](https://www.baeldung.com/java-spi) mechanism. vscode-xml provides the ability use your custom XML support provider, by adding external jars to the XML language server's classpath.

To do that:

* create a Java project which provides a custom XML extension providing your custom completion, hover, validation, rename, etc:
* create the XML extension like [MavenPlugin](https://github.com/angelozerr/lsp4xml-extensions-maven/blob/master/org.eclipse.lsp4xml.extensions.maven/src/main/java/org/eclipse/lsp4xml/extensions/maven/MavenPlugin.java).
* register your custom completion participant in the XML extension like [MavenCompletionParticipant](https://github.com/angelozerr/lsp4xml-extensions-maven/blob/master/org.eclipse.lsp4xml.extensions.maven/src/main/java/org/eclipse/lsp4xml/extensions/maven/MavenCompletionParticipant.java#L28)
* register your custom XML extension with [Java Service Provider Interface (SPI)](https://www.baeldung.com/java-spi) mechanism in the [/META-INF/services/org.eclipse.lemminx.services.extensions.IXMLExtension](https://github.com/angelozerr/lsp4xml-extensions-maven/blob/master/org.eclipse.lsp4xml.extensions.maven/src/main/resources/META-INF/services/org.eclipse.lsp4xml.services.extensions.IXMLExtension) file.
* build a JAR `your-custom-xml-extension.jar`.

* create a `vscode extension` which embeds the `your-custom-xml-extension.jar` JAR and declares this JAR path in the `package.json`:

```json
"contributes": {
"xml.javaExtensions": [
"./jar/your-custom-xml-extension.jar"
]
}
```

* You can also list multiple jars or use glob patterns to specify the jars:

```json
"contributes": {
"xml.javaExtensions": [
"./jar/dependencies/*.jar",
"./jar/my-xml-extension.jar"
]
}
```


You can see the [vscode-xml-maven](https://github.com/angelozerr/vscode-xml-maven) sample which registers custom maven completion [MavenCompletionParticipant](https://github.com/angelozerr/lsp4xml-extensions-maven/blob/master/org.eclipse.lsp4xml.extensions.maven/src/main/java/org/eclipse/lsp4xml/extensions/maven/MavenCompletionParticipant.java#L28) for scope:

![VScode XML Maven](images/vscode-xml-maven.gif)
The [LemMinX - XML Language Server](https://github.com/eclipse/lemminx) can be extended to support custom completion, hover, validation, rename, etc.
Please see the [extensions documentation](./docs/Extensions#custom-xml-extensions) for more information.

## Contributing

Expand Down
36 changes: 36 additions & 0 deletions docs/Extensions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Custom XML Extensions

The [LemMinX - XML Language Server](https://github.com/eclipse/lemminx) can be extended to support custom completion, hover, validation, rename, etc by using the [Java Service Provider Interface (SPI)](https://www.baeldung.com/java-spi) mechanism.
vscode-xml provides the ability to use your custom XML support provider, by adding external jars to the XML language server's classpath.

To do that:

* create a Java project which provides a custom XML extension providing your custom completion, hover, validation, rename, etc:
* create the XML extension like [MavenLemminxExtension](https://github.com/eclipse/lemminx-maven/blob/master/lemminx-maven/src/main/java/org/eclipse/lemminx/extensions/maven/MavenLemminxExtension.java).
* register your custom completion participant in the XML extension like [MavenCompletionParticipant](https://github.com/eclipse/lemminx-maven/blob/master/lemminx-maven/src/main/java/org/eclipse/lemminx/extensions/maven/MavenCompletionParticipant.java#L75)
* register your custom XML extension with [Java Service Provider Interface (SPI)](https://www.baeldung.com/java-spi) mechanism in the [/META-INF/services/org.eclipse.lemminx.services.extensions.IXMLExtension](https://github.com/eclipse/lemminx-maven/blob/master/lemminx-maven/src/main/resources/META-INF/services/org.eclipse.lemminx.services.extensions.IXMLExtension) file.
* build a JAR `your-custom-xml-extension.jar`.
* create a `vscode extension` which embeds the `your-custom-xml-extension.jar` JAR and declares this JAR path in the `package.json`:

```json
"contributes": {
"xml.javaExtensions": [
"./jar/your-custom-xml-extension.jar"
]
}
```

* You can also list multiple jars or use glob patterns to specify the jars:

```json
"contributes": {
"xml.javaExtensions": [
"./jar/dependencies/*.jar",
"./jar/my-xml-extension.jar"
]
}
```

You can see the [vscode-xml-maven](https://github.com/angelozerr/vscode-xml-maven) sample which registers custom maven completion [MavenCompletionParticipant](https://github.com/eclipse/lemminx-maven/blob/master/lemminx-maven/src/main/java/org/eclipse/lemminx/extensions/maven/MavenCompletionParticipant.java#L210) for scope:

![demo of vscode xml maven suggesting different scopes for a dependency](./images/vscode-xml-maven.gif)
13 changes: 13 additions & 0 deletions docs/Preferences.md
Original file line number Diff line number Diff line change
Expand Up @@ -161,3 +161,16 @@ The different options are:
Here is a demonstration of the effects of the setting on hovering. The above schema is used in the example:

![Changing the documentation type setting changes which text the hover shows when hovering over an element that is in a schema document](./images/Preferences/HoverDocumentationQuickDemo.gif)

## Extension JARs

The LemMinX XML Language Server can be extended with custom plugins to provide additional validation and assistance.
Typically this is done for specific files or contexts.
External extensions are are contributed via an external JAR.
Please see [the extension development documentation](https://github.com/eclipse/lemminx/blob/master/docs/LemMinX-Extensions.md) for more information on how this works.

JARs can be contributed to the LemMinX classpath using the `xml.extension.jars` preference.
These paths can include globs.
This feature is only intended to be used for LemMinX extension development purposes.
Distributing vscode-xml extensions is best done through the mechanism described in the
[vscode-xml extension development documentation](Extensions#custom-xml-extensions).
File renamed without changes
8 changes: 7 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,13 @@
"xml.symbols.showReferencedGrammars": {
"type": "boolean",
"default": true,
"markdownDescription": "Show referenced grammars in the Outline. Default is `true.",
"markdownDescription": "Show referenced grammars in the Outline. Default is `true`.",
"scope": "window"
},
"xml.extension.jars": {
"type": "array",
"default": [],
"markdownDescription": "An array of paths to JARs that should be contributed to the LemMinX classpath. The paths can include glob patterns. This is intended to be used as a tool for developing extensions to vscode-xml. Please see [here](command:xml.open.docs?%5B%7B%22page%22%3A%22Preferences%22%2C%22section%22%3A%22extension-jars%22%7D%5D) for more information",
"scope": "window"
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import * as path from 'path';
import * as os from 'os';
import { activateTagClosing, AutoCloseResult } from './tagClosing';
import { Commands } from './commands';
import { onConfigurationChange, subscribeJDKChangeConfiguration } from './settings';
import { getXMLConfiguration, onConfigurationChange, subscribeJDKChangeConfiguration } from './settings';
import { collectXmlJavaExtensions, onExtensionChange } from './plugin';
import { markdownPreviewProvider } from "./markdownPreviewProvider";

Expand Down Expand Up @@ -203,7 +203,7 @@ export function activate(context: ExtensionContext) {
}
}

let serverOptions = prepareExecutable(requirements, collectXmlJavaExtensions(extensions.all), context);
let serverOptions = prepareExecutable(requirements, collectXmlJavaExtensions(extensions.all, getXMLConfiguration().get("extension.jars", [])), context);
languageClient = new LanguageClient('xml', 'XML Support', serverOptions, clientOptions);
let toDispose = context.subscriptions;
let disposable = languageClient.start();
Expand Down Expand Up @@ -245,7 +245,7 @@ export function activate(context: ExtensionContext) {

if (extensions.onDidChange) {// Theia doesn't support this API yet
context.subscriptions.push(extensions.onDidChange(() => {
onExtensionChange(extensions.all);
onExtensionChange(extensions.all, getXMLConfiguration().get("extension.jars", []));
}));
}

Expand Down
9 changes: 6 additions & 3 deletions src/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const glob = require('glob');

let existingExtensions: Array<string>;

export function collectXmlJavaExtensions(extensions: readonly vscode.Extension<any>[]): string[] {
export function collectXmlJavaExtensions(extensions: readonly vscode.Extension<any>[], jars: string[]): string[] {
const result = [];
if (extensions && extensions.length) {
for (const extension of extensions) {
Expand All @@ -22,17 +22,20 @@ export function collectXmlJavaExtensions(extensions: readonly vscode.Extension<a
}
}
}
for (const extension of jars) {
result.push(...glob.sync(extension));
}
// Make a copy of extensions:
existingExtensions = result.slice();
return result;
}

export function onExtensionChange(extensions: readonly vscode.Extension<any>[]) {
export function onExtensionChange(extensions: readonly vscode.Extension<any>[], jars: string[]) {
if (!existingExtensions) {
return;
}
const oldExtensions = new Set(existingExtensions.slice());
const newExtensions = collectXmlJavaExtensions(extensions);
const newExtensions = collectXmlJavaExtensions(extensions, jars);
let hasChanged = ( oldExtensions.size !== newExtensions.length);
if (!hasChanged) {
for (const newExtension of newExtensions) {
Expand Down

0 comments on commit 4f002c9

Please sign in to comment.