miniscript-languageserver
Version:
Language server for MiniScript
362 lines (298 loc) • 13 kB
Markdown
# miniscript-languageserver
[](https://circleci.com/gh/ayecue/miniscript-languageserver)
`miniscript-languageserver` is a Language Server for MiniScript that offers a variety of features, including:
- Auto-completion
- Hover tooltips
- Syntax highlighting and more
This language server is compatible with any client that follows the [LSP standards](https://code.visualstudio.com/api/language-extensions/language-server-extension-guide).
For an example of how it integrates with a popular editor, take a look at the [examples](#example-implementations).
## Supported Providers
`miniscript-languageserver` supports the following language server protocol (LSP) features:
- **Completion**: Auto-completion suggestions for code.
- **Hover**: Displays information about a symbol when you hover over it.
- **Color**: Color information for syntax highlighting and theming.
- **Definition**: Navigate to the definition of a symbol.
- **Formatter**: Automatically format the code according to set rules.
- **Signature Help**: Shows function or method signatures while typing.
- **Document Symbol**: Lists all symbols in a document (e.g., functions, classes).
- **Workspace Symbol**: Search for symbols across the workspace.
- **Diagnostic**: Provides error, warning, and information diagnostics.
- **Semantic Tokens**: Enhanced token classification for syntax highlighting and analysis.
## Install
```bash
npm install -g miniscript-languageserver
```
## Usage
```bash
miniscript-languageserver
```
## Configuration
```ts
{
fileExtensions: string; // default: "ms"
formatter: boolean; // default: true
autocomplete: boolean; // default: true
hoverdocs: boolean; // default: true
diagnostic: boolean; // default: true
transpiler: {
beautify: {
keepParentheses: boolean; // default: true
indentation: "Tab" | "Whitespace"; // default: "Tab"
indentationSpaces: number; // default: 2
};
};
typeAnalyzer: {
strategy: "Dependency" | "Workspace"; // default: "Dependency"
exclude?: string; // default: undefined
};
}
```
## Example Implementations
This section provides a collection of IDEs that implement the `miniscript-languageserver`.
- [VSCode](#vscode): Visual Studio Code setup for `miniscript-languageserver`.
- [Sublime Text](#sublime): Instructions for integrating with Sublime Text.
- [IntelliJ](#intellij): Guide for using `miniscript-languageserver` with IntelliJ.
- [Neovim (nvim)](#nvim): Configuration for Neovim users.
- [Visual Studio](#visual-studio): Learn how to set up a Visual Studio extension using LSP to add support for the MiniScript language in Visual Studio.
Any other IDEs that follow the [LSP standards](https://code.visualstudio.com/api/language-extensions/language-server-extension-guide) should also work with `miniscript-languageserver`.
#### VSCode
1. Create language client file.
```ts
import * as path from 'path';
import {
LanguageClient,
LanguageClientOptions,
ServerOptions,
TransportKind
} from 'vscode-languageclient/node';
const serverModule = context.asAbsolutePath(
path.join('node_modules', 'miniscript-languageserver', 'index.js')
);
const serverOptions: ServerOptions = {
run: { module: serverModule, transport: TransportKind.ipc }
};
const clientOptions: LanguageClientOptions = {
documentSelector: [{ scheme: 'file', language: 'miniscript' }],
synchronize: {
fileEvents: workspace.createFileSystemWatcher('**/*')
},
diagnosticCollectionName: 'miniscript'
};
const client = new LanguageClient(
'languageServerExample',
'Language Server Example',
serverOptions,
clientOptions
);
client.registerProposedFeatures();
client.start();
```
#### Sublime
1. Install the [LSP Package](https://lsp.sublimetext.io/) from the Sublime Text Package Control.
2. Create the following LSP client configuration in your Sublime settings:
```json
{
"show_diagnostics_panel_on_save": 0,
"clients": {
"miniscript": {
"enabled": true,
"command": ["miniscript-languageserver", "--stdio"],
"selector": "source.miniscript"
}
},
"semantic_highlighting": true
}
```
3. Create a Sublime syntax file for miniscript. The highlighting will be provided via the semantic provider, so there's no need to add additional patterns here. Use the following configuration:
```yaml
%YAML 1.2
---
name: miniscript
file_extensions:
- src
scope: source.miniscript
contexts:
main:
- match: '.+'
scope: text.miniscript
```
#### IntelliJ
To set up `miniscript-languageserver` in IntelliJ, follow these steps:
1. [Install miniscript-languageserver](#install).
2. Install the `LSP4IJ` plugin from the JetBrains Plugin Marketplace.
3. Go to **Languages & Frameworks > Language Servers**.
4. Click the "+" icon to add a new language server configuration.
5. In the **Name** field, enter `miniscript`.
6. In the **Command** field, enter `miniscript-languageserver --stdio`.
7. In the **Filename Patterns** section:
- Set **File Name Pattern** to `*.src`.
- Set **Language Id** to `miniscript`.
8. Restart IntelliJ.
You should now have `miniscript-languageserver` set up and ready to use with IntelliJ.
#### nvim
1. Add the following configuration to your `init.vim`:
```vim
" Install vim-plug if it's not already installed
call plug#begin('~/.vim/plugged')
" Install LSP config plugin
Plug 'neovim/nvim-lspconfig'
call plug#end()
" LSP configuration for miniscript-languageserver
lua <<EOF
local configs = require'lspconfig.configs'
local lspconfig = require'lspconfig'
-- Enable debug-level logging
vim.lsp.set_log_level("debug")
if not configs.miniscript then
configs.miniscript = {
default_config = {
cmd = { "miniscript-languageserver", "--stdio" },
filetypes = { "miniscript" },
root_dir = lspconfig.util.root_pattern(".git", vim.fn.getcwd()),
settings = {},
on_attach = function(client, bufnr) -- Optional on_attach function
-- Set up hover keybinding here
vim.api.nvim_buf_set_keymap(bufnr, 'n', 'K', '<cmd>lua vim.lsp.buf.hover()<CR>', { noremap = true, silent = true })
end,
},
}
end
-- Register and start the miniscript LSP
lspconfig.miniscript.setup{}
EOF
autocmd BufRead,BufNewFile *.src set filetype=miniscript
```
2. Don't forget to run :PlugInstall to install the necessary plugins.
This configuration ensures that miniscript-languageserver will be properly integrated into Neovim, and that .src files will be recognized with the correct syntax highlighting and LSP features.
#### Visual Studio
1. Begin by following the [official Visual Studio Extensibility Tutorial](https://learn.microsoft.com/de-de/visualstudio/extensibility/adding-an-lsp-extension?view=vs-2022#get-started) to create a new Visual Studio extension. This will set up the basic structure for the extension project.
2. In this step, we define a custom content type for the language we are adding (e.g., MiniScript). This will help Visual Studio identify files based on their extension or content type. Create a new class called ContentTypeDefinitions.cs:
```csharp
using Microsoft.VisualStudio.LanguageServer.Client;
using Microsoft.VisualStudio.Utilities;
using System.ComponentModel.Composition;
namespace MiniScript
{
internal static class MiniScriptContentDefinition
{
[Export]
[Name("miniscript")]
[BaseDefinition(CodeRemoteContentDefinition.CodeRemoteContentTypeName)]
public static ContentTypeDefinition MiniScriptContentTypeDefinition;
[Export]
[FileExtension(".ms")]
[ContentType("miniscript")]
public static FileExtensionToContentTypeDefinition MiniScriptFileExtensionDefinition;
}
}
```
3. Next, you will create the LanguageClient.cs class that connects Visual Studio to the language server. This class implements ILanguageClient, which is essential for interacting with the LSP. Create a new file called LanguageClient.cs:
```csharp
using Microsoft.VisualStudio.LanguageServer.Client;
using Microsoft.VisualStudio.Threading;
using Microsoft.VisualStudio.Utilities;
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
namespace MiniScript
{
[Export(typeof(ILanguageClient))]
[ContentType("miniscript")]
[RunOnContext(RunningContext.RunOnHost)]
public class MiniScriptLanguageClient : ILanguageClient
{
public event AsyncEventHandler<EventArgs> StartAsync;
public event AsyncEventHandler<EventArgs> StopAsync;
public object InitializationOptions => null;
public IEnumerable<string> FilesToWatch => null;
public bool ShowNotificationOnInitializeFailed => true;
public string Name => "MiniScript Language Client";
public IEnumerable<string> ConfigurationSections => new[] { "miniscript" };
public Task<Connection> ActivateAsync(CancellationToken token)
{
var info = new ProcessStartInfo
{
FileName = @"C:\Users\myUser\AppData\Roaming\npm\miniscript-languageserver.cmd",
Arguments = "--stdio",
RedirectStandardInput = true,
RedirectStandardOutput = true,
UseShellExecute = false,
CreateNoWindow = true
};
var process = new Process { StartInfo = info };
if (process.Start())
{
Debug.WriteLine("Language server started successfully.");
return Task.FromResult(new Connection(process.StandardOutput.BaseStream, process.StandardInput.BaseStream));
}
Debug.WriteLine("Failed to start language server.");
return Task.FromResult<Connection>(null);
}
public async Task OnLoadedAsync()
{
if (StartAsync != null)
{
await StartAsync.InvokeAsync(this, EventArgs.Empty);
}
}
public async Task StopServerAsync()
{
if (StopAsync != null)
{
await StopAsync.InvokeAsync(this, EventArgs.Empty);
}
}
public Task OnServerInitializedAsync()
{
return Task.CompletedTask;
}
public Task<InitializationFailureContext> OnServerInitializeFailedAsync(ILanguageClientInitializationInfo initializationState)
{
string message = "MiniScript failed to activate, now we can't test LSP! :(";
string exception = initializationState.InitializationException?.ToString() ?? string.Empty;
message = $"{message}\n {exception}";
var failureContext = new InitializationFailureContext()
{
FailureMessage = message,
};
return Task.FromResult(failureContext);
}
}
}
```
4. At this point, you have a basic framework for integrating a custom language server into Visual Studio. You can customize the content type, server activation, or extend the language client.
## How to Add Tooltips
Tooltips in `miniscript-languageserver` can help provide additional context, such as method descriptions, to users. You can contribute your own tooltips by following this workflow:
1. Fork and create a pull request (PR) with your changes to the [miniscript-meta repository](https://github.com/ayecue/miniscript-meta), where the meta descriptions are stored.
2. Once your changes are merged, create a separate PR in this repository to update the version of `miniscript-languageserver` to include the new meta descriptions.
Additionally, you can define method-specific tooltips directly in the code using comments. This allows for quick, tooltips for individual methods.
```js
// @type Bar
// @property {string} virtualMoo
Bar = {}
Bar.moo = ""
// Hello world
// I am **bold**
// @description Alternative description
// @example test("title", 123)
// @param {string} test - The title of the book.
// @param {string|number} abc - The author of the book.
// @return {Bar} - Some info about return
Bar.test = function(test, abc)
print "test"
return self
end function
// @type Foo
Foo = new Bar
// @return {Foo}
Foo.New = function(message)
result = new Foo
return result
end function
myVar = Foo.New
myVar.test // shows defined signature of Bar.test on hover
myVar.virtualMoo // shows virtual property of type string on hover
```