Skip to content

Commit

Permalink
Marshal arbitrary JSON diagnostics and other minor improvemenmts. (#13)
Browse files Browse the repository at this point in the history
  • Loading branch information
friedbrice authored Jan 26, 2024
1 parent 956ffc8 commit fcfc8f0
Show file tree
Hide file tree
Showing 9 changed files with 526 additions and 333 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
# Current

- remove "start", "stop", and "restart" commands (they were broken)
- marshal arbitrary JSON to Annotation via use-configurable paths
- `makeClient` now cleans up its resources correctly
- Add documentation

# 1.2.0

- Implement LSP client
Expand Down
226 changes: 99 additions & 127 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,168 +4,140 @@ Language agnostic IDE for VS Code.

## Features

- [x] Reads code diagnostics info by polling a list of user-supplied JSON files.
- [x] Allows the user to configure a custom command as their code formatter.
- [x] Allows the user to configure a custom URL for documentation/API search.
- [x] Per-language LSP client.
- ~~Run a user-configurable command on activation and manage the child-process. (TODO)~~ (redundant)
- ~~Code navigation via a small subset of LSP. (TODO)~~ (redundant)
- Full-feature generic LSP client.
- Allows user to specify files to poll for diagnostics information.
- Supports arbitrary JSON formats via user-specified mapping.
- Mapping is configurable for each file independently.
- Allows the user to configure a custom command as their code formatter.
- Allows the user to configure a custom URL for documentation/API search.
- Single extension supports arbitrarily-many language configurations.

## Configuration

Alloglot uses the following configuration schema.

```typescript
type Config = {
/**
* Extension configuration.
*/
export type Config = {
/**
* An array of language configurations.
* An array of per-language configurations.
*/
languages: Array<{
/**
* The unique language ID.
* You can usually find this in a language's syntax-highlighting extension.
*/
languageId: string

/**
* A command to start the language server.
*/
serverCommand: string

/**
* A formatter command.
* Reads from STDIN and writes to STDOUT.
* `${file}` will be interpolated with the path to the file.
*/
formatCommand: string

/**
* URL to documentation/API search.
* `${query}` will be interpolated with the symbol under cursor.
*/
apiSearchUrl: string

/**
* JSON files that will be polled for diagnostics.
* See README.md for the format.
*/
annotationsFiles: Array<string>
}>
languages: Array<LanguageConfig>
}
```
An example configuration follows.
```json
{
"alloglot.languages": [
{
"languageId": "haskell",
"serverCommand": "static-ls",
"formatCommand": "fourmolu --mode stdout --stdin-input-file ${file}",
"apiSearchUrl": "https://hoogle.haskell.org/?hoogle=${query}",
"annotationsFiles": "ghcid.txt"
}
]
}
```

## Diagnostics JSON format
Alloglot provides diagnostics information by polling a user-configurable list of JSON files.
The intention is that you start a filewatcher that runs a compiler on file save in a terminal, with the compiler writing its output to a JSON file.
On creation or change of the JSON file, Alloglot will read the file and interface with VS Code's diagnostics API.
The diagnostics will remain until the JSON file is changed or deleted.
This allows arbitrary sources of diagnostics, even for languages that have no VS Code extension.
Alloglot expects the JSON file be a list of _annotations,_ objects adhering to the following format.
```typescript
type Annotation = {
/**
* Configuration for an arbitrary language.
*/
export type LanguageConfig = {
/**
* Source of this annotation.
* E.g. the name of the compiler or linter that created it.
* The unique language ID.
* You can usually find this in a language's syntax-highlighting extension.
*/
source: string
languageId: string

/**
* The diagnostic-severity levels supported by VS Code.
* A command to start the language server.
*/
severity: 'error' | 'warning' | 'info' | 'hint'
serverCommand?: string

/**
* Path to the file to which this diagnostic applies, relative to project root.
* A formatter command.
* Reads from STDIN and writes to STDOUT.
* `${file}` will be interpolated with the path to the file.
*/
file: string
formatCommand?: string

/**
* Document span info.
* Lines and columns should be indexed from 1
* URL to documentation/API search.
* `${query}` will be interpolated with the symbol under cursor.
*/
startLine: number
apiSearchUrl?: string

/**
* Document span info.
* Lines and columns should be indexed from 1
* A list of files to watch for compiler-generated JSON output.
*/
startColumn: number
annotations?: Array<AnnotationsConfig>
}

/**
* A file to watch for compiler-generated JSON output, and instructions on how to marshal the JSON objects.
*/
export type AnnotationsConfig = {
/**
* Document span info.
* Lines and columns should be indexed from 1
* The path to the file to watch.
*/
endLine: number
file: string

/**
* Document span info.
* Lines and columns should be indexed from 1
* `json` for a top-level array of objects.
* `jsonl` for a newline-separated stream of objects.
*/
endColumn: number
format: 'json' | 'jsonl'

/**
* The error/warning message text.
* Mapping between properties of the JSON objects and properties of `Annotation`.
*/
message: string
mapping: AnnotationsMapping
}

/**
* List of textual replacements, in any, for VS Code's _Quick Fix_ feature.
*/
/**
* Intermediate representation of compiler-generated JSON output and VS Code diagnostics.
*/
export type Annotation = {
source: string
severity: 'error' | 'warning' | 'info' | 'hint'
file: string
startLine: number
startColumn: number
endLine: number
endColumn: number
message: string
replacements: Array<string>

/**
* Reference code for the error/warning message.
* E.g. `"ts(2552)"`.
*/
referenceCode?: string
}
```
## ~~Future work~~
### ~~Code Navigation~~
~~We intend to implement a client for a subset of the LSP narrowly focused on code navigation.~~
~~We intend to support the following requests.~~
- ~~Goto Definition~~
- ~~Find References~~
- ~~Hover~~
- ~~Document Symbols~~
- ~~Completion Proposals~~
- ~~Completion Item Resolve Request~~
~~The intention is to make code navigation possible for languages that don't have a more-robust language server.~~
~~A simple language server supporting these requests could be implemented using SQLite or even Ctags, for example.~~
~~Such a language server can watch for file save events and re-index a file on save.~~
~~This workflow decouples the background task of generating code navigation information from the forground task of presenting the information in the text editor.~~

This was made redundant, since we added a full LSP client from a library.
### ~~Startup and shutdown commands~~
/**
* Mapping between arbitrary JSON object and properties of `Annotation`.
* Each property is an array of strings that will be used as a path into the JSON object.
*/
export type AnnotationsMapping = {
message: Array<string>
file?: Array<string>
startLine?: Array<string>
startColumn?: Array<string>
endLine?: Array<string>
endColumn?: Array<string>
source?: Array<string>
severity?: Array<string>
replacements?: Array<string>
referenceCode?: Array<string>
}
```
~~Commands to run on extention activation and extention deactivation.~~
~~The intent is that you launch a filewatcher that runs a compiler or linter on file change.~~
~~This compiler or linter should write its output to a JSON file in the format described in [Diagnostics](#diagnostics).~~
~~This workflow decouples the background task of generating code diagnostics information from the forground task of presenting the information in the text editor.~~
An example configuration follows.
This is made redundant, since the LSP client takes care of that for us.
```json
{
"alloglot.languages": [
{
"languageId": "haskell",
"serverCommand": "static-ls",
"formatCommand": "fourmolu --mode stdout --stdin-input-file ${file}",
"apiSearchUrl": "https://hoogle.haskell.org/?hoogle=${query}",
"annotations": {
"file": "ghcid.out",
"format": "jsonl",
"mapping": {
"file": ["span", "file"],
"startLine": ["span", "startLine"],
"startColumn": ["span", "startCol"],
"endLine": ["span", "endLine"],
"endColumn": ["span", "endCol"],
"message": ["doc"],
"severity": ["messageClass"]
}
}
}
]
}
```
Loading

0 comments on commit fcfc8f0

Please sign in to comment.