mirror of
https://github.com/helix-editor/helix.git
synced 2024-11-22 09:26:19 +04:00
Merge branch 'helix-editor:master' into master
This commit is contained in:
commit
61bd5b60af
453
Cargo.lock
generated
453
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -5,6 +5,7 @@ members = [
|
||||
"helix-view",
|
||||
"helix-term",
|
||||
"helix-tui",
|
||||
"helix-lsp-types",
|
||||
"helix-lsp",
|
||||
"helix-event",
|
||||
"helix-dap",
|
||||
|
@ -1,6 +1,6 @@
|
||||
| Language | Syntax Highlighting | Treesitter Textobjects | Auto Indent | Default LSP |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| ada | ✓ | ✓ | | `ada_language_server`, `ada_language_server` |
|
||||
| ada | ✓ | ✓ | | `ada_language_server` |
|
||||
| adl | ✓ | ✓ | ✓ | |
|
||||
| agda | ✓ | | | |
|
||||
| astro | ✓ | | | |
|
||||
@ -34,8 +34,8 @@
|
||||
| devicetree | ✓ | | | |
|
||||
| dhall | ✓ | ✓ | | `dhall-lsp-server` |
|
||||
| diff | ✓ | | | |
|
||||
| docker-compose | ✓ | | ✓ | `docker-compose-langserver`, `yaml-language-server` |
|
||||
| dockerfile | ✓ | | | `docker-langserver` |
|
||||
| docker-compose | ✓ | ✓ | ✓ | `docker-compose-langserver`, `yaml-language-server` |
|
||||
| dockerfile | ✓ | ✓ | | `docker-langserver` |
|
||||
| dot | ✓ | | | `dot-language-server` |
|
||||
| dtd | ✓ | | | |
|
||||
| earthfile | ✓ | ✓ | ✓ | `earthlyls` |
|
||||
@ -46,7 +46,7 @@
|
||||
| elixir | ✓ | ✓ | ✓ | `elixir-ls` |
|
||||
| elm | ✓ | ✓ | | `elm-language-server` |
|
||||
| elvish | ✓ | | | `elvish` |
|
||||
| env | ✓ | | | |
|
||||
| env | ✓ | ✓ | | |
|
||||
| erb | ✓ | | | |
|
||||
| erlang | ✓ | ✓ | | `erlang_ls` |
|
||||
| esdl | ✓ | | | |
|
||||
@ -58,9 +58,10 @@
|
||||
| gas | ✓ | ✓ | | |
|
||||
| gdscript | ✓ | ✓ | ✓ | |
|
||||
| gemini | ✓ | | | |
|
||||
| gherkin | ✓ | | | |
|
||||
| git-attributes | ✓ | | | |
|
||||
| git-commit | ✓ | ✓ | | |
|
||||
| git-config | ✓ | | | |
|
||||
| git-config | ✓ | ✓ | | |
|
||||
| git-ignore | ✓ | | | |
|
||||
| git-rebase | ✓ | | | |
|
||||
| gjs | ✓ | ✓ | ✓ | `typescript-language-server`, `vscode-eslint-language-server`, `ember-language-server` |
|
||||
@ -69,7 +70,7 @@
|
||||
| glsl | ✓ | ✓ | ✓ | |
|
||||
| gn | ✓ | | | |
|
||||
| go | ✓ | ✓ | ✓ | `gopls`, `golangci-lint-langserver` |
|
||||
| godot-resource | ✓ | | | |
|
||||
| godot-resource | ✓ | ✓ | | |
|
||||
| gomod | ✓ | | | `gopls` |
|
||||
| gotmpl | ✓ | | | `gopls` |
|
||||
| gowork | ✓ | | | `gopls` |
|
||||
@ -82,7 +83,7 @@
|
||||
| hcl | ✓ | ✓ | ✓ | `terraform-ls` |
|
||||
| heex | ✓ | ✓ | | `elixir-ls` |
|
||||
| helm | ✓ | | | `helm_ls` |
|
||||
| hocon | ✓ | | ✓ | |
|
||||
| hocon | ✓ | ✓ | ✓ | |
|
||||
| hoon | ✓ | | | |
|
||||
| hosts | ✓ | | | |
|
||||
| html | ✓ | | | `vscode-html-language-server` |
|
||||
@ -97,6 +98,7 @@
|
||||
| javascript | ✓ | ✓ | ✓ | `typescript-language-server` |
|
||||
| jinja | ✓ | | | |
|
||||
| jjdescription | ✓ | | | |
|
||||
| jq | ✓ | ✓ | | `jq-lsp` |
|
||||
| jsdoc | ✓ | | | |
|
||||
| json | ✓ | ✓ | ✓ | `vscode-json-language-server` |
|
||||
| json5 | ✓ | | | |
|
||||
@ -125,7 +127,7 @@
|
||||
| markdown.inline | ✓ | | | |
|
||||
| matlab | ✓ | ✓ | ✓ | |
|
||||
| mermaid | ✓ | | | |
|
||||
| meson | ✓ | | ✓ | |
|
||||
| meson | ✓ | | ✓ | `mesonlsp` |
|
||||
| mint | | | | `mint` |
|
||||
| mojo | ✓ | ✓ | ✓ | `mojo-lsp-server` |
|
||||
| move | ✓ | | | |
|
||||
@ -133,7 +135,7 @@
|
||||
| nasm | ✓ | ✓ | | |
|
||||
| nickel | ✓ | | ✓ | `nls` |
|
||||
| nim | ✓ | ✓ | ✓ | `nimlangserver` |
|
||||
| nix | ✓ | ✓ | | `nil` |
|
||||
| nix | ✓ | ✓ | | `nil`, `nixd` |
|
||||
| nu | ✓ | | | `nu` |
|
||||
| nunjucks | ✓ | | | |
|
||||
| ocaml | ✓ | | ✓ | `ocamllsp` |
|
||||
@ -156,7 +158,7 @@
|
||||
| pod | ✓ | | | |
|
||||
| ponylang | ✓ | ✓ | ✓ | |
|
||||
| powershell | ✓ | | | |
|
||||
| prisma | ✓ | | | `prisma-language-server` |
|
||||
| prisma | ✓ | ✓ | | `prisma-language-server` |
|
||||
| prolog | | | | `swipl` |
|
||||
| protobuf | ✓ | ✓ | ✓ | `bufls`, `pb` |
|
||||
| prql | ✓ | | | |
|
||||
@ -184,7 +186,7 @@
|
||||
| sml | ✓ | | | |
|
||||
| solidity | ✓ | ✓ | | `solc` |
|
||||
| spicedb | ✓ | | | |
|
||||
| sql | ✓ | | | |
|
||||
| sql | ✓ | ✓ | | |
|
||||
| sshclientconfig | ✓ | | | |
|
||||
| starlark | ✓ | ✓ | | |
|
||||
| strace | ✓ | | | |
|
||||
@ -199,12 +201,14 @@
|
||||
| tcl | ✓ | | ✓ | |
|
||||
| templ | ✓ | | | `templ` |
|
||||
| tfvars | ✓ | | ✓ | `terraform-ls` |
|
||||
| thrift | ✓ | | | |
|
||||
| todotxt | ✓ | | | |
|
||||
| toml | ✓ | ✓ | | `taplo` |
|
||||
| tsq | ✓ | | | |
|
||||
| tsx | ✓ | ✓ | ✓ | `typescript-language-server` |
|
||||
| twig | ✓ | | | |
|
||||
| typescript | ✓ | ✓ | ✓ | `typescript-language-server` |
|
||||
| typespec | ✓ | ✓ | ✓ | `tsp-server` |
|
||||
| typst | ✓ | | | `tinymist`, `typst-lsp` |
|
||||
| ungrammar | ✓ | | | |
|
||||
| unison | ✓ | | ✓ | |
|
||||
@ -224,6 +228,6 @@
|
||||
| xit | ✓ | | | |
|
||||
| xml | ✓ | | ✓ | |
|
||||
| xtc | ✓ | | | |
|
||||
| yaml | ✓ | | ✓ | `yaml-language-server`, `ansible-language-server` |
|
||||
| yaml | ✓ | ✓ | ✓ | `yaml-language-server`, `ansible-language-server` |
|
||||
| yuck | ✓ | | | |
|
||||
| zig | ✓ | ✓ | ✓ | `zls` |
|
||||
|
@ -14,6 +14,10 @@ # Installing Helix
|
||||
## Pre-built binaries
|
||||
|
||||
Download pre-built binaries from the [GitHub Releases page](https://github.com/helix-editor/helix/releases).
|
||||
Add the `hx` binary to your system's `$PATH` to use it from the command line, and copy the `runtime` directory into the config directory (for example `~/.config/helix/runtime` on Linux/macOS).
|
||||
The runtime location can be overriden via the HELIX_RUNTIME environment variable.
|
||||
The tarball contents include an `hx` binary and a `runtime` directory.
|
||||
To set up Helix:
|
||||
|
||||
1. Add the `hx` binary to your system's `$PATH` to allow it to be used from the command line.
|
||||
2. Copy the `runtime` directory to a location that `hx` searches for runtime files. A typical location on Linux/macOS is `~/.config/helix/runtime`.
|
||||
|
||||
To see the runtime directories that `hx` searches, run `hx --health`. If necessary, you can override the default runtime location by setting the `HELIX_RUNTIME` environment variable.
|
||||
|
@ -320,10 +320,14 @@ ##### Completion Menu
|
||||
|
||||
Displays documentation for the selected completion item. Remapping currently not supported.
|
||||
|
||||
| Key | Description |
|
||||
| ---- | ----------- |
|
||||
| `Shift-Tab`, `Ctrl-p`, `Up` | Previous entry |
|
||||
| `Tab`, `Ctrl-n`, `Down` | Next entry |
|
||||
| Key | Description |
|
||||
| ---- | ----------- |
|
||||
| `Shift-Tab`, `Ctrl-p`, `Up` | Previous entry |
|
||||
| `Tab`, `Ctrl-n`, `Down` | Next entry |
|
||||
| `Enter` | Close menu and accept completion |
|
||||
| `Ctrl-c` | Close menu and reject completion |
|
||||
|
||||
Any other keypresses result in the completion being accepted.
|
||||
|
||||
##### Signature-help Popup
|
||||
|
||||
|
@ -75,5 +75,20 @@ ## Special keys and modifiers
|
||||
|
||||
Keys can be disabled by binding them to the `no_op` command.
|
||||
|
||||
A list of commands is available in the [Keymap](https://docs.helix-editor.com/keymap.html) documentation
|
||||
and in the source code at [`helix-term/src/commands.rs`](https://github.com/helix-editor/helix/blob/master/helix-term/src/commands.rs) at the invocation of `static_commands!` macro and the `TypableCommandList`.
|
||||
## Commands
|
||||
|
||||
There are three kinds of commands that can be used in keymaps:
|
||||
|
||||
* Static commands: commands like `move_char_right` which are usually bound to
|
||||
keys and used for movement and editing. A list of static commands is
|
||||
available in the [Keymap](./keymap.html) documentation and in the source code
|
||||
in [`helix-term/src/commands.rs`](https://github.com/helix-editor/helix/blob/master/helix-term/src/commands.rs)
|
||||
at the invocation of `static_commands!` macro and the `TypableCommandList`.
|
||||
* Typable commands: commands that can be executed from command mode (`:`), for
|
||||
example `:write!`. See the [Commands](./commands.html) documentation for a
|
||||
list of available typeable commands.
|
||||
* Macros: sequences of keys that are executed in order. These keybindings
|
||||
start with `@` and then list any number of keys to be executed. For example
|
||||
`@miw` can be used to select the surrounding word. For now, macro keybindings
|
||||
are not allowed in keybinding sequences due to limitations in the way that
|
||||
command sequences are executed.
|
||||
|
@ -293,12 +293,13 @@ #### Interface
|
||||
| `ui.statusline.select` | Statusline mode during select mode ([only if `editor.color-modes` is enabled][editor-section]) |
|
||||
| `ui.statusline.separator` | Separator character in statusline |
|
||||
| `ui.bufferline` | Style for the buffer line |
|
||||
| `ui.bufferline.active` | Style for the active buffer in buffer line |
|
||||
| `ui.bufferline.active` | Style for the active buffer in buffer line |
|
||||
| `ui.bufferline.background` | Style for bufferline background |
|
||||
| `ui.popup` | Documentation popups (e.g. Space + k) |
|
||||
| `ui.popup.info` | Prompt for multiple key options |
|
||||
| `ui.picker.header` | Column names in pickers with multiple columns |
|
||||
| `ui.picker.header.active` | The column name in pickers with multiple columns where the cursor is entering into. |
|
||||
| `ui.picker.header` | Header row area in pickers with multiple columns |
|
||||
| `ui.picker.header.column` | Column names in pickers with multiple columns |
|
||||
| `ui.picker.header.column.active` | The column name in pickers with multiple columns where the cursor is entering into. |
|
||||
| `ui.window` | Borderlines separating splits |
|
||||
| `ui.help` | Description box for commands |
|
||||
| `ui.text` | Default text style, command prompts, popup text, etc. |
|
||||
|
@ -53,6 +53,10 @@ ## Integration tests
|
||||
[helpers.rs][helpers.rs]. The log level can be set with the `HELIX_LOG_LEVEL`
|
||||
environment variable, e.g. `HELIX_LOG_LEVEL=debug cargo integration-test`.
|
||||
|
||||
Contributors using MacOS might encounter `Too many open files (os error 24)`
|
||||
failures while running integration tests. This can be resolved by increasing
|
||||
the default value (e.g. to `10240` from `256`) by running `ulimit -n 10240`.
|
||||
|
||||
## Minimum Stable Rust Version (MSRV) Policy
|
||||
|
||||
Helix follows the MSRV of Firefox.
|
||||
|
@ -1,13 +1,14 @@
|
||||
|
||||
| Crate | Description |
|
||||
| ----------- | ----------- |
|
||||
| helix-core | Core editing primitives, functional. |
|
||||
| helix-lsp | Language server client |
|
||||
| helix-dap | Debug Adapter Protocol (DAP) client |
|
||||
| helix-loader | Functions for building, fetching, and loading external resources |
|
||||
| helix-view | UI abstractions for use in backends, imperative shell. |
|
||||
| helix-term | Terminal UI |
|
||||
| helix-tui | TUI primitives, forked from tui-rs, inspired by Cursive |
|
||||
| Crate | Description |
|
||||
| ----------- | ----------- |
|
||||
| helix-core | Core editing primitives, functional. |
|
||||
| helix-lsp | Language server client |
|
||||
| helix-lsp-types | Language Server Protocol type definitions |
|
||||
| helix-dap | Debug Adapter Protocol (DAP) client |
|
||||
| helix-loader | Functions for building, fetching, and loading external resources |
|
||||
| helix-view | UI abstractions for use in backends, imperative shell. |
|
||||
| helix-term | Terminal UI |
|
||||
| helix-tui | TUI primitives, forked from tui-rs, inspired by Cursive |
|
||||
|
||||
|
||||
This document contains a high-level overview of Helix internals.
|
||||
|
@ -126,6 +126,7 @@
|
||||
# disable fetching and building of tree-sitter grammars in the helix-term build.rs
|
||||
HELIX_DISABLE_AUTO_GRAMMAR_BUILD = "1";
|
||||
buildInputs = [stdenv.cc.cc.lib];
|
||||
nativeBuildInputs = [pkgs.installShellFiles];
|
||||
# disable tests
|
||||
doCheck = false;
|
||||
meta.mainProgram = "hx";
|
||||
@ -141,6 +142,7 @@
|
||||
cp contrib/Helix.desktop $out/share/applications
|
||||
cp logo.svg $out/share/icons/hicolor/scalable/apps/helix.svg
|
||||
cp contrib/helix.png $out/share/icons/hicolor/256x256/apps
|
||||
installShellCompletion contrib/completion/hx.{bash,fish,zsh}
|
||||
'';
|
||||
});
|
||||
helix = makeOverridableHelix self.packages.${system}.helix-unwrapped {};
|
||||
|
@ -46,7 +46,7 @@ serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
toml = "0.8"
|
||||
|
||||
imara-diff = "0.1.6"
|
||||
imara-diff = "0.1.7"
|
||||
|
||||
encoding_rs = "0.8"
|
||||
|
||||
|
@ -75,9 +75,9 @@ fn from((open, close): (&char, &char)) -> Self {
|
||||
|
||||
impl AutoPairs {
|
||||
/// Make a new AutoPairs set with the given pairs and default conditions.
|
||||
pub fn new<'a, V: 'a, A>(pairs: V) -> Self
|
||||
pub fn new<'a, V, A>(pairs: V) -> Self
|
||||
where
|
||||
V: IntoIterator<Item = A>,
|
||||
V: IntoIterator<Item = A> + 'a,
|
||||
A: Into<Pair>,
|
||||
{
|
||||
let mut auto_pairs = HashMap::new();
|
||||
|
@ -265,7 +265,7 @@ fn is_first_in_line(node: Node, text: RopeSlice, new_line_byte_pos: Option<usize
|
||||
/// This is usually constructed in one of 2 ways:
|
||||
/// - Successively add indent captures to get the (added) indent from a single line
|
||||
/// - Successively add the indent results for each line
|
||||
/// The string that this indentation defines starts with the string contained in the align field (unless it is None), followed by:
|
||||
/// The string that this indentation defines starts with the string contained in the align field (unless it is None), followed by:
|
||||
/// - max(0, indent - outdent) tabs, if tabs are used for indentation
|
||||
/// - max(0, indent - outdent)*indent_width spaces, if spaces are used for indentation
|
||||
#[derive(Default, Debug, PartialEq, Eq, Clone)]
|
||||
@ -457,7 +457,7 @@ fn query_indents<'a>(
|
||||
// Skip matches where not all custom predicates are fulfilled
|
||||
if !query.general_predicates(m.pattern_index).iter().all(|pred| {
|
||||
match pred.operator.as_ref() {
|
||||
"not-kind-eq?" => match (pred.args.get(0), pred.args.get(1)) {
|
||||
"not-kind-eq?" => match (pred.args.first(), pred.args.get(1)) {
|
||||
(
|
||||
Some(QueryPredicateArg::Capture(capture_idx)),
|
||||
Some(QueryPredicateArg::String(kind)),
|
||||
@ -473,7 +473,7 @@ fn query_indents<'a>(
|
||||
}
|
||||
},
|
||||
"same-line?" | "not-same-line?" => {
|
||||
match (pred.args.get(0), pred.args.get(1)) {
|
||||
match (pred.args.first(), pred.args.get(1)) {
|
||||
(
|
||||
Some(QueryPredicateArg::Capture(capt1)),
|
||||
Some(QueryPredicateArg::Capture(capt2))
|
||||
@ -495,7 +495,7 @@ fn query_indents<'a>(
|
||||
}
|
||||
}
|
||||
}
|
||||
"one-line?" | "not-one-line?" => match pred.args.get(0) {
|
||||
"one-line?" | "not-one-line?" => match pred.args.first() {
|
||||
Some(QueryPredicateArg::Capture(capture_idx)) => {
|
||||
let node = m.nodes_for_capture_index(*capture_idx).next();
|
||||
|
||||
@ -786,6 +786,7 @@ fn init_indent_query<'a, 'b>(
|
||||
/// - The line after the node. This is defined by:
|
||||
/// - The scope `tail`.
|
||||
/// - The scope `all` if this node is not the first node on its line.
|
||||
///
|
||||
/// Intuitively, `all` applies to everything contained in this node while `tail` applies to everything except for the first line of the node.
|
||||
/// The indents from different nodes for the same line are then combined.
|
||||
/// The result [Indentation] is simply the sum of the [Indentation] for all lines.
|
||||
|
@ -197,13 +197,31 @@ pub fn move_prev_long_word_end(slice: RopeSlice, range: Range, count: usize) ->
|
||||
word_move(slice, range, count, WordMotionTarget::PrevLongWordEnd)
|
||||
}
|
||||
|
||||
pub fn move_next_sub_word_start(slice: RopeSlice, range: Range, count: usize) -> Range {
|
||||
word_move(slice, range, count, WordMotionTarget::NextSubWordStart)
|
||||
}
|
||||
|
||||
pub fn move_next_sub_word_end(slice: RopeSlice, range: Range, count: usize) -> Range {
|
||||
word_move(slice, range, count, WordMotionTarget::NextSubWordEnd)
|
||||
}
|
||||
|
||||
pub fn move_prev_sub_word_start(slice: RopeSlice, range: Range, count: usize) -> Range {
|
||||
word_move(slice, range, count, WordMotionTarget::PrevSubWordStart)
|
||||
}
|
||||
|
||||
pub fn move_prev_sub_word_end(slice: RopeSlice, range: Range, count: usize) -> Range {
|
||||
word_move(slice, range, count, WordMotionTarget::PrevSubWordEnd)
|
||||
}
|
||||
|
||||
fn word_move(slice: RopeSlice, range: Range, count: usize, target: WordMotionTarget) -> Range {
|
||||
let is_prev = matches!(
|
||||
target,
|
||||
WordMotionTarget::PrevWordStart
|
||||
| WordMotionTarget::PrevLongWordStart
|
||||
| WordMotionTarget::PrevSubWordStart
|
||||
| WordMotionTarget::PrevWordEnd
|
||||
| WordMotionTarget::PrevLongWordEnd
|
||||
| WordMotionTarget::PrevSubWordEnd
|
||||
);
|
||||
|
||||
// Special-case early-out.
|
||||
@ -383,6 +401,12 @@ pub enum WordMotionTarget {
|
||||
NextLongWordEnd,
|
||||
PrevLongWordStart,
|
||||
PrevLongWordEnd,
|
||||
// A sub word is similar to a regular word, except it is also delimited by
|
||||
// underscores and transitions from lowercase to uppercase.
|
||||
NextSubWordStart,
|
||||
NextSubWordEnd,
|
||||
PrevSubWordStart,
|
||||
PrevSubWordEnd,
|
||||
}
|
||||
|
||||
pub trait CharHelpers {
|
||||
@ -398,8 +422,10 @@ fn range_to_target(&mut self, target: WordMotionTarget, origin: Range) -> Range
|
||||
target,
|
||||
WordMotionTarget::PrevWordStart
|
||||
| WordMotionTarget::PrevLongWordStart
|
||||
| WordMotionTarget::PrevSubWordStart
|
||||
| WordMotionTarget::PrevWordEnd
|
||||
| WordMotionTarget::PrevLongWordEnd
|
||||
| WordMotionTarget::PrevSubWordEnd
|
||||
);
|
||||
|
||||
// Reverse the iterator if needed for the motion direction.
|
||||
@ -476,6 +502,25 @@ fn is_long_word_boundary(a: char, b: char) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
fn is_sub_word_boundary(a: char, b: char, dir: Direction) -> bool {
|
||||
match (categorize_char(a), categorize_char(b)) {
|
||||
(CharCategory::Word, CharCategory::Word) => {
|
||||
if (a == '_') != (b == '_') {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Subword boundaries are directional: in 'fooBar', there is a
|
||||
// boundary between 'o' and 'B', but not between 'B' and 'a'.
|
||||
match dir {
|
||||
Direction::Forward => a.is_lowercase() && b.is_uppercase(),
|
||||
Direction::Backward => a.is_uppercase() && b.is_lowercase(),
|
||||
}
|
||||
}
|
||||
(a, b) if a != b => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn reached_target(target: WordMotionTarget, prev_ch: char, next_ch: char) -> bool {
|
||||
match target {
|
||||
WordMotionTarget::NextWordStart | WordMotionTarget::PrevWordEnd => {
|
||||
@ -494,6 +539,22 @@ fn reached_target(target: WordMotionTarget, prev_ch: char, next_ch: char) -> boo
|
||||
is_long_word_boundary(prev_ch, next_ch)
|
||||
&& (!prev_ch.is_whitespace() || char_is_line_ending(next_ch))
|
||||
}
|
||||
WordMotionTarget::NextSubWordStart => {
|
||||
is_sub_word_boundary(prev_ch, next_ch, Direction::Forward)
|
||||
&& (char_is_line_ending(next_ch) || !(next_ch.is_whitespace() || next_ch == '_'))
|
||||
}
|
||||
WordMotionTarget::PrevSubWordEnd => {
|
||||
is_sub_word_boundary(prev_ch, next_ch, Direction::Backward)
|
||||
&& (char_is_line_ending(next_ch) || !(next_ch.is_whitespace() || next_ch == '_'))
|
||||
}
|
||||
WordMotionTarget::NextSubWordEnd => {
|
||||
is_sub_word_boundary(prev_ch, next_ch, Direction::Forward)
|
||||
&& (!(prev_ch.is_whitespace() || prev_ch == '_') || char_is_line_ending(next_ch))
|
||||
}
|
||||
WordMotionTarget::PrevSubWordStart => {
|
||||
is_sub_word_boundary(prev_ch, next_ch, Direction::Backward)
|
||||
&& (!(prev_ch.is_whitespace() || prev_ch == '_') || char_is_line_ending(next_ch))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1012,6 +1073,178 @@ fn test_behaviour_when_moving_to_start_of_next_words() {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_behaviour_when_moving_to_start_of_next_sub_words() {
|
||||
let tests = [
|
||||
(
|
||||
"NextSubwordStart",
|
||||
vec![
|
||||
(1, Range::new(0, 0), Range::new(0, 4)),
|
||||
(1, Range::new(4, 4), Range::new(4, 11)),
|
||||
],
|
||||
),
|
||||
(
|
||||
"next_subword_start",
|
||||
vec![
|
||||
(1, Range::new(0, 0), Range::new(0, 5)),
|
||||
(1, Range::new(4, 4), Range::new(5, 13)),
|
||||
],
|
||||
),
|
||||
(
|
||||
"Next_Subword_Start",
|
||||
vec![
|
||||
(1, Range::new(0, 0), Range::new(0, 5)),
|
||||
(1, Range::new(4, 4), Range::new(5, 13)),
|
||||
],
|
||||
),
|
||||
(
|
||||
"NEXT_SUBWORD_START",
|
||||
vec![
|
||||
(1, Range::new(0, 0), Range::new(0, 5)),
|
||||
(1, Range::new(4, 4), Range::new(5, 13)),
|
||||
],
|
||||
),
|
||||
(
|
||||
"next subword start",
|
||||
vec![
|
||||
(1, Range::new(0, 0), Range::new(0, 5)),
|
||||
(1, Range::new(4, 4), Range::new(5, 13)),
|
||||
],
|
||||
),
|
||||
(
|
||||
"Next Subword Start",
|
||||
vec![
|
||||
(1, Range::new(0, 0), Range::new(0, 5)),
|
||||
(1, Range::new(4, 4), Range::new(5, 13)),
|
||||
],
|
||||
),
|
||||
(
|
||||
"NEXT SUBWORD START",
|
||||
vec![
|
||||
(1, Range::new(0, 0), Range::new(0, 5)),
|
||||
(1, Range::new(4, 4), Range::new(5, 13)),
|
||||
],
|
||||
),
|
||||
(
|
||||
"next__subword__start",
|
||||
vec![
|
||||
(1, Range::new(0, 0), Range::new(0, 6)),
|
||||
(1, Range::new(4, 4), Range::new(4, 6)),
|
||||
(1, Range::new(5, 5), Range::new(6, 15)),
|
||||
],
|
||||
),
|
||||
(
|
||||
"Next__Subword__Start",
|
||||
vec![
|
||||
(1, Range::new(0, 0), Range::new(0, 6)),
|
||||
(1, Range::new(4, 4), Range::new(4, 6)),
|
||||
(1, Range::new(5, 5), Range::new(6, 15)),
|
||||
],
|
||||
),
|
||||
(
|
||||
"NEXT__SUBWORD__START",
|
||||
vec![
|
||||
(1, Range::new(0, 0), Range::new(0, 6)),
|
||||
(1, Range::new(4, 4), Range::new(4, 6)),
|
||||
(1, Range::new(5, 5), Range::new(6, 15)),
|
||||
],
|
||||
),
|
||||
];
|
||||
|
||||
for (sample, scenario) in tests {
|
||||
for (count, begin, expected_end) in scenario.into_iter() {
|
||||
let range = move_next_sub_word_start(Rope::from(sample).slice(..), begin, count);
|
||||
assert_eq!(range, expected_end, "Case failed: [{}]", sample);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_behaviour_when_moving_to_end_of_next_sub_words() {
|
||||
let tests = [
|
||||
(
|
||||
"NextSubwordEnd",
|
||||
vec![
|
||||
(1, Range::new(0, 0), Range::new(0, 4)),
|
||||
(1, Range::new(4, 4), Range::new(4, 11)),
|
||||
],
|
||||
),
|
||||
(
|
||||
"next subword end",
|
||||
vec![
|
||||
(1, Range::new(0, 0), Range::new(0, 4)),
|
||||
(1, Range::new(4, 4), Range::new(4, 12)),
|
||||
],
|
||||
),
|
||||
(
|
||||
"Next Subword End",
|
||||
vec![
|
||||
(1, Range::new(0, 0), Range::new(0, 4)),
|
||||
(1, Range::new(4, 4), Range::new(4, 12)),
|
||||
],
|
||||
),
|
||||
(
|
||||
"NEXT SUBWORD END",
|
||||
vec![
|
||||
(1, Range::new(0, 0), Range::new(0, 4)),
|
||||
(1, Range::new(4, 4), Range::new(4, 12)),
|
||||
],
|
||||
),
|
||||
(
|
||||
"next_subword_end",
|
||||
vec![
|
||||
(1, Range::new(0, 0), Range::new(0, 4)),
|
||||
(1, Range::new(4, 4), Range::new(4, 12)),
|
||||
],
|
||||
),
|
||||
(
|
||||
"Next_Subword_End",
|
||||
vec![
|
||||
(1, Range::new(0, 0), Range::new(0, 4)),
|
||||
(1, Range::new(4, 4), Range::new(4, 12)),
|
||||
],
|
||||
),
|
||||
(
|
||||
"NEXT_SUBWORD_END",
|
||||
vec![
|
||||
(1, Range::new(0, 0), Range::new(0, 4)),
|
||||
(1, Range::new(4, 4), Range::new(4, 12)),
|
||||
],
|
||||
),
|
||||
(
|
||||
"next__subword__end",
|
||||
vec![
|
||||
(1, Range::new(0, 0), Range::new(0, 4)),
|
||||
(1, Range::new(4, 4), Range::new(4, 13)),
|
||||
(1, Range::new(5, 5), Range::new(5, 13)),
|
||||
],
|
||||
),
|
||||
(
|
||||
"Next__Subword__End",
|
||||
vec![
|
||||
(1, Range::new(0, 0), Range::new(0, 4)),
|
||||
(1, Range::new(4, 4), Range::new(4, 13)),
|
||||
(1, Range::new(5, 5), Range::new(5, 13)),
|
||||
],
|
||||
),
|
||||
(
|
||||
"NEXT__SUBWORD__END",
|
||||
vec![
|
||||
(1, Range::new(0, 0), Range::new(0, 4)),
|
||||
(1, Range::new(4, 4), Range::new(4, 13)),
|
||||
(1, Range::new(5, 5), Range::new(5, 13)),
|
||||
],
|
||||
),
|
||||
];
|
||||
|
||||
for (sample, scenario) in tests {
|
||||
for (count, begin, expected_end) in scenario.into_iter() {
|
||||
let range = move_next_sub_word_end(Rope::from(sample).slice(..), begin, count);
|
||||
assert_eq!(range, expected_end, "Case failed: [{}]", sample);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_behaviour_when_moving_to_start_of_next_long_words() {
|
||||
let tests = [
|
||||
@ -1181,6 +1414,92 @@ fn test_behaviour_when_moving_to_start_of_previous_words() {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_behaviour_when_moving_to_start_of_previous_sub_words() {
|
||||
let tests = [
|
||||
(
|
||||
"PrevSubwordEnd",
|
||||
vec![
|
||||
(1, Range::new(13, 13), Range::new(14, 11)),
|
||||
(1, Range::new(11, 11), Range::new(11, 4)),
|
||||
],
|
||||
),
|
||||
(
|
||||
"prev subword end",
|
||||
vec![
|
||||
(1, Range::new(15, 15), Range::new(16, 13)),
|
||||
(1, Range::new(12, 12), Range::new(13, 5)),
|
||||
],
|
||||
),
|
||||
(
|
||||
"Prev Subword End",
|
||||
vec![
|
||||
(1, Range::new(15, 15), Range::new(16, 13)),
|
||||
(1, Range::new(12, 12), Range::new(13, 5)),
|
||||
],
|
||||
),
|
||||
(
|
||||
"PREV SUBWORD END",
|
||||
vec![
|
||||
(1, Range::new(15, 15), Range::new(16, 13)),
|
||||
(1, Range::new(12, 12), Range::new(13, 5)),
|
||||
],
|
||||
),
|
||||
(
|
||||
"prev_subword_end",
|
||||
vec![
|
||||
(1, Range::new(15, 15), Range::new(16, 13)),
|
||||
(1, Range::new(12, 12), Range::new(13, 5)),
|
||||
],
|
||||
),
|
||||
(
|
||||
"Prev_Subword_End",
|
||||
vec![
|
||||
(1, Range::new(15, 15), Range::new(16, 13)),
|
||||
(1, Range::new(12, 12), Range::new(13, 5)),
|
||||
],
|
||||
),
|
||||
(
|
||||
"PREV_SUBWORD_END",
|
||||
vec![
|
||||
(1, Range::new(15, 15), Range::new(16, 13)),
|
||||
(1, Range::new(12, 12), Range::new(13, 5)),
|
||||
],
|
||||
),
|
||||
(
|
||||
"prev__subword__end",
|
||||
vec![
|
||||
(1, Range::new(17, 17), Range::new(18, 15)),
|
||||
(1, Range::new(13, 13), Range::new(14, 6)),
|
||||
(1, Range::new(14, 14), Range::new(15, 6)),
|
||||
],
|
||||
),
|
||||
(
|
||||
"Prev__Subword__End",
|
||||
vec![
|
||||
(1, Range::new(17, 17), Range::new(18, 15)),
|
||||
(1, Range::new(13, 13), Range::new(14, 6)),
|
||||
(1, Range::new(14, 14), Range::new(15, 6)),
|
||||
],
|
||||
),
|
||||
(
|
||||
"PREV__SUBWORD__END",
|
||||
vec![
|
||||
(1, Range::new(17, 17), Range::new(18, 15)),
|
||||
(1, Range::new(13, 13), Range::new(14, 6)),
|
||||
(1, Range::new(14, 14), Range::new(15, 6)),
|
||||
],
|
||||
),
|
||||
];
|
||||
|
||||
for (sample, scenario) in tests {
|
||||
for (count, begin, expected_end) in scenario.into_iter() {
|
||||
let range = move_prev_sub_word_start(Rope::from(sample).slice(..), begin, count);
|
||||
assert_eq!(range, expected_end, "Case failed: [{}]", sample);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_behaviour_when_moving_to_start_of_previous_long_words() {
|
||||
let tests = [
|
||||
@ -1444,6 +1763,92 @@ fn test_behaviour_when_moving_to_end_of_previous_words() {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_behaviour_when_moving_to_end_of_previous_sub_words() {
|
||||
let tests = [
|
||||
(
|
||||
"PrevSubwordEnd",
|
||||
vec![
|
||||
(1, Range::new(13, 13), Range::new(14, 11)),
|
||||
(1, Range::new(11, 11), Range::new(11, 4)),
|
||||
],
|
||||
),
|
||||
(
|
||||
"prev subword end",
|
||||
vec![
|
||||
(1, Range::new(15, 15), Range::new(16, 12)),
|
||||
(1, Range::new(12, 12), Range::new(12, 4)),
|
||||
],
|
||||
),
|
||||
(
|
||||
"Prev Subword End",
|
||||
vec![
|
||||
(1, Range::new(15, 15), Range::new(16, 12)),
|
||||
(1, Range::new(12, 12), Range::new(12, 4)),
|
||||
],
|
||||
),
|
||||
(
|
||||
"PREV SUBWORD END",
|
||||
vec![
|
||||
(1, Range::new(15, 15), Range::new(16, 12)),
|
||||
(1, Range::new(12, 12), Range::new(12, 4)),
|
||||
],
|
||||
),
|
||||
(
|
||||
"prev_subword_end",
|
||||
vec![
|
||||
(1, Range::new(15, 15), Range::new(16, 12)),
|
||||
(1, Range::new(12, 12), Range::new(12, 4)),
|
||||
],
|
||||
),
|
||||
(
|
||||
"Prev_Subword_End",
|
||||
vec![
|
||||
(1, Range::new(15, 15), Range::new(16, 12)),
|
||||
(1, Range::new(12, 12), Range::new(12, 4)),
|
||||
],
|
||||
),
|
||||
(
|
||||
"PREV_SUBWORD_END",
|
||||
vec![
|
||||
(1, Range::new(15, 15), Range::new(16, 12)),
|
||||
(1, Range::new(12, 12), Range::new(12, 4)),
|
||||
],
|
||||
),
|
||||
(
|
||||
"prev__subword__end",
|
||||
vec![
|
||||
(1, Range::new(17, 17), Range::new(18, 13)),
|
||||
(1, Range::new(13, 13), Range::new(13, 4)),
|
||||
(1, Range::new(14, 14), Range::new(15, 13)),
|
||||
],
|
||||
),
|
||||
(
|
||||
"Prev__Subword__End",
|
||||
vec![
|
||||
(1, Range::new(17, 17), Range::new(18, 13)),
|
||||
(1, Range::new(13, 13), Range::new(13, 4)),
|
||||
(1, Range::new(14, 14), Range::new(15, 13)),
|
||||
],
|
||||
),
|
||||
(
|
||||
"PREV__SUBWORD__END",
|
||||
vec![
|
||||
(1, Range::new(17, 17), Range::new(18, 13)),
|
||||
(1, Range::new(13, 13), Range::new(13, 4)),
|
||||
(1, Range::new(14, 14), Range::new(15, 13)),
|
||||
],
|
||||
),
|
||||
];
|
||||
|
||||
for (sample, scenario) in tests {
|
||||
for (count, begin, expected_end) in scenario.into_iter() {
|
||||
let range = move_prev_sub_word_end(Rope::from(sample).slice(..), begin, count);
|
||||
assert_eq!(range, expected_end, "Case failed: [{}]", sample);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_behaviour_when_moving_to_end_of_next_long_words() {
|
||||
let tests = [
|
||||
|
@ -184,16 +184,16 @@ pub fn map(mut self, changes: &ChangeSet) -> Self {
|
||||
|
||||
let positions_to_map = match self.anchor.cmp(&self.head) {
|
||||
Ordering::Equal => [
|
||||
(&mut self.anchor, Assoc::After),
|
||||
(&mut self.head, Assoc::After),
|
||||
(&mut self.anchor, Assoc::AfterSticky),
|
||||
(&mut self.head, Assoc::AfterSticky),
|
||||
],
|
||||
Ordering::Less => [
|
||||
(&mut self.anchor, Assoc::After),
|
||||
(&mut self.head, Assoc::Before),
|
||||
(&mut self.anchor, Assoc::AfterSticky),
|
||||
(&mut self.head, Assoc::BeforeSticky),
|
||||
],
|
||||
Ordering::Greater => [
|
||||
(&mut self.head, Assoc::After),
|
||||
(&mut self.anchor, Assoc::Before),
|
||||
(&mut self.head, Assoc::AfterSticky),
|
||||
(&mut self.anchor, Assoc::BeforeSticky),
|
||||
],
|
||||
};
|
||||
changes.update_positions(positions_to_map.into_iter());
|
||||
@ -482,16 +482,16 @@ pub fn map_no_normalize(mut self, changes: &ChangeSet) -> Self {
|
||||
range.old_visual_position = None;
|
||||
match range.anchor.cmp(&range.head) {
|
||||
Ordering::Equal => [
|
||||
(&mut range.anchor, Assoc::After),
|
||||
(&mut range.head, Assoc::After),
|
||||
(&mut range.anchor, Assoc::AfterSticky),
|
||||
(&mut range.head, Assoc::AfterSticky),
|
||||
],
|
||||
Ordering::Less => [
|
||||
(&mut range.anchor, Assoc::After),
|
||||
(&mut range.head, Assoc::Before),
|
||||
(&mut range.anchor, Assoc::AfterSticky),
|
||||
(&mut range.head, Assoc::BeforeSticky),
|
||||
],
|
||||
Ordering::Greater => [
|
||||
(&mut range.head, Assoc::After),
|
||||
(&mut range.anchor, Assoc::Before),
|
||||
(&mut range.head, Assoc::AfterSticky),
|
||||
(&mut range.anchor, Assoc::BeforeSticky),
|
||||
],
|
||||
}
|
||||
});
|
||||
|
@ -1431,8 +1431,11 @@ pub fn highlight_iter<'a>(
|
||||
// The `captures` iterator borrows the `Tree` and the `QueryCursor`, which
|
||||
// prevents them from being moved. But both of these values are really just
|
||||
// pointers, so it's actually ok to move them.
|
||||
let cursor_ref =
|
||||
unsafe { mem::transmute::<_, &'static mut QueryCursor>(&mut cursor) };
|
||||
let cursor_ref = unsafe {
|
||||
mem::transmute::<&mut tree_sitter::QueryCursor, &mut tree_sitter::QueryCursor>(
|
||||
&mut cursor,
|
||||
)
|
||||
};
|
||||
|
||||
// if reusing cursors & no range this resets to whole range
|
||||
cursor_ref.set_byte_range(range.clone().unwrap_or(0..usize::MAX));
|
||||
@ -1737,7 +1740,7 @@ fn traverse(point: Point, text: &Tendril) -> Point {
|
||||
}
|
||||
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
use std::{iter, mem, ops, str, usize};
|
||||
use std::{iter, mem, ops, str};
|
||||
use tree_sitter::{
|
||||
Language as Grammar, Node, Parser, Point, Query, QueryCaptures, QueryCursor, QueryError,
|
||||
QueryMatch, Range, TextProvider, Tree,
|
||||
|
@ -204,7 +204,7 @@ fn layer_id_containing_byte_range(&self, start: usize, end: usize) -> LayerId {
|
||||
|
||||
self.injection_ranges[start_idx..]
|
||||
.iter()
|
||||
.take_while(|range| range.start < end)
|
||||
.take_while(|range| range.start < end || range.depth > 1)
|
||||
.find_map(|range| (range.start <= start).then_some(range.layer_id))
|
||||
.unwrap_or(self.root)
|
||||
}
|
||||
|
@ -29,6 +29,12 @@ pub enum Assoc {
|
||||
/// Acts like `Before` if a word character is inserted
|
||||
/// before the position, otherwise acts like `After`
|
||||
BeforeWord,
|
||||
/// Acts like `Before` but if the position is within an exact replacement
|
||||
/// (exact size) the offset to the start of the replacement is kept
|
||||
BeforeSticky,
|
||||
/// Acts like `After` but if the position is within an exact replacement
|
||||
/// (exact size) the offset to the start of the replacement is kept
|
||||
AfterSticky,
|
||||
}
|
||||
|
||||
impl Assoc {
|
||||
@ -40,13 +46,17 @@ fn stay_at_gaps(self) -> bool {
|
||||
fn insert_offset(self, s: &str) -> usize {
|
||||
let chars = s.chars().count();
|
||||
match self {
|
||||
Assoc::After => chars,
|
||||
Assoc::After | Assoc::AfterSticky => chars,
|
||||
Assoc::AfterWord => s.chars().take_while(|&c| char_is_word(c)).count(),
|
||||
// return position before inserted text
|
||||
Assoc::Before => 0,
|
||||
Assoc::Before | Assoc::BeforeSticky => 0,
|
||||
Assoc::BeforeWord => chars - s.chars().rev().take_while(|&c| char_is_word(c)).count(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sticky(self) -> bool {
|
||||
matches!(self, Assoc::BeforeSticky | Assoc::AfterSticky)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, PartialEq, Eq)]
|
||||
@ -456,8 +466,14 @@ macro_rules! map {
|
||||
if pos == old_pos && assoc.stay_at_gaps() {
|
||||
new_pos
|
||||
} else {
|
||||
// place to end of insert
|
||||
new_pos + assoc.insert_offset(s)
|
||||
let ins = assoc.insert_offset(s);
|
||||
// if the deleted and inserted text have the exact same size
|
||||
// keep the relative offset into the new text
|
||||
if *len == ins && assoc.sticky() {
|
||||
new_pos + (pos - old_pos)
|
||||
} else {
|
||||
new_pos + assoc.insert_offset(s)
|
||||
}
|
||||
}
|
||||
}),
|
||||
i
|
||||
|
@ -30,8 +30,8 @@ log = "0.4"
|
||||
# cloning/compiling tree-sitter grammars
|
||||
cc = { version = "1" }
|
||||
threadpool = { version = "1.0" }
|
||||
tempfile = "3.10.1"
|
||||
dunce = "1.0.4"
|
||||
tempfile = "3.12.0"
|
||||
dunce = "1.0.5"
|
||||
|
||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||
libloading = "0.8"
|
||||
|
@ -225,13 +225,16 @@ fn get_name(v: &Value) -> Option<&str> {
|
||||
/// Used as a ceiling dir for LSP root resolution, the filepicker and potentially as a future filewatching root
|
||||
///
|
||||
/// This function starts searching the FS upward from the CWD
|
||||
/// and returns the first directory that contains either `.git` or `.helix`.
|
||||
/// and returns the first directory that contains either `.git`, `.svn` or `.helix`.
|
||||
/// If no workspace was found returns (CWD, true).
|
||||
/// Otherwise (workspace, false) is returned
|
||||
pub fn find_workspace() -> (PathBuf, bool) {
|
||||
let current_dir = current_working_dir();
|
||||
for ancestor in current_dir.ancestors() {
|
||||
if ancestor.join(".git").exists() || ancestor.join(".helix").exists() {
|
||||
if ancestor.join(".git").exists()
|
||||
|| ancestor.join(".svn").exists()
|
||||
|| ancestor.join(".helix").exists()
|
||||
{
|
||||
return (ancestor.to_owned(), false);
|
||||
}
|
||||
}
|
||||
|
176
helix-lsp-types/Cargo.lock
generated
Normal file
176
helix-lsp-types/Cargo.lock
generated
Normal file
@ -0,0 +1,176 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "form_urlencoded"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8"
|
||||
dependencies = [
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6"
|
||||
dependencies = [
|
||||
"unicode-bidi",
|
||||
"unicode-normalization",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc"
|
||||
|
||||
[[package]]
|
||||
name = "lsp-types"
|
||||
version = "0.95.1"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_repr",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.47"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.145"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "728eb6351430bccb993660dfffc5a72f91ccc1295abaa8ce19b27ebe4f75568b"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.145"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "81fa1584d3d1bcacd84c277a0dfe21f5b0f6accf4a23d04d4c6d61f1af522b4c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.86"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41feea4228a6f1cd09ec7a3593a682276702cd67b5273544757dae23c096f074"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_repr"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fe39d9fbb0ebf5eb2c7cb7e2a47e4f462fad1379f1166b8ae49ad9eae89a7ca"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.102"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3fcd952facd492f9be3ef0d0b7032a6e442ee9b361d4acc2b1d0c4aaa5f613a1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec"
|
||||
version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50"
|
||||
dependencies = [
|
||||
"tinyvec_macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec_macros"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-bidi"
|
||||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-normalization"
|
||||
version = "0.1.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921"
|
||||
dependencies = [
|
||||
"tinyvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "2.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643"
|
||||
dependencies = [
|
||||
"form_urlencoded",
|
||||
"idna",
|
||||
"percent-encoding",
|
||||
"serde",
|
||||
]
|
34
helix-lsp-types/Cargo.toml
Normal file
34
helix-lsp-types/Cargo.toml
Normal file
@ -0,0 +1,34 @@
|
||||
[package]
|
||||
name = "helix-lsp-types"
|
||||
version = "0.95.1"
|
||||
authors = [
|
||||
# Original authors
|
||||
"Markus Westerlind <marwes91@gmail.com>",
|
||||
"Bruno Medeiros <bruno.do.medeiros@gmail.com>",
|
||||
# Since forking
|
||||
"Helix contributors"
|
||||
]
|
||||
edition = "2018"
|
||||
description = "Types for interaction with a language server, using VSCode's Language Server Protocol"
|
||||
|
||||
repository = "https://github.com/gluon-lang/lsp-types"
|
||||
documentation = "https://docs.rs/lsp-types"
|
||||
|
||||
readme = "README.md"
|
||||
|
||||
keywords = ["language", "server", "lsp", "vscode", "lsif"]
|
||||
|
||||
license = "MIT"
|
||||
|
||||
[dependencies]
|
||||
bitflags = "2.6.0"
|
||||
serde = { version = "1.0.209", features = ["derive"] }
|
||||
serde_json = "1.0.127"
|
||||
serde_repr = "0.1"
|
||||
url = {version = "2.0.0", features = ["serde"]}
|
||||
|
||||
[features]
|
||||
default = []
|
||||
# Enables proposed LSP extensions.
|
||||
# NOTE: No semver compatibility is guaranteed for types enabled by this feature.
|
||||
proposed = []
|
22
helix-lsp-types/LICENSE
Normal file
22
helix-lsp-types/LICENSE
Normal file
@ -0,0 +1,22 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 Markus Westerlind
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
3
helix-lsp-types/README.md
Normal file
3
helix-lsp-types/README.md
Normal file
@ -0,0 +1,3 @@
|
||||
# Helix's `lsp-types`
|
||||
|
||||
This is a fork of the [`lsp-types`](https://crates.io/crates/lsp-types) crate ([`gluon-lang/lsp-types`](https://github.com/gluon-lang/lsp-types)) taken at version v0.95.1 (commit [3e6daee](https://github.com/gluon-lang/lsp-types/commit/3e6daee771d14db4094a554b8d03e29c310dfcbe)). This fork focuses usability improvements that make the types easier to work with for the Helix codebase. For example the URL type - the `uri` crate at this version of `lsp-types` - will be replaced with a wrapper around a string.
|
127
helix-lsp-types/src/call_hierarchy.rs
Normal file
127
helix-lsp-types/src/call_hierarchy.rs
Normal file
@ -0,0 +1,127 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
use url::Url;
|
||||
|
||||
use crate::{
|
||||
DynamicRegistrationClientCapabilities, PartialResultParams, Range, SymbolKind, SymbolTag,
|
||||
TextDocumentPositionParams, WorkDoneProgressOptions, WorkDoneProgressParams,
|
||||
};
|
||||
|
||||
pub type CallHierarchyClientCapabilities = DynamicRegistrationClientCapabilities;
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize, Copy)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CallHierarchyOptions {
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_options: WorkDoneProgressOptions,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize, Copy)]
|
||||
#[serde(untagged)]
|
||||
pub enum CallHierarchyServerCapability {
|
||||
Simple(bool),
|
||||
Options(CallHierarchyOptions),
|
||||
}
|
||||
|
||||
impl From<CallHierarchyOptions> for CallHierarchyServerCapability {
|
||||
fn from(from: CallHierarchyOptions) -> Self {
|
||||
Self::Options(from)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<bool> for CallHierarchyServerCapability {
|
||||
fn from(from: bool) -> Self {
|
||||
Self::Simple(from)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CallHierarchyPrepareParams {
|
||||
#[serde(flatten)]
|
||||
pub text_document_position_params: TextDocumentPositionParams,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_params: WorkDoneProgressParams,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CallHierarchyItem {
|
||||
/// The name of this item.
|
||||
pub name: String,
|
||||
|
||||
/// The kind of this item.
|
||||
pub kind: SymbolKind,
|
||||
|
||||
/// Tags for this item.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub tags: Option<Vec<SymbolTag>>,
|
||||
|
||||
/// More detail for this item, e.g. the signature of a function.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub detail: Option<String>,
|
||||
|
||||
/// The resource identifier of this item.
|
||||
pub uri: Url,
|
||||
|
||||
/// The range enclosing this symbol not including leading/trailing whitespace but everything else, e.g. comments and code.
|
||||
pub range: Range,
|
||||
|
||||
/// The range that should be selected and revealed when this symbol is being picked, e.g. the name of a function.
|
||||
/// Must be contained by the [`range`](#CallHierarchyItem.range).
|
||||
pub selection_range: Range,
|
||||
|
||||
/// A data entry field that is preserved between a call hierarchy prepare and incoming calls or outgoing calls requests.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub data: Option<Value>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CallHierarchyIncomingCallsParams {
|
||||
pub item: CallHierarchyItem,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_params: WorkDoneProgressParams,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub partial_result_params: PartialResultParams,
|
||||
}
|
||||
|
||||
/// Represents an incoming call, e.g. a caller of a method or constructor.
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CallHierarchyIncomingCall {
|
||||
/// The item that makes the call.
|
||||
pub from: CallHierarchyItem,
|
||||
|
||||
/// The range at which at which the calls appears. This is relative to the caller
|
||||
/// denoted by [`this.from`](#CallHierarchyIncomingCall.from).
|
||||
pub from_ranges: Vec<Range>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CallHierarchyOutgoingCallsParams {
|
||||
pub item: CallHierarchyItem,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_params: WorkDoneProgressParams,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub partial_result_params: PartialResultParams,
|
||||
}
|
||||
|
||||
/// Represents an outgoing call, e.g. calling a getter from a method or a method from a constructor etc.
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CallHierarchyOutgoingCall {
|
||||
/// The item that is called.
|
||||
pub to: CallHierarchyItem,
|
||||
|
||||
/// The range at which this item is called. This is the range relative to the caller, e.g the item
|
||||
/// passed to [`provideCallHierarchyOutgoingCalls`](#CallHierarchyItemProvider.provideCallHierarchyOutgoingCalls)
|
||||
/// and not [`this.to`](#CallHierarchyOutgoingCall.to).
|
||||
pub from_ranges: Vec<Range>,
|
||||
}
|
395
helix-lsp-types/src/code_action.rs
Normal file
395
helix-lsp-types/src/code_action.rs
Normal file
@ -0,0 +1,395 @@
|
||||
use crate::{
|
||||
Command, Diagnostic, PartialResultParams, Range, TextDocumentIdentifier,
|
||||
WorkDoneProgressOptions, WorkDoneProgressParams, WorkspaceEdit,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use serde_json::Value;
|
||||
|
||||
use std::borrow::Cow;
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum CodeActionProviderCapability {
|
||||
Simple(bool),
|
||||
Options(CodeActionOptions),
|
||||
}
|
||||
|
||||
impl From<CodeActionOptions> for CodeActionProviderCapability {
|
||||
fn from(from: CodeActionOptions) -> Self {
|
||||
Self::Options(from)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<bool> for CodeActionProviderCapability {
|
||||
fn from(from: bool) -> Self {
|
||||
Self::Simple(from)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CodeActionClientCapabilities {
|
||||
///
|
||||
/// This capability supports dynamic registration.
|
||||
///
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub dynamic_registration: Option<bool>,
|
||||
|
||||
/// The client support code action literals as a valid
|
||||
/// response of the `textDocument/codeAction` request.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub code_action_literal_support: Option<CodeActionLiteralSupport>,
|
||||
|
||||
/// Whether code action supports the `isPreferred` property.
|
||||
///
|
||||
/// @since 3.15.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub is_preferred_support: Option<bool>,
|
||||
|
||||
/// Whether code action supports the `disabled` property.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub disabled_support: Option<bool>,
|
||||
|
||||
/// Whether code action supports the `data` property which is
|
||||
/// preserved between a `textDocument/codeAction` and a
|
||||
/// `codeAction/resolve` request.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub data_support: Option<bool>,
|
||||
|
||||
/// Whether the client supports resolving additional code action
|
||||
/// properties via a separate `codeAction/resolve` request.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub resolve_support: Option<CodeActionCapabilityResolveSupport>,
|
||||
|
||||
/// Whether the client honors the change annotations in
|
||||
/// text edits and resource operations returned via the
|
||||
/// `CodeAction#edit` property by for example presenting
|
||||
/// the workspace edit in the user interface and asking
|
||||
/// for confirmation.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub honors_change_annotations: Option<bool>,
|
||||
}
|
||||
|
||||
/// Whether the client supports resolving additional code action
|
||||
/// properties via a separate `codeAction/resolve` request.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CodeActionCapabilityResolveSupport {
|
||||
/// The properties that a client can resolve lazily.
|
||||
pub properties: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CodeActionLiteralSupport {
|
||||
/// The code action kind is support with the following value set.
|
||||
pub code_action_kind: CodeActionKindLiteralSupport,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CodeActionKindLiteralSupport {
|
||||
/// The code action kind values the client supports. When this
|
||||
/// property exists the client also guarantees that it will
|
||||
/// handle values outside its set gracefully and falls back
|
||||
/// to a default value when unknown.
|
||||
pub value_set: Vec<String>,
|
||||
}
|
||||
|
||||
/// Params for the CodeActionRequest
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CodeActionParams {
|
||||
/// The document in which the command was invoked.
|
||||
pub text_document: TextDocumentIdentifier,
|
||||
|
||||
/// The range for which the command was invoked.
|
||||
pub range: Range,
|
||||
|
||||
/// Context carrying additional information.
|
||||
pub context: CodeActionContext,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_params: WorkDoneProgressParams,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub partial_result_params: PartialResultParams,
|
||||
}
|
||||
|
||||
/// response for CodeActionRequest
|
||||
pub type CodeActionResponse = Vec<CodeActionOrCommand>;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum CodeActionOrCommand {
|
||||
Command(Command),
|
||||
CodeAction(CodeAction),
|
||||
}
|
||||
|
||||
impl From<Command> for CodeActionOrCommand {
|
||||
fn from(command: Command) -> Self {
|
||||
CodeActionOrCommand::Command(command)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CodeAction> for CodeActionOrCommand {
|
||||
fn from(action: CodeAction) -> Self {
|
||||
CodeActionOrCommand::CodeAction(action)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Hash, PartialOrd, Clone, Deserialize, Serialize)]
|
||||
pub struct CodeActionKind(Cow<'static, str>);
|
||||
|
||||
impl CodeActionKind {
|
||||
/// Empty kind.
|
||||
pub const EMPTY: CodeActionKind = CodeActionKind::new("");
|
||||
|
||||
/// Base kind for quickfix actions: 'quickfix'
|
||||
pub const QUICKFIX: CodeActionKind = CodeActionKind::new("quickfix");
|
||||
|
||||
/// Base kind for refactoring actions: 'refactor'
|
||||
pub const REFACTOR: CodeActionKind = CodeActionKind::new("refactor");
|
||||
|
||||
/// Base kind for refactoring extraction actions: 'refactor.extract'
|
||||
///
|
||||
/// Example extract actions:
|
||||
///
|
||||
/// - Extract method
|
||||
/// - Extract function
|
||||
/// - Extract variable
|
||||
/// - Extract interface from class
|
||||
/// - ...
|
||||
pub const REFACTOR_EXTRACT: CodeActionKind = CodeActionKind::new("refactor.extract");
|
||||
|
||||
/// Base kind for refactoring inline actions: 'refactor.inline'
|
||||
///
|
||||
/// Example inline actions:
|
||||
///
|
||||
/// - Inline function
|
||||
/// - Inline variable
|
||||
/// - Inline constant
|
||||
/// - ...
|
||||
pub const REFACTOR_INLINE: CodeActionKind = CodeActionKind::new("refactor.inline");
|
||||
|
||||
/// Base kind for refactoring rewrite actions: 'refactor.rewrite'
|
||||
///
|
||||
/// Example rewrite actions:
|
||||
///
|
||||
/// - Convert JavaScript function to class
|
||||
/// - Add or remove parameter
|
||||
/// - Encapsulate field
|
||||
/// - Make method static
|
||||
/// - Move method to base class
|
||||
/// - ...
|
||||
pub const REFACTOR_REWRITE: CodeActionKind = CodeActionKind::new("refactor.rewrite");
|
||||
|
||||
/// Base kind for source actions: `source`
|
||||
///
|
||||
/// Source code actions apply to the entire file.
|
||||
pub const SOURCE: CodeActionKind = CodeActionKind::new("source");
|
||||
|
||||
/// Base kind for an organize imports source action: `source.organizeImports`
|
||||
pub const SOURCE_ORGANIZE_IMPORTS: CodeActionKind =
|
||||
CodeActionKind::new("source.organizeImports");
|
||||
|
||||
/// Base kind for a 'fix all' source action: `source.fixAll`.
|
||||
///
|
||||
/// 'Fix all' actions automatically fix errors that have a clear fix that
|
||||
/// do not require user input. They should not suppress errors or perform
|
||||
/// unsafe fixes such as generating new types or classes.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
pub const SOURCE_FIX_ALL: CodeActionKind = CodeActionKind::new("source.fixAll");
|
||||
|
||||
pub const fn new(tag: &'static str) -> Self {
|
||||
CodeActionKind(Cow::Borrowed(tag))
|
||||
}
|
||||
|
||||
pub fn as_str(&self) -> &str {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for CodeActionKind {
|
||||
fn from(from: String) -> Self {
|
||||
CodeActionKind(Cow::from(from))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'static str> for CodeActionKind {
|
||||
fn from(from: &'static str) -> Self {
|
||||
CodeActionKind::new(from)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CodeAction {
|
||||
/// A short, human-readable, title for this code action.
|
||||
pub title: String,
|
||||
|
||||
/// The kind of the code action.
|
||||
/// Used to filter code actions.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub kind: Option<CodeActionKind>,
|
||||
|
||||
/// The diagnostics that this code action resolves.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub diagnostics: Option<Vec<Diagnostic>>,
|
||||
|
||||
/// The workspace edit this code action performs.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub edit: Option<WorkspaceEdit>,
|
||||
|
||||
/// A command this code action executes. If a code action
|
||||
/// provides an edit and a command, first the edit is
|
||||
/// executed and then the command.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub command: Option<Command>,
|
||||
|
||||
/// Marks this as a preferred action. Preferred actions are used by the `auto fix` command and can be targeted
|
||||
/// by keybindings.
|
||||
/// A quick fix should be marked preferred if it properly addresses the underlying error.
|
||||
/// A refactoring should be marked preferred if it is the most reasonable choice of actions to take.
|
||||
///
|
||||
/// @since 3.15.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub is_preferred: Option<bool>,
|
||||
|
||||
/// Marks that the code action cannot currently be applied.
|
||||
///
|
||||
/// Clients should follow the following guidelines regarding disabled code actions:
|
||||
///
|
||||
/// - Disabled code actions are not shown in automatic
|
||||
/// [lightbulb](https://code.visualstudio.com/docs/editor/editingevolved#_code-action)
|
||||
/// code action menu.
|
||||
///
|
||||
/// - Disabled actions are shown as faded out in the code action menu when the user request
|
||||
/// a more specific type of code action, such as refactorings.
|
||||
///
|
||||
/// - If the user has a keybinding that auto applies a code action and only a disabled code
|
||||
/// actions are returned, the client should show the user an error message with `reason`
|
||||
/// in the editor.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub disabled: Option<CodeActionDisabled>,
|
||||
|
||||
/// A data entry field that is preserved on a code action between
|
||||
/// a `textDocument/codeAction` and a `codeAction/resolve` request.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub data: Option<Value>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CodeActionDisabled {
|
||||
/// Human readable description of why the code action is currently disabled.
|
||||
///
|
||||
/// This is displayed in the code actions UI.
|
||||
pub reason: String,
|
||||
}
|
||||
|
||||
/// The reason why code actions were requested.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Eq, PartialEq, Clone, Copy, Deserialize, Serialize)]
|
||||
#[serde(transparent)]
|
||||
pub struct CodeActionTriggerKind(i32);
|
||||
lsp_enum! {
|
||||
impl CodeActionTriggerKind {
|
||||
/// Code actions were explicitly requested by the user or by an extension.
|
||||
pub const INVOKED: CodeActionTriggerKind = CodeActionTriggerKind(1);
|
||||
|
||||
/// Code actions were requested automatically.
|
||||
///
|
||||
/// This typically happens when current selection in a file changes, but can
|
||||
/// also be triggered when file content changes.
|
||||
pub const AUTOMATIC: CodeActionTriggerKind = CodeActionTriggerKind(2);
|
||||
}
|
||||
}
|
||||
|
||||
/// Contains additional diagnostic information about the context in which
|
||||
/// a code action is run.
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CodeActionContext {
|
||||
/// An array of diagnostics.
|
||||
pub diagnostics: Vec<Diagnostic>,
|
||||
|
||||
/// Requested kind of actions to return.
|
||||
///
|
||||
/// Actions not of this kind are filtered out by the client before being shown. So servers
|
||||
/// can omit computing them.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub only: Option<Vec<CodeActionKind>>,
|
||||
|
||||
/// The reason why code actions were requested.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub trigger_kind: Option<CodeActionTriggerKind>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize, Default)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CodeActionOptions {
|
||||
/// CodeActionKinds that this server may return.
|
||||
///
|
||||
/// The list of kinds may be generic, such as `CodeActionKind.Refactor`, or the server
|
||||
/// may list out every specific kind they provide.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub code_action_kinds: Option<Vec<CodeActionKind>>,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_options: WorkDoneProgressOptions,
|
||||
|
||||
/// The server provides support to resolve additional
|
||||
/// information for a code action.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub resolve_provider: Option<bool>,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::tests::test_serialization;
|
||||
|
||||
#[test]
|
||||
fn test_code_action_response() {
|
||||
test_serialization(
|
||||
&vec![
|
||||
CodeActionOrCommand::Command(Command {
|
||||
title: "title".to_string(),
|
||||
command: "command".to_string(),
|
||||
arguments: None,
|
||||
}),
|
||||
CodeActionOrCommand::CodeAction(CodeAction {
|
||||
title: "title".to_string(),
|
||||
kind: Some(CodeActionKind::QUICKFIX),
|
||||
command: None,
|
||||
diagnostics: None,
|
||||
edit: None,
|
||||
is_preferred: None,
|
||||
..CodeAction::default()
|
||||
}),
|
||||
],
|
||||
r#"[{"title":"title","command":"command"},{"title":"title","kind":"quickfix"}]"#,
|
||||
)
|
||||
}
|
||||
}
|
66
helix-lsp-types/src/code_lens.rs
Normal file
66
helix-lsp-types/src/code_lens.rs
Normal file
@ -0,0 +1,66 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::{
|
||||
Command, DynamicRegistrationClientCapabilities, PartialResultParams, Range,
|
||||
TextDocumentIdentifier, WorkDoneProgressParams,
|
||||
};
|
||||
|
||||
pub type CodeLensClientCapabilities = DynamicRegistrationClientCapabilities;
|
||||
|
||||
/// Code Lens options.
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize, Copy)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CodeLensOptions {
|
||||
/// Code lens has a resolve provider as well.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub resolve_provider: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CodeLensParams {
|
||||
/// The document to request code lens for.
|
||||
pub text_document: TextDocumentIdentifier,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_params: WorkDoneProgressParams,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub partial_result_params: PartialResultParams,
|
||||
}
|
||||
|
||||
/// A code lens represents a command that should be shown along with
|
||||
/// source text, like the number of references, a way to run tests, etc.
|
||||
///
|
||||
/// A code lens is _unresolved_ when no command is associated to it. For performance
|
||||
/// reasons the creation of a code lens and resolving should be done in two stages.
|
||||
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CodeLens {
|
||||
/// The range in which this code lens is valid. Should only span a single line.
|
||||
pub range: Range,
|
||||
|
||||
/// The command this code lens represents.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub command: Option<Command>,
|
||||
|
||||
/// A data entry field that is preserved on a code lens item between
|
||||
/// a code lens and a code lens resolve request.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub data: Option<Value>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CodeLensWorkspaceClientCapabilities {
|
||||
/// Whether the client implementation supports a refresh request sent from the
|
||||
/// server to the client.
|
||||
///
|
||||
/// Note that this event is global and will force the client to refresh all
|
||||
/// code lenses currently shown. It should be used with absolute care and is
|
||||
/// useful for situation where a server for example detect a project wide
|
||||
/// change that requires such a calculation.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub refresh_support: Option<bool>,
|
||||
}
|
122
helix-lsp-types/src/color.rs
Normal file
122
helix-lsp-types/src/color.rs
Normal file
@ -0,0 +1,122 @@
|
||||
use crate::{
|
||||
DocumentSelector, DynamicRegistrationClientCapabilities, PartialResultParams, Range,
|
||||
TextDocumentIdentifier, TextEdit, WorkDoneProgressParams,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub type DocumentColorClientCapabilities = DynamicRegistrationClientCapabilities;
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ColorProviderOptions {}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct StaticTextDocumentColorProviderOptions {
|
||||
/// A document selector to identify the scope of the registration. If set to null
|
||||
/// the document selector provided on the client side will be used.
|
||||
pub document_selector: Option<DocumentSelector>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub id: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum ColorProviderCapability {
|
||||
Simple(bool),
|
||||
ColorProvider(ColorProviderOptions),
|
||||
Options(StaticTextDocumentColorProviderOptions),
|
||||
}
|
||||
|
||||
impl From<ColorProviderOptions> for ColorProviderCapability {
|
||||
fn from(from: ColorProviderOptions) -> Self {
|
||||
Self::ColorProvider(from)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<StaticTextDocumentColorProviderOptions> for ColorProviderCapability {
|
||||
fn from(from: StaticTextDocumentColorProviderOptions) -> Self {
|
||||
Self::Options(from)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<bool> for ColorProviderCapability {
|
||||
fn from(from: bool) -> Self {
|
||||
Self::Simple(from)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DocumentColorParams {
|
||||
/// The text document
|
||||
pub text_document: TextDocumentIdentifier,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_params: WorkDoneProgressParams,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub partial_result_params: PartialResultParams,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ColorInformation {
|
||||
/// The range in the document where this color appears.
|
||||
pub range: Range,
|
||||
/// The actual color value for this color range.
|
||||
pub color: Color,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize, Copy)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Color {
|
||||
/// The red component of this color in the range [0-1].
|
||||
pub red: f32,
|
||||
/// The green component of this color in the range [0-1].
|
||||
pub green: f32,
|
||||
/// The blue component of this color in the range [0-1].
|
||||
pub blue: f32,
|
||||
/// The alpha component of this color in the range [0-1].
|
||||
pub alpha: f32,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ColorPresentationParams {
|
||||
/// The text document.
|
||||
pub text_document: TextDocumentIdentifier,
|
||||
|
||||
/// The color information to request presentations for.
|
||||
pub color: Color,
|
||||
|
||||
/// The range where the color would be inserted. Serves as a context.
|
||||
pub range: Range,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_params: WorkDoneProgressParams,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub partial_result_params: PartialResultParams,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Deserialize, Serialize, Default, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ColorPresentation {
|
||||
/// The label of this color presentation. It will be shown on the color
|
||||
/// picker header. By default this is also the text that is inserted when selecting
|
||||
/// this color presentation.
|
||||
pub label: String,
|
||||
|
||||
/// An [edit](#TextEdit) which is applied to a document when selecting
|
||||
/// this presentation for the color. When `falsy` the [label](#ColorPresentation.label)
|
||||
/// is used.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub text_edit: Option<TextEdit>,
|
||||
|
||||
/// An optional array of additional [text edits](#TextEdit) that are applied when
|
||||
/// selecting this color presentation. Edits must not overlap with the main [edit](#ColorPresentation.textEdit) nor with themselves.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub additional_text_edits: Option<Vec<TextEdit>>,
|
||||
}
|
622
helix-lsp-types/src/completion.rs
Normal file
622
helix-lsp-types/src/completion.rs
Normal file
@ -0,0 +1,622 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
Command, Documentation, MarkupKind, PartialResultParams, TagSupport,
|
||||
TextDocumentPositionParams, TextDocumentRegistrationOptions, TextEdit, WorkDoneProgressOptions,
|
||||
WorkDoneProgressParams,
|
||||
};
|
||||
|
||||
use crate::Range;
|
||||
use serde_json::Value;
|
||||
use std::fmt::Debug;
|
||||
|
||||
/// Defines how to interpret the insert text in a completion item
|
||||
#[derive(Eq, PartialEq, Clone, Copy, Serialize, Deserialize)]
|
||||
#[serde(transparent)]
|
||||
pub struct InsertTextFormat(i32);
|
||||
lsp_enum! {
|
||||
impl InsertTextFormat {
|
||||
pub const PLAIN_TEXT: InsertTextFormat = InsertTextFormat(1);
|
||||
pub const SNIPPET: InsertTextFormat = InsertTextFormat(2);
|
||||
}
|
||||
}
|
||||
|
||||
/// The kind of a completion entry.
|
||||
#[derive(Eq, PartialEq, Clone, Copy, Serialize, Deserialize)]
|
||||
#[serde(transparent)]
|
||||
pub struct CompletionItemKind(i32);
|
||||
lsp_enum! {
|
||||
impl CompletionItemKind {
|
||||
pub const TEXT: CompletionItemKind = CompletionItemKind(1);
|
||||
pub const METHOD: CompletionItemKind = CompletionItemKind(2);
|
||||
pub const FUNCTION: CompletionItemKind = CompletionItemKind(3);
|
||||
pub const CONSTRUCTOR: CompletionItemKind = CompletionItemKind(4);
|
||||
pub const FIELD: CompletionItemKind = CompletionItemKind(5);
|
||||
pub const VARIABLE: CompletionItemKind = CompletionItemKind(6);
|
||||
pub const CLASS: CompletionItemKind = CompletionItemKind(7);
|
||||
pub const INTERFACE: CompletionItemKind = CompletionItemKind(8);
|
||||
pub const MODULE: CompletionItemKind = CompletionItemKind(9);
|
||||
pub const PROPERTY: CompletionItemKind = CompletionItemKind(10);
|
||||
pub const UNIT: CompletionItemKind = CompletionItemKind(11);
|
||||
pub const VALUE: CompletionItemKind = CompletionItemKind(12);
|
||||
pub const ENUM: CompletionItemKind = CompletionItemKind(13);
|
||||
pub const KEYWORD: CompletionItemKind = CompletionItemKind(14);
|
||||
pub const SNIPPET: CompletionItemKind = CompletionItemKind(15);
|
||||
pub const COLOR: CompletionItemKind = CompletionItemKind(16);
|
||||
pub const FILE: CompletionItemKind = CompletionItemKind(17);
|
||||
pub const REFERENCE: CompletionItemKind = CompletionItemKind(18);
|
||||
pub const FOLDER: CompletionItemKind = CompletionItemKind(19);
|
||||
pub const ENUM_MEMBER: CompletionItemKind = CompletionItemKind(20);
|
||||
pub const CONSTANT: CompletionItemKind = CompletionItemKind(21);
|
||||
pub const STRUCT: CompletionItemKind = CompletionItemKind(22);
|
||||
pub const EVENT: CompletionItemKind = CompletionItemKind(23);
|
||||
pub const OPERATOR: CompletionItemKind = CompletionItemKind(24);
|
||||
pub const TYPE_PARAMETER: CompletionItemKind = CompletionItemKind(25);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CompletionItemCapability {
|
||||
/// Client supports snippets as insert text.
|
||||
///
|
||||
/// A snippet can define tab stops and placeholders with `$1`, `$2`
|
||||
/// and `${3:foo}`. `$0` defines the final tab stop, it defaults to
|
||||
/// the end of the snippet. Placeholders with equal identifiers are linked,
|
||||
/// that is typing in one will update others too.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub snippet_support: Option<bool>,
|
||||
|
||||
/// Client supports commit characters on a completion item.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub commit_characters_support: Option<bool>,
|
||||
|
||||
/// Client supports the follow content formats for the documentation
|
||||
/// property. The order describes the preferred format of the client.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub documentation_format: Option<Vec<MarkupKind>>,
|
||||
|
||||
/// Client supports the deprecated property on a completion item.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub deprecated_support: Option<bool>,
|
||||
|
||||
/// Client supports the preselect property on a completion item.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub preselect_support: Option<bool>,
|
||||
|
||||
/// Client supports the tag property on a completion item. Clients supporting
|
||||
/// tags have to handle unknown tags gracefully. Clients especially need to
|
||||
/// preserve unknown tags when sending a completion item back to the server in
|
||||
/// a resolve call.
|
||||
#[serde(
|
||||
default,
|
||||
skip_serializing_if = "Option::is_none",
|
||||
deserialize_with = "TagSupport::deserialize_compat"
|
||||
)]
|
||||
pub tag_support: Option<TagSupport<CompletionItemTag>>,
|
||||
|
||||
/// Client support insert replace edit to control different behavior if a
|
||||
/// completion item is inserted in the text or should replace text.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub insert_replace_support: Option<bool>,
|
||||
|
||||
/// Indicates which properties a client can resolve lazily on a completion
|
||||
/// item. Before version 3.16.0 only the predefined properties `documentation`
|
||||
/// and `details` could be resolved lazily.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub resolve_support: Option<CompletionItemCapabilityResolveSupport>,
|
||||
|
||||
/// The client supports the `insertTextMode` property on
|
||||
/// a completion item to override the whitespace handling mode
|
||||
/// as defined by the client.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub insert_text_mode_support: Option<InsertTextModeSupport>,
|
||||
|
||||
/// The client has support for completion item label
|
||||
/// details (see also `CompletionItemLabelDetails`).
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub label_details_support: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CompletionItemCapabilityResolveSupport {
|
||||
/// The properties that a client can resolve lazily.
|
||||
pub properties: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct InsertTextModeSupport {
|
||||
pub value_set: Vec<InsertTextMode>,
|
||||
}
|
||||
|
||||
/// How whitespace and indentation is handled during completion
|
||||
/// item insertion.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[derive(Eq, PartialEq, Clone, Copy, Serialize, Deserialize)]
|
||||
#[serde(transparent)]
|
||||
pub struct InsertTextMode(i32);
|
||||
lsp_enum! {
|
||||
impl InsertTextMode {
|
||||
/// The insertion or replace strings is taken as it is. If the
|
||||
/// value is multi line the lines below the cursor will be
|
||||
/// inserted using the indentation defined in the string value.
|
||||
/// The client will not apply any kind of adjustments to the
|
||||
/// string.
|
||||
pub const AS_IS: InsertTextMode = InsertTextMode(1);
|
||||
|
||||
/// The editor adjusts leading whitespace of new lines so that
|
||||
/// they match the indentation up to the cursor of the line for
|
||||
/// which the item is accepted.
|
||||
///
|
||||
/// Consider a line like this: `<2tabs><cursor><3tabs>foo`. Accepting a
|
||||
/// multi line completion item is indented using 2 tabs all
|
||||
/// following lines inserted will be indented using 2 tabs as well.
|
||||
pub const ADJUST_INDENTATION: InsertTextMode = InsertTextMode(2);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(transparent)]
|
||||
pub struct CompletionItemTag(i32);
|
||||
lsp_enum! {
|
||||
impl CompletionItemTag {
|
||||
pub const DEPRECATED: CompletionItemTag = CompletionItemTag(1);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CompletionItemKindCapability {
|
||||
/// The completion item kind values the client supports. When this
|
||||
/// property exists the client also guarantees that it will
|
||||
/// handle values outside its set gracefully and falls back
|
||||
/// to a default value when unknown.
|
||||
///
|
||||
/// If this property is not present the client only supports
|
||||
/// the completion items kinds from `Text` to `Reference` as defined in
|
||||
/// the initial version of the protocol.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub value_set: Option<Vec<CompletionItemKind>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CompletionListCapability {
|
||||
/// The client supports the following itemDefaults on
|
||||
/// a completion list.
|
||||
///
|
||||
/// The value lists the supported property names of the
|
||||
/// `CompletionList.itemDefaults` object. If omitted
|
||||
/// no properties are supported.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub item_defaults: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CompletionClientCapabilities {
|
||||
/// Whether completion supports dynamic registration.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub dynamic_registration: Option<bool>,
|
||||
|
||||
/// The client supports the following `CompletionItem` specific
|
||||
/// capabilities.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub completion_item: Option<CompletionItemCapability>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub completion_item_kind: Option<CompletionItemKindCapability>,
|
||||
|
||||
/// The client supports to send additional context information for a
|
||||
/// `textDocument/completion` request.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub context_support: Option<bool>,
|
||||
|
||||
/// The client's default when the completion item doesn't provide a
|
||||
/// `insertTextMode` property.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub insert_text_mode: Option<InsertTextMode>,
|
||||
|
||||
/// The client supports the following `CompletionList` specific
|
||||
/// capabilities.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub completion_list: Option<CompletionListCapability>,
|
||||
}
|
||||
|
||||
/// A special text edit to provide an insert and a replace operation.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct InsertReplaceEdit {
|
||||
/// The string to be inserted.
|
||||
pub new_text: String,
|
||||
|
||||
/// The range if the insert is requested
|
||||
pub insert: Range,
|
||||
|
||||
/// The range if the replace is requested.
|
||||
pub replace: Range,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum CompletionTextEdit {
|
||||
Edit(TextEdit),
|
||||
InsertAndReplace(InsertReplaceEdit),
|
||||
}
|
||||
|
||||
impl From<TextEdit> for CompletionTextEdit {
|
||||
fn from(edit: TextEdit) -> Self {
|
||||
CompletionTextEdit::Edit(edit)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<InsertReplaceEdit> for CompletionTextEdit {
|
||||
fn from(edit: InsertReplaceEdit) -> Self {
|
||||
CompletionTextEdit::InsertAndReplace(edit)
|
||||
}
|
||||
}
|
||||
|
||||
/// Completion options.
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CompletionOptions {
|
||||
/// The server provides support to resolve additional information for a completion item.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub resolve_provider: Option<bool>,
|
||||
|
||||
/// Most tools trigger completion request automatically without explicitly
|
||||
/// requesting it using a keyboard shortcut (e.g. Ctrl+Space). Typically they
|
||||
/// do so when the user starts to type an identifier. For example if the user
|
||||
/// types `c` in a JavaScript file code complete will automatically pop up
|
||||
/// present `console` besides others as a completion item. Characters that
|
||||
/// make up identifiers don't need to be listed here.
|
||||
///
|
||||
/// If code complete should automatically be trigger on characters not being
|
||||
/// valid inside an identifier (for example `.` in JavaScript) list them in
|
||||
/// `triggerCharacters`.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub trigger_characters: Option<Vec<String>>,
|
||||
|
||||
/// The list of all possible characters that commit a completion. This field
|
||||
/// can be used if clients don't support individual commit characters per
|
||||
/// completion item. See client capability
|
||||
/// `completion.completionItem.commitCharactersSupport`.
|
||||
///
|
||||
/// If a server provides both `allCommitCharacters` and commit characters on
|
||||
/// an individual completion item the ones on the completion item win.
|
||||
///
|
||||
/// @since 3.2.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub all_commit_characters: Option<Vec<String>>,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_options: WorkDoneProgressOptions,
|
||||
|
||||
/// The server supports the following `CompletionItem` specific
|
||||
/// capabilities.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub completion_item: Option<CompletionOptionsCompletionItem>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CompletionOptionsCompletionItem {
|
||||
/// The server has support for completion item label
|
||||
/// details (see also `CompletionItemLabelDetails`) when receiving
|
||||
/// a completion item in a resolve call.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub label_details_support: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
|
||||
pub struct CompletionRegistrationOptions {
|
||||
#[serde(flatten)]
|
||||
pub text_document_registration_options: TextDocumentRegistrationOptions,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub completion_options: CompletionOptions,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum CompletionResponse {
|
||||
Array(Vec<CompletionItem>),
|
||||
List(CompletionList),
|
||||
}
|
||||
|
||||
impl From<Vec<CompletionItem>> for CompletionResponse {
|
||||
fn from(items: Vec<CompletionItem>) -> Self {
|
||||
CompletionResponse::Array(items)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CompletionList> for CompletionResponse {
|
||||
fn from(list: CompletionList) -> Self {
|
||||
CompletionResponse::List(list)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CompletionParams {
|
||||
// This field was "mixed-in" from TextDocumentPositionParams
|
||||
#[serde(flatten)]
|
||||
pub text_document_position: TextDocumentPositionParams,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_params: WorkDoneProgressParams,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub partial_result_params: PartialResultParams,
|
||||
|
||||
// CompletionParams properties:
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub context: Option<CompletionContext>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CompletionContext {
|
||||
/// How the completion was triggered.
|
||||
pub trigger_kind: CompletionTriggerKind,
|
||||
|
||||
/// The trigger character (a single character) that has trigger code complete.
|
||||
/// Is undefined if `triggerKind !== CompletionTriggerKind.TriggerCharacter`
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub trigger_character: Option<String>,
|
||||
}
|
||||
|
||||
/// How a completion was triggered.
|
||||
#[derive(Eq, PartialEq, Clone, Copy, Deserialize, Serialize)]
|
||||
#[serde(transparent)]
|
||||
pub struct CompletionTriggerKind(i32);
|
||||
lsp_enum! {
|
||||
impl CompletionTriggerKind {
|
||||
pub const INVOKED: CompletionTriggerKind = CompletionTriggerKind(1);
|
||||
pub const TRIGGER_CHARACTER: CompletionTriggerKind = CompletionTriggerKind(2);
|
||||
pub const TRIGGER_FOR_INCOMPLETE_COMPLETIONS: CompletionTriggerKind = CompletionTriggerKind(3);
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a collection of [completion items](#CompletionItem) to be presented
|
||||
/// in the editor.
|
||||
#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CompletionList {
|
||||
/// This list it not complete. Further typing should result in recomputing
|
||||
/// this list.
|
||||
pub is_incomplete: bool,
|
||||
|
||||
/// The completion items.
|
||||
pub items: Vec<CompletionItem>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Default, Deserialize, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CompletionItem {
|
||||
/// The label of this completion item. By default
|
||||
/// also the text that is inserted when selecting
|
||||
/// this completion.
|
||||
pub label: String,
|
||||
|
||||
/// Additional details for the label
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub label_details: Option<CompletionItemLabelDetails>,
|
||||
|
||||
/// The kind of this completion item. Based of the kind
|
||||
/// an icon is chosen by the editor.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub kind: Option<CompletionItemKind>,
|
||||
|
||||
/// A human-readable string with additional information
|
||||
/// about this item, like type or symbol information.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub detail: Option<String>,
|
||||
|
||||
/// A human-readable string that represents a doc-comment.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub documentation: Option<Documentation>,
|
||||
|
||||
/// Indicates if this item is deprecated.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub deprecated: Option<bool>,
|
||||
|
||||
/// Select this item when showing.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub preselect: Option<bool>,
|
||||
|
||||
/// A string that should be used when comparing this item
|
||||
/// with other items. When `falsy` the label is used
|
||||
/// as the sort text for this item.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub sort_text: Option<String>,
|
||||
|
||||
/// A string that should be used when filtering a set of
|
||||
/// completion items. When `falsy` the label is used as the
|
||||
/// filter text for this item.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub filter_text: Option<String>,
|
||||
|
||||
/// A string that should be inserted into a document when selecting
|
||||
/// this completion. When `falsy` the label is used as the insert text
|
||||
/// for this item.
|
||||
///
|
||||
/// The `insertText` is subject to interpretation by the client side.
|
||||
/// Some tools might not take the string literally. For example
|
||||
/// VS Code when code complete is requested in this example
|
||||
/// `con<cursor position>` and a completion item with an `insertText` of
|
||||
/// `console` is provided it will only insert `sole`. Therefore it is
|
||||
/// recommended to use `textEdit` instead since it avoids additional client
|
||||
/// side interpretation.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub insert_text: Option<String>,
|
||||
|
||||
/// The format of the insert text. The format applies to both the `insertText` property
|
||||
/// and the `newText` property of a provided `textEdit`. If omitted defaults to `InsertTextFormat.PlainText`.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub insert_text_format: Option<InsertTextFormat>,
|
||||
|
||||
/// How whitespace and indentation is handled during completion
|
||||
/// item insertion. If not provided the client's default value depends on
|
||||
/// the `textDocument.completion.insertTextMode` client capability.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
/// @since 3.17.0 - support for `textDocument.completion.insertTextMode`
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub insert_text_mode: Option<InsertTextMode>,
|
||||
|
||||
/// An edit which is applied to a document when selecting
|
||||
/// this completion. When an edit is provided the value of
|
||||
/// insertText is ignored.
|
||||
///
|
||||
/// Most editors support two different operation when accepting a completion item. One is to insert a
|
||||
|
||||
/// completion text and the other is to replace an existing text with a completion text. Since this can
|
||||
/// usually not predetermined by a server it can report both ranges. Clients need to signal support for
|
||||
/// `InsertReplaceEdits` via the `textDocument.completion.insertReplaceSupport` client capability
|
||||
/// property.
|
||||
///
|
||||
/// *Note 1:* The text edit's range as well as both ranges from a insert replace edit must be a
|
||||
/// [single line] and they must contain the position at which completion has been requested.
|
||||
/// *Note 2:* If an `InsertReplaceEdit` is returned the edit's insert range must be a prefix of
|
||||
/// the edit's replace range, that means it must be contained and starting at the same position.
|
||||
///
|
||||
/// @since 3.16.0 additional type `InsertReplaceEdit`
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub text_edit: Option<CompletionTextEdit>,
|
||||
|
||||
/// An optional array of additional text edits that are applied when
|
||||
/// selecting this completion. Edits must not overlap with the main edit
|
||||
/// nor with themselves.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub additional_text_edits: Option<Vec<TextEdit>>,
|
||||
|
||||
/// An optional command that is executed *after* inserting this completion. *Note* that
|
||||
/// additional modifications to the current document should be described with the
|
||||
/// additionalTextEdits-property.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub command: Option<Command>,
|
||||
|
||||
/// An optional set of characters that when pressed while this completion is
|
||||
/// active will accept it first and then type that character. *Note* that all
|
||||
/// commit characters should have `length=1` and that superfluous characters
|
||||
/// will be ignored.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub commit_characters: Option<Vec<String>>,
|
||||
|
||||
/// An data entry field that is preserved on a completion item between
|
||||
/// a completion and a completion resolve request.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub data: Option<Value>,
|
||||
|
||||
/// Tags for this completion item.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub tags: Option<Vec<CompletionItemTag>>,
|
||||
}
|
||||
|
||||
impl CompletionItem {
|
||||
/// Create a CompletionItem with the minimum possible info (label and detail).
|
||||
pub fn new_simple(label: String, detail: String) -> CompletionItem {
|
||||
CompletionItem {
|
||||
label,
|
||||
detail: Some(detail),
|
||||
..Self::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Additional details for a completion item label.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, PartialEq, Default, Deserialize, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CompletionItemLabelDetails {
|
||||
/// An optional string which is rendered less prominently directly after
|
||||
/// {@link CompletionItemLabel.label label}, without any spacing. Should be
|
||||
/// used for function signatures or type annotations.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub detail: Option<String>,
|
||||
|
||||
/// An optional string which is rendered less prominently after
|
||||
/// {@link CompletionItemLabel.detail}. Should be used for fully qualified
|
||||
/// names or file path.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub description: Option<String>,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::tests::test_deserialization;
|
||||
|
||||
#[test]
|
||||
fn test_tag_support_deserialization() {
|
||||
let empty = CompletionItemCapability {
|
||||
tag_support: None,
|
||||
..CompletionItemCapability::default()
|
||||
};
|
||||
|
||||
test_deserialization(r#"{}"#, &empty);
|
||||
test_deserialization(r#"{"tagSupport": false}"#, &empty);
|
||||
|
||||
let t = CompletionItemCapability {
|
||||
tag_support: Some(TagSupport { value_set: vec![] }),
|
||||
..CompletionItemCapability::default()
|
||||
};
|
||||
test_deserialization(r#"{"tagSupport": true}"#, &t);
|
||||
|
||||
let t = CompletionItemCapability {
|
||||
tag_support: Some(TagSupport {
|
||||
value_set: vec![CompletionItemTag::DEPRECATED],
|
||||
}),
|
||||
..CompletionItemCapability::default()
|
||||
};
|
||||
test_deserialization(r#"{"tagSupport": {"valueSet": [1]}}"#, &t);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_debug_enum() {
|
||||
assert_eq!(format!("{:?}", CompletionItemKind::TEXT), "Text");
|
||||
assert_eq!(
|
||||
format!("{:?}", CompletionItemKind::TYPE_PARAMETER),
|
||||
"TypeParameter"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_try_from_enum() {
|
||||
use std::convert::TryInto;
|
||||
assert_eq!("Text".try_into(), Ok(CompletionItemKind::TEXT));
|
||||
assert_eq!(
|
||||
"TypeParameter".try_into(),
|
||||
Ok(CompletionItemKind::TYPE_PARAMETER)
|
||||
);
|
||||
}
|
||||
}
|
269
helix-lsp-types/src/document_diagnostic.rs
Normal file
269
helix-lsp-types/src/document_diagnostic.rs
Normal file
@ -0,0 +1,269 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use url::Url;
|
||||
|
||||
use crate::{
|
||||
Diagnostic, PartialResultParams, StaticRegistrationOptions, TextDocumentIdentifier,
|
||||
TextDocumentRegistrationOptions, WorkDoneProgressOptions, WorkDoneProgressParams,
|
||||
};
|
||||
|
||||
/// Client capabilities specific to diagnostic pull requests.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DiagnosticClientCapabilities {
|
||||
/// Whether implementation supports dynamic registration.
|
||||
///
|
||||
/// If this is set to `true` the client supports the new `(TextDocumentRegistrationOptions &
|
||||
/// StaticRegistrationOptions)` return value for the corresponding server capability as well.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub dynamic_registration: Option<bool>,
|
||||
|
||||
/// Whether the clients supports related documents for document diagnostic pulls.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub related_document_support: Option<bool>,
|
||||
}
|
||||
|
||||
/// Diagnostic options.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DiagnosticOptions {
|
||||
/// An optional identifier under which the diagnostics are
|
||||
/// managed by the client.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub identifier: Option<String>,
|
||||
|
||||
/// Whether the language has inter file dependencies, meaning that editing code in one file can
|
||||
/// result in a different diagnostic set in another file. Inter file dependencies are common
|
||||
/// for most programming languages and typically uncommon for linters.
|
||||
pub inter_file_dependencies: bool,
|
||||
|
||||
/// The server provides support for workspace diagnostics as well.
|
||||
pub workspace_diagnostics: bool,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_options: WorkDoneProgressOptions,
|
||||
}
|
||||
|
||||
/// Diagnostic registration options.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DiagnosticRegistrationOptions {
|
||||
#[serde(flatten)]
|
||||
pub text_document_registration_options: TextDocumentRegistrationOptions,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub diagnostic_options: DiagnosticOptions,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub static_registration_options: StaticRegistrationOptions,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum DiagnosticServerCapabilities {
|
||||
Options(DiagnosticOptions),
|
||||
RegistrationOptions(DiagnosticRegistrationOptions),
|
||||
}
|
||||
|
||||
/// Parameters of the document diagnostic request.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DocumentDiagnosticParams {
|
||||
/// The text document.
|
||||
pub text_document: TextDocumentIdentifier,
|
||||
|
||||
/// The additional identifier provided during registration.
|
||||
pub identifier: Option<String>,
|
||||
|
||||
/// The result ID of a previous response if provided.
|
||||
pub previous_result_id: Option<String>,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_params: WorkDoneProgressParams,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub partial_result_params: PartialResultParams,
|
||||
}
|
||||
|
||||
/// A diagnostic report with a full set of problems.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, PartialEq, Default, Deserialize, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct FullDocumentDiagnosticReport {
|
||||
/// An optional result ID. If provided it will be sent on the next diagnostic request for the
|
||||
/// same document.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub result_id: Option<String>,
|
||||
|
||||
/// The actual items.
|
||||
pub items: Vec<Diagnostic>,
|
||||
}
|
||||
|
||||
/// A diagnostic report indicating that the last returned report is still accurate.
|
||||
///
|
||||
/// A server can only return `unchanged` if result ids are provided.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct UnchangedDocumentDiagnosticReport {
|
||||
/// A result ID which will be sent on the next diagnostic request for the same document.
|
||||
pub result_id: String,
|
||||
}
|
||||
|
||||
/// The document diagnostic report kinds.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)]
|
||||
#[serde(tag = "kind", rename_all = "lowercase")]
|
||||
pub enum DocumentDiagnosticReportKind {
|
||||
/// A diagnostic report with a full set of problems.
|
||||
Full(FullDocumentDiagnosticReport),
|
||||
/// A report indicating that the last returned report is still accurate.
|
||||
Unchanged(UnchangedDocumentDiagnosticReport),
|
||||
}
|
||||
|
||||
impl From<FullDocumentDiagnosticReport> for DocumentDiagnosticReportKind {
|
||||
fn from(from: FullDocumentDiagnosticReport) -> Self {
|
||||
DocumentDiagnosticReportKind::Full(from)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<UnchangedDocumentDiagnosticReport> for DocumentDiagnosticReportKind {
|
||||
fn from(from: UnchangedDocumentDiagnosticReport) -> Self {
|
||||
DocumentDiagnosticReportKind::Unchanged(from)
|
||||
}
|
||||
}
|
||||
|
||||
/// A full diagnostic report with a set of related documents.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, PartialEq, Default, Deserialize, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RelatedFullDocumentDiagnosticReport {
|
||||
/// Diagnostics of related documents.
|
||||
///
|
||||
/// This information is useful in programming languages where code in a file A can generate
|
||||
/// diagnostics in a file B which A depends on. An example of such a language is C/C++ where
|
||||
/// macro definitions in a file `a.cpp` result in errors in a header file `b.hpp`.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[serde(with = "crate::url_map")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[serde(default)]
|
||||
pub related_documents: Option<HashMap<Url, DocumentDiagnosticReportKind>>,
|
||||
// relatedDocuments?: { [uri: string]: FullDocumentDiagnosticReport | UnchangedDocumentDiagnosticReport; };
|
||||
#[serde(flatten)]
|
||||
pub full_document_diagnostic_report: FullDocumentDiagnosticReport,
|
||||
}
|
||||
|
||||
/// An unchanged diagnostic report with a set of related documents.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RelatedUnchangedDocumentDiagnosticReport {
|
||||
/// Diagnostics of related documents.
|
||||
///
|
||||
/// This information is useful in programming languages where code in a file A can generate
|
||||
/// diagnostics in a file B which A depends on. An example of such a language is C/C++ where
|
||||
/// macro definitions in a file `a.cpp` result in errors in a header file `b.hpp`.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[serde(with = "crate::url_map")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[serde(default)]
|
||||
pub related_documents: Option<HashMap<Url, DocumentDiagnosticReportKind>>,
|
||||
// relatedDocuments?: { [uri: string]: FullDocumentDiagnosticReport | UnchangedDocumentDiagnosticReport; };
|
||||
#[serde(flatten)]
|
||||
pub unchanged_document_diagnostic_report: UnchangedDocumentDiagnosticReport,
|
||||
}
|
||||
|
||||
/// The result of a document diagnostic pull request.
|
||||
///
|
||||
/// A report can either be a full report containing all diagnostics for the requested document or
|
||||
/// an unchanged report indicating that nothing has changed in terms of diagnostics in comparison
|
||||
/// to the last pull request.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)]
|
||||
#[serde(tag = "kind", rename_all = "lowercase")]
|
||||
pub enum DocumentDiagnosticReport {
|
||||
/// A diagnostic report with a full set of problems.
|
||||
Full(RelatedFullDocumentDiagnosticReport),
|
||||
/// A report indicating that the last returned report is still accurate.
|
||||
Unchanged(RelatedUnchangedDocumentDiagnosticReport),
|
||||
}
|
||||
|
||||
impl From<RelatedFullDocumentDiagnosticReport> for DocumentDiagnosticReport {
|
||||
fn from(from: RelatedFullDocumentDiagnosticReport) -> Self {
|
||||
DocumentDiagnosticReport::Full(from)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RelatedUnchangedDocumentDiagnosticReport> for DocumentDiagnosticReport {
|
||||
fn from(from: RelatedUnchangedDocumentDiagnosticReport) -> Self {
|
||||
DocumentDiagnosticReport::Unchanged(from)
|
||||
}
|
||||
}
|
||||
|
||||
/// A partial result for a document diagnostic report.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, PartialEq, Default, Deserialize, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DocumentDiagnosticReportPartialResult {
|
||||
#[serde(with = "crate::url_map")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[serde(default)]
|
||||
pub related_documents: Option<HashMap<Url, DocumentDiagnosticReportKind>>,
|
||||
// relatedDocuments?: { [uri: string]: FullDocumentDiagnosticReport | UnchangedDocumentDiagnosticReport; };
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)]
|
||||
#[serde(untagged)]
|
||||
pub enum DocumentDiagnosticReportResult {
|
||||
Report(DocumentDiagnosticReport),
|
||||
Partial(DocumentDiagnosticReportPartialResult),
|
||||
}
|
||||
|
||||
impl From<DocumentDiagnosticReport> for DocumentDiagnosticReportResult {
|
||||
fn from(from: DocumentDiagnosticReport) -> Self {
|
||||
DocumentDiagnosticReportResult::Report(from)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<DocumentDiagnosticReportPartialResult> for DocumentDiagnosticReportResult {
|
||||
fn from(from: DocumentDiagnosticReportPartialResult) -> Self {
|
||||
DocumentDiagnosticReportResult::Partial(from)
|
||||
}
|
||||
}
|
||||
|
||||
/// Cancellation data returned from a diagnostic request.
|
||||
///
|
||||
/// If no data is provided, it defaults to `{ retrigger_request: true }`.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DiagnosticServerCancellationData {
|
||||
pub retrigger_request: bool,
|
||||
}
|
||||
|
||||
impl Default for DiagnosticServerCancellationData {
|
||||
fn default() -> Self {
|
||||
DiagnosticServerCancellationData {
|
||||
retrigger_request: true,
|
||||
}
|
||||
}
|
||||
}
|
51
helix-lsp-types/src/document_highlight.rs
Normal file
51
helix-lsp-types/src/document_highlight.rs
Normal file
@ -0,0 +1,51 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
DynamicRegistrationClientCapabilities, PartialResultParams, Range, TextDocumentPositionParams,
|
||||
WorkDoneProgressParams,
|
||||
};
|
||||
|
||||
pub type DocumentHighlightClientCapabilities = DynamicRegistrationClientCapabilities;
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DocumentHighlightParams {
|
||||
#[serde(flatten)]
|
||||
pub text_document_position_params: TextDocumentPositionParams,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_params: WorkDoneProgressParams,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub partial_result_params: PartialResultParams,
|
||||
}
|
||||
|
||||
/// A document highlight is a range inside a text document which deserves
|
||||
/// special attention. Usually a document highlight is visualized by changing
|
||||
/// the background color of its range.
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
pub struct DocumentHighlight {
|
||||
/// The range this highlight applies to.
|
||||
pub range: Range,
|
||||
|
||||
/// The highlight kind, default is DocumentHighlightKind.Text.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub kind: Option<DocumentHighlightKind>,
|
||||
}
|
||||
|
||||
/// A document highlight kind.
|
||||
#[derive(Eq, PartialEq, Copy, Clone, Deserialize, Serialize)]
|
||||
#[serde(transparent)]
|
||||
pub struct DocumentHighlightKind(i32);
|
||||
lsp_enum! {
|
||||
impl DocumentHighlightKind {
|
||||
/// A textual occurrence.
|
||||
pub const TEXT: DocumentHighlightKind = DocumentHighlightKind(1);
|
||||
|
||||
/// Read-access of a symbol, like reading a variable.
|
||||
pub const READ: DocumentHighlightKind = DocumentHighlightKind(2);
|
||||
|
||||
/// Write-access of a symbol, like writing to a variable.
|
||||
pub const WRITE: DocumentHighlightKind = DocumentHighlightKind(3);
|
||||
}
|
||||
}
|
67
helix-lsp-types/src/document_link.rs
Normal file
67
helix-lsp-types/src/document_link.rs
Normal file
@ -0,0 +1,67 @@
|
||||
use crate::{
|
||||
PartialResultParams, Range, TextDocumentIdentifier, WorkDoneProgressOptions,
|
||||
WorkDoneProgressParams,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
use url::Url;
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DocumentLinkClientCapabilities {
|
||||
/// Whether document link supports dynamic registration.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub dynamic_registration: Option<bool>,
|
||||
|
||||
/// Whether the client support the `tooltip` property on `DocumentLink`.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub tooltip_support: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DocumentLinkOptions {
|
||||
/// Document links have a resolve provider as well.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub resolve_provider: Option<bool>,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_options: WorkDoneProgressOptions,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DocumentLinkParams {
|
||||
/// The document to provide document links for.
|
||||
pub text_document: TextDocumentIdentifier,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_params: WorkDoneProgressParams,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub partial_result_params: PartialResultParams,
|
||||
}
|
||||
|
||||
/// A document link is a range in a text document that links to an internal or external resource, like another
|
||||
/// text document or a web site.
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
pub struct DocumentLink {
|
||||
/// The range this link applies to.
|
||||
pub range: Range,
|
||||
/// The uri this link points to.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub target: Option<Url>,
|
||||
|
||||
/// The tooltip text when you hover over this link.
|
||||
///
|
||||
/// If a tooltip is provided, is will be displayed in a string that includes instructions on how to
|
||||
/// trigger the link, such as `{0} (ctrl + click)`. The specific instructions vary depending on OS,
|
||||
/// user settings, and localization.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub tooltip: Option<String>,
|
||||
|
||||
/// A data entry field that is preserved on a document link between a DocumentLinkRequest
|
||||
/// and a DocumentLinkResolveRequest.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub data: Option<Value>,
|
||||
}
|
134
helix-lsp-types/src/document_symbols.rs
Normal file
134
helix-lsp-types/src/document_symbols.rs
Normal file
@ -0,0 +1,134 @@
|
||||
use crate::{
|
||||
Location, PartialResultParams, Range, SymbolKind, SymbolKindCapability, TextDocumentIdentifier,
|
||||
WorkDoneProgressParams,
|
||||
};
|
||||
|
||||
use crate::{SymbolTag, TagSupport};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DocumentSymbolClientCapabilities {
|
||||
/// This capability supports dynamic registration.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub dynamic_registration: Option<bool>,
|
||||
|
||||
/// Specific capabilities for the `SymbolKind`.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub symbol_kind: Option<SymbolKindCapability>,
|
||||
|
||||
/// The client support hierarchical document symbols.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub hierarchical_document_symbol_support: Option<bool>,
|
||||
|
||||
/// The client supports tags on `SymbolInformation`. Tags are supported on
|
||||
/// `DocumentSymbol` if `hierarchicalDocumentSymbolSupport` is set to true.
|
||||
/// Clients supporting tags have to handle unknown tags gracefully.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[serde(
|
||||
default,
|
||||
skip_serializing_if = "Option::is_none",
|
||||
deserialize_with = "TagSupport::deserialize_compat"
|
||||
)]
|
||||
pub tag_support: Option<TagSupport<SymbolTag>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum DocumentSymbolResponse {
|
||||
Flat(Vec<SymbolInformation>),
|
||||
Nested(Vec<DocumentSymbol>),
|
||||
}
|
||||
|
||||
impl From<Vec<SymbolInformation>> for DocumentSymbolResponse {
|
||||
fn from(info: Vec<SymbolInformation>) -> Self {
|
||||
DocumentSymbolResponse::Flat(info)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<DocumentSymbol>> for DocumentSymbolResponse {
|
||||
fn from(symbols: Vec<DocumentSymbol>) -> Self {
|
||||
DocumentSymbolResponse::Nested(symbols)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DocumentSymbolParams {
|
||||
/// The text document.
|
||||
pub text_document: TextDocumentIdentifier,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_params: WorkDoneProgressParams,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub partial_result_params: PartialResultParams,
|
||||
}
|
||||
|
||||
/// Represents programming constructs like variables, classes, interfaces etc.
|
||||
/// that appear in a document. Document symbols can be hierarchical and they have two ranges:
|
||||
/// one that encloses its definition and one that points to its most interesting range,
|
||||
/// e.g. the range of an identifier.
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DocumentSymbol {
|
||||
/// The name of this symbol.
|
||||
pub name: String,
|
||||
/// More detail for this symbol, e.g the signature of a function. If not provided the
|
||||
/// name is used.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub detail: Option<String>,
|
||||
/// The kind of this symbol.
|
||||
pub kind: SymbolKind,
|
||||
/// Tags for this completion item.
|
||||
///
|
||||
/// @since 3.15.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub tags: Option<Vec<SymbolTag>>,
|
||||
/// Indicates if this symbol is deprecated.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[deprecated(note = "Use tags instead")]
|
||||
pub deprecated: Option<bool>,
|
||||
/// The range enclosing this symbol not including leading/trailing whitespace but everything else
|
||||
/// like comments. This information is typically used to determine if the the clients cursor is
|
||||
/// inside the symbol to reveal in the symbol in the UI.
|
||||
pub range: Range,
|
||||
/// The range that should be selected and revealed when this symbol is being picked, e.g the name of a function.
|
||||
/// Must be contained by the the `range`.
|
||||
pub selection_range: Range,
|
||||
/// Children of this symbol, e.g. properties of a class.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub children: Option<Vec<DocumentSymbol>>,
|
||||
}
|
||||
|
||||
/// Represents information about programming constructs like variables, classes,
|
||||
/// interfaces etc.
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SymbolInformation {
|
||||
/// The name of this symbol.
|
||||
pub name: String,
|
||||
|
||||
/// The kind of this symbol.
|
||||
pub kind: SymbolKind,
|
||||
|
||||
/// Tags for this completion item.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub tags: Option<Vec<SymbolTag>>,
|
||||
|
||||
/// Indicates if this symbol is deprecated.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[deprecated(note = "Use tags instead")]
|
||||
pub deprecated: Option<bool>,
|
||||
|
||||
/// The location of this symbol.
|
||||
pub location: Location,
|
||||
|
||||
/// The name of the symbol containing this symbol.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub container_name: Option<String>,
|
||||
}
|
54
helix-lsp-types/src/error_codes.rs
Normal file
54
helix-lsp-types/src/error_codes.rs
Normal file
@ -0,0 +1,54 @@
|
||||
//! In this module we only define constants for lsp specific error codes.
|
||||
//! There are other error codes that are defined in the
|
||||
//! [JSON RPC specification](https://www.jsonrpc.org/specification#error_object).
|
||||
|
||||
/// Defined in the LSP specification but in the range reserved for JSON-RPC error codes,
|
||||
/// namely the -32099 to -32000 "Reserved for implementation-defined server-errors." range.
|
||||
/// The code has, nonetheless, been left in this range for backwards compatibility reasons.
|
||||
pub const SERVER_NOT_INITIALIZED: i64 = -32002;
|
||||
|
||||
/// Defined in the LSP specification but in the range reserved for JSON-RPC error codes,
|
||||
/// namely the -32099 to -32000 "Reserved for implementation-defined server-errors." range.
|
||||
/// The code has, nonetheless, left in this range for backwards compatibility reasons.
|
||||
pub const UNKNOWN_ERROR_CODE: i64 = -32001;
|
||||
|
||||
/// This is the start range of LSP reserved error codes.
|
||||
/// It doesn't denote a real error code.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
pub const LSP_RESERVED_ERROR_RANGE_START: i64 = -32899;
|
||||
|
||||
/// A request failed but it was syntactically correct, e.g the
|
||||
/// method name was known and the parameters were valid. The error
|
||||
/// message should contain human readable information about why
|
||||
/// the request failed.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
pub const REQUEST_FAILED: i64 = -32803;
|
||||
|
||||
/// The server cancelled the request. This error code should
|
||||
/// only be used for requests that explicitly support being
|
||||
/// server cancellable.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
pub const SERVER_CANCELLED: i64 = -32802;
|
||||
|
||||
/// The server detected that the content of a document got
|
||||
/// modified outside normal conditions. A server should
|
||||
/// NOT send this error code if it detects a content change
|
||||
/// in it unprocessed messages. The result even computed
|
||||
/// on an older state might still be useful for the client.
|
||||
///
|
||||
/// If a client decides that a result is not of any use anymore
|
||||
/// the client should cancel the request.
|
||||
pub const CONTENT_MODIFIED: i64 = -32801;
|
||||
|
||||
/// The client has canceled a request and a server as detected
|
||||
/// the cancel.
|
||||
pub const REQUEST_CANCELLED: i64 = -32800;
|
||||
|
||||
/// This is the end range of LSP reserved error codes.
|
||||
/// It doesn't denote a real error code.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
pub const LSP_RESERVED_ERROR_RANGE_END: i64 = -32800;
|
213
helix-lsp-types/src/file_operations.rs
Normal file
213
helix-lsp-types/src/file_operations.rs
Normal file
@ -0,0 +1,213 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct WorkspaceFileOperationsClientCapabilities {
|
||||
/// Whether the client supports dynamic registration for file
|
||||
/// requests/notifications.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub dynamic_registration: Option<bool>,
|
||||
|
||||
/// The client has support for sending didCreateFiles notifications.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub did_create: Option<bool>,
|
||||
|
||||
/// The server is interested in receiving willCreateFiles requests.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub will_create: Option<bool>,
|
||||
|
||||
/// The server is interested in receiving didRenameFiles requests.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub did_rename: Option<bool>,
|
||||
|
||||
/// The server is interested in receiving willRenameFiles requests.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub will_rename: Option<bool>,
|
||||
|
||||
/// The server is interested in receiving didDeleteFiles requests.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub did_delete: Option<bool>,
|
||||
|
||||
/// The server is interested in receiving willDeleteFiles requests.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub will_delete: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct WorkspaceFileOperationsServerCapabilities {
|
||||
/// The server is interested in receiving didCreateFiles
|
||||
/// notifications.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub did_create: Option<FileOperationRegistrationOptions>,
|
||||
|
||||
/// The server is interested in receiving willCreateFiles requests.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub will_create: Option<FileOperationRegistrationOptions>,
|
||||
|
||||
/// The server is interested in receiving didRenameFiles
|
||||
/// notifications.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub did_rename: Option<FileOperationRegistrationOptions>,
|
||||
|
||||
/// The server is interested in receiving willRenameFiles requests.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub will_rename: Option<FileOperationRegistrationOptions>,
|
||||
|
||||
/// The server is interested in receiving didDeleteFiles file
|
||||
/// notifications.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub did_delete: Option<FileOperationRegistrationOptions>,
|
||||
|
||||
/// The server is interested in receiving willDeleteFiles file
|
||||
/// requests.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub will_delete: Option<FileOperationRegistrationOptions>,
|
||||
}
|
||||
|
||||
/// The options to register for file operations.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct FileOperationRegistrationOptions {
|
||||
/// The actual filters.
|
||||
pub filters: Vec<FileOperationFilter>,
|
||||
}
|
||||
|
||||
/// A filter to describe in which file operation requests or notifications
|
||||
/// the server is interested in.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct FileOperationFilter {
|
||||
/// A Uri like `file` or `untitled`.
|
||||
pub scheme: Option<String>,
|
||||
|
||||
/// The actual file operation pattern.
|
||||
pub pattern: FileOperationPattern,
|
||||
}
|
||||
|
||||
/// A pattern kind describing if a glob pattern matches a file a folder or
|
||||
/// both.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[derive(Debug, Eq, PartialEq, Deserialize, Serialize, Clone)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum FileOperationPatternKind {
|
||||
/// The pattern matches a file only.
|
||||
File,
|
||||
|
||||
/// The pattern matches a folder only.
|
||||
Folder,
|
||||
}
|
||||
|
||||
/// Matching options for the file operation pattern.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
///
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct FileOperationPatternOptions {
|
||||
/// The pattern should be matched ignoring casing.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub ignore_case: Option<bool>,
|
||||
}
|
||||
|
||||
/// A pattern to describe in which file operation requests or notifications
|
||||
/// the server is interested in.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct FileOperationPattern {
|
||||
/// The glob pattern to match. Glob patterns can have the following syntax:
|
||||
/// - `*` to match one or more characters in a path segment
|
||||
/// - `?` to match on one character in a path segment
|
||||
/// - `**` to match any number of path segments, including none
|
||||
/// - `{}` to group conditions (e.g. `**/*.{ts,js}` matches all TypeScript
|
||||
/// and JavaScript files)
|
||||
/// - `[]` to declare a range of characters to match in a path segment
|
||||
/// (e.g., `example.[0-9]` to match on `example.0`, `example.1`, …)
|
||||
/// - `[!...]` to negate a range of characters to match in a path segment
|
||||
/// (e.g., `example.[!0-9]` to match on `example.a`, `example.b`, but
|
||||
/// not `example.0`)
|
||||
pub glob: String,
|
||||
|
||||
/// Whether to match files or folders with this pattern.
|
||||
///
|
||||
/// Matches both if undefined.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub matches: Option<FileOperationPatternKind>,
|
||||
|
||||
/// Additional options used during matching.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub options: Option<FileOperationPatternOptions>,
|
||||
}
|
||||
|
||||
/// The parameters sent in notifications/requests for user-initiated creation
|
||||
/// of files.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CreateFilesParams {
|
||||
/// An array of all files/folders created in this operation.
|
||||
pub files: Vec<FileCreate>,
|
||||
}
|
||||
/// Represents information on a file/folder create.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct FileCreate {
|
||||
/// A file:// URI for the location of the file/folder being created.
|
||||
pub uri: String,
|
||||
}
|
||||
|
||||
/// The parameters sent in notifications/requests for user-initiated renames
|
||||
/// of files.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RenameFilesParams {
|
||||
/// An array of all files/folders renamed in this operation. When a folder
|
||||
/// is renamed, only the folder will be included, and not its children.
|
||||
pub files: Vec<FileRename>,
|
||||
}
|
||||
|
||||
/// Represents information on a file/folder rename.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct FileRename {
|
||||
/// A file:// URI for the original location of the file/folder being renamed.
|
||||
pub old_uri: String,
|
||||
|
||||
/// A file:// URI for the new location of the file/folder being renamed.
|
||||
pub new_uri: String,
|
||||
}
|
||||
|
||||
/// The parameters sent in notifications/requests for user-initiated deletes
|
||||
/// of files.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DeleteFilesParams {
|
||||
/// An array of all files/folders deleted in this operation.
|
||||
pub files: Vec<FileDelete>,
|
||||
}
|
||||
|
||||
/// Represents information on a file/folder delete.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct FileDelete {
|
||||
/// A file:// URI for the location of the file/folder being deleted.
|
||||
pub uri: String,
|
||||
}
|
145
helix-lsp-types/src/folding_range.rs
Normal file
145
helix-lsp-types/src/folding_range.rs
Normal file
@ -0,0 +1,145 @@
|
||||
use crate::{
|
||||
PartialResultParams, StaticTextDocumentColorProviderOptions, TextDocumentIdentifier,
|
||||
WorkDoneProgressParams,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct FoldingRangeParams {
|
||||
/// The text document.
|
||||
pub text_document: TextDocumentIdentifier,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_params: WorkDoneProgressParams,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub partial_result_params: PartialResultParams,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum FoldingRangeProviderCapability {
|
||||
Simple(bool),
|
||||
FoldingProvider(FoldingProviderOptions),
|
||||
Options(StaticTextDocumentColorProviderOptions),
|
||||
}
|
||||
|
||||
impl From<StaticTextDocumentColorProviderOptions> for FoldingRangeProviderCapability {
|
||||
fn from(from: StaticTextDocumentColorProviderOptions) -> Self {
|
||||
Self::Options(from)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<FoldingProviderOptions> for FoldingRangeProviderCapability {
|
||||
fn from(from: FoldingProviderOptions) -> Self {
|
||||
Self::FoldingProvider(from)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<bool> for FoldingRangeProviderCapability {
|
||||
fn from(from: bool) -> Self {
|
||||
Self::Simple(from)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
pub struct FoldingProviderOptions {}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct FoldingRangeKindCapability {
|
||||
/// The folding range kind values the client supports. When this
|
||||
/// property exists the client also guarantees that it will
|
||||
/// handle values outside its set gracefully and falls back
|
||||
/// to a default value when unknown.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub value_set: Option<Vec<FoldingRangeKind>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct FoldingRangeCapability {
|
||||
/// If set, the client signals that it supports setting collapsedText on
|
||||
/// folding ranges to display custom labels instead of the default text.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub collapsed_text: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct FoldingRangeClientCapabilities {
|
||||
/// Whether implementation supports dynamic registration for folding range providers. If this is set to `true`
|
||||
/// the client supports the new `(FoldingRangeProviderOptions & TextDocumentRegistrationOptions & StaticRegistrationOptions)`
|
||||
/// return value for the corresponding server capability as well.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub dynamic_registration: Option<bool>,
|
||||
|
||||
/// The maximum number of folding ranges that the client prefers to receive per document. The value serves as a
|
||||
/// hint, servers are free to follow the limit.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub range_limit: Option<u32>,
|
||||
|
||||
/// If set, the client signals that it only supports folding complete lines. If set, client will
|
||||
/// ignore specified `startCharacter` and `endCharacter` properties in a FoldingRange.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub line_folding_only: Option<bool>,
|
||||
|
||||
/// Specific options for the folding range kind.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub folding_range_kind: Option<FoldingRangeKindCapability>,
|
||||
|
||||
/// Specific options for the folding range.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub folding_range: Option<FoldingRangeCapability>,
|
||||
}
|
||||
|
||||
/// Enum of known range kinds
|
||||
#[derive(Debug, Eq, PartialEq, Deserialize, Serialize, Clone)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum FoldingRangeKind {
|
||||
/// Folding range for a comment
|
||||
Comment,
|
||||
/// Folding range for a imports or includes
|
||||
Imports,
|
||||
/// Folding range for a region (e.g. `#region`)
|
||||
Region,
|
||||
}
|
||||
|
||||
/// Represents a folding range.
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct FoldingRange {
|
||||
/// The zero-based line number from where the folded range starts.
|
||||
pub start_line: u32,
|
||||
|
||||
/// The zero-based character offset from where the folded range starts. If not defined, defaults to the length of the start line.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub start_character: Option<u32>,
|
||||
|
||||
/// The zero-based line number where the folded range ends.
|
||||
pub end_line: u32,
|
||||
|
||||
/// The zero-based character offset before the folded range ends. If not defined, defaults to the length of the end line.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub end_character: Option<u32>,
|
||||
|
||||
/// Describes the kind of the folding range such as `comment' or 'region'. The kind
|
||||
/// is used to categorize folding ranges and used by commands like 'Fold all comments'. See
|
||||
/// [FoldingRangeKind](#FoldingRangeKind) for an enumeration of standardized kinds.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub kind: Option<FoldingRangeKind>,
|
||||
|
||||
/// The text that the client should show when the specified range is
|
||||
/// collapsed. If not defined or not supported by the client, a default
|
||||
/// will be chosen by the client.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub collapsed_text: Option<String>,
|
||||
}
|
153
helix-lsp-types/src/formatting.rs
Normal file
153
helix-lsp-types/src/formatting.rs
Normal file
@ -0,0 +1,153 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
DocumentSelector, DynamicRegistrationClientCapabilities, Range, TextDocumentIdentifier,
|
||||
TextDocumentPositionParams, WorkDoneProgressParams,
|
||||
};
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub type DocumentFormattingClientCapabilities = DynamicRegistrationClientCapabilities;
|
||||
pub type DocumentRangeFormattingClientCapabilities = DynamicRegistrationClientCapabilities;
|
||||
pub type DocumentOnTypeFormattingClientCapabilities = DynamicRegistrationClientCapabilities;
|
||||
|
||||
/// Format document on type options
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DocumentOnTypeFormattingOptions {
|
||||
/// A character on which formatting should be triggered, like `}`.
|
||||
pub first_trigger_character: String,
|
||||
|
||||
/// More trigger characters.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub more_trigger_character: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DocumentFormattingParams {
|
||||
/// The document to format.
|
||||
pub text_document: TextDocumentIdentifier,
|
||||
|
||||
/// The format options.
|
||||
pub options: FormattingOptions,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_params: WorkDoneProgressParams,
|
||||
}
|
||||
|
||||
/// Value-object describing what options formatting should use.
|
||||
#[derive(Debug, PartialEq, Clone, Default, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct FormattingOptions {
|
||||
/// Size of a tab in spaces.
|
||||
pub tab_size: u32,
|
||||
|
||||
/// Prefer spaces over tabs.
|
||||
pub insert_spaces: bool,
|
||||
|
||||
/// Signature for further properties.
|
||||
#[serde(flatten)]
|
||||
pub properties: HashMap<String, FormattingProperty>,
|
||||
|
||||
/// Trim trailing whitespace on a line.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub trim_trailing_whitespace: Option<bool>,
|
||||
|
||||
/// Insert a newline character at the end of the file if one does not exist.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub insert_final_newline: Option<bool>,
|
||||
|
||||
/// Trim all newlines after the final newline at the end of the file.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub trim_final_newlines: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum FormattingProperty {
|
||||
Bool(bool),
|
||||
Number(i32),
|
||||
String(String),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DocumentRangeFormattingParams {
|
||||
/// The document to format.
|
||||
pub text_document: TextDocumentIdentifier,
|
||||
|
||||
/// The range to format
|
||||
pub range: Range,
|
||||
|
||||
/// The format options
|
||||
pub options: FormattingOptions,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_params: WorkDoneProgressParams,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DocumentOnTypeFormattingParams {
|
||||
/// Text Document and Position fields.
|
||||
#[serde(flatten)]
|
||||
pub text_document_position: TextDocumentPositionParams,
|
||||
|
||||
/// The character that has been typed.
|
||||
pub ch: String,
|
||||
|
||||
/// The format options.
|
||||
pub options: FormattingOptions,
|
||||
}
|
||||
|
||||
/// Extends TextDocumentRegistrationOptions
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DocumentOnTypeFormattingRegistrationOptions {
|
||||
/// A document selector to identify the scope of the registration. If set to null
|
||||
/// the document selector provided on the client side will be used.
|
||||
pub document_selector: Option<DocumentSelector>,
|
||||
|
||||
/// A character on which formatting should be triggered, like `}`.
|
||||
pub first_trigger_character: String,
|
||||
|
||||
/// More trigger characters.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub more_trigger_character: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::tests::test_serialization;
|
||||
|
||||
#[test]
|
||||
fn formatting_options() {
|
||||
test_serialization(
|
||||
&FormattingOptions {
|
||||
tab_size: 123,
|
||||
insert_spaces: true,
|
||||
properties: HashMap::new(),
|
||||
trim_trailing_whitespace: None,
|
||||
insert_final_newline: None,
|
||||
trim_final_newlines: None,
|
||||
},
|
||||
r#"{"tabSize":123,"insertSpaces":true}"#,
|
||||
);
|
||||
|
||||
test_serialization(
|
||||
&FormattingOptions {
|
||||
tab_size: 123,
|
||||
insert_spaces: true,
|
||||
properties: vec![("prop".to_string(), FormattingProperty::Number(1))]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
trim_trailing_whitespace: None,
|
||||
insert_final_newline: None,
|
||||
trim_final_newlines: None,
|
||||
},
|
||||
r#"{"tabSize":123,"insertSpaces":true,"prop":1}"#,
|
||||
);
|
||||
}
|
||||
}
|
86
helix-lsp-types/src/hover.rs
Normal file
86
helix-lsp-types/src/hover.rs
Normal file
@ -0,0 +1,86 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
MarkedString, MarkupContent, MarkupKind, Range, TextDocumentPositionParams,
|
||||
TextDocumentRegistrationOptions, WorkDoneProgressOptions, WorkDoneProgressParams,
|
||||
};
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct HoverClientCapabilities {
|
||||
/// Whether completion supports dynamic registration.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub dynamic_registration: Option<bool>,
|
||||
|
||||
/// Client supports the follow content formats for the content
|
||||
/// property. The order describes the preferred format of the client.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub content_format: Option<Vec<MarkupKind>>,
|
||||
}
|
||||
|
||||
/// Hover options.
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct HoverOptions {
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_options: WorkDoneProgressOptions,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct HoverRegistrationOptions {
|
||||
#[serde(flatten)]
|
||||
pub text_document_registration_options: TextDocumentRegistrationOptions,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub hover_options: HoverOptions,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum HoverProviderCapability {
|
||||
Simple(bool),
|
||||
Options(HoverOptions),
|
||||
}
|
||||
|
||||
impl From<HoverOptions> for HoverProviderCapability {
|
||||
fn from(from: HoverOptions) -> Self {
|
||||
Self::Options(from)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<bool> for HoverProviderCapability {
|
||||
fn from(from: bool) -> Self {
|
||||
Self::Simple(from)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct HoverParams {
|
||||
#[serde(flatten)]
|
||||
pub text_document_position_params: TextDocumentPositionParams,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_params: WorkDoneProgressParams,
|
||||
}
|
||||
|
||||
/// The result of a hover request.
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
pub struct Hover {
|
||||
/// The hover's content
|
||||
pub contents: HoverContents,
|
||||
/// An optional range is a range inside a text document
|
||||
/// that is used to visualize a hover, e.g. by changing the background color.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub range: Option<Range>,
|
||||
}
|
||||
|
||||
/// Hover contents could be single entry or multiple entries.
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Serialize, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum HoverContents {
|
||||
Scalar(MarkedString),
|
||||
Array(Vec<MarkedString>),
|
||||
Markup(MarkupContent),
|
||||
}
|
281
helix-lsp-types/src/inlay_hint.rs
Normal file
281
helix-lsp-types/src/inlay_hint.rs
Normal file
@ -0,0 +1,281 @@
|
||||
use crate::{
|
||||
Command, LSPAny, Location, MarkupContent, Position, Range, StaticRegistrationOptions,
|
||||
TextDocumentIdentifier, TextDocumentRegistrationOptions, TextEdit, WorkDoneProgressOptions,
|
||||
WorkDoneProgressParams,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[serde(untagged)]
|
||||
pub enum InlayHintServerCapabilities {
|
||||
Options(InlayHintOptions),
|
||||
RegistrationOptions(InlayHintRegistrationOptions),
|
||||
}
|
||||
|
||||
/// Inlay hint client capabilities.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct InlayHintClientCapabilities {
|
||||
/// Whether inlay hints support dynamic registration.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub dynamic_registration: Option<bool>,
|
||||
|
||||
/// Indicates which properties a client can resolve lazily on a inlay
|
||||
/// hint.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub resolve_support: Option<InlayHintResolveClientCapabilities>,
|
||||
}
|
||||
|
||||
/// Inlay hint options used during static registration.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct InlayHintOptions {
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_options: WorkDoneProgressOptions,
|
||||
|
||||
/// The server provides support to resolve additional
|
||||
/// information for an inlay hint item.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub resolve_provider: Option<bool>,
|
||||
}
|
||||
|
||||
/// Inlay hint options used during static or dynamic registration.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct InlayHintRegistrationOptions {
|
||||
#[serde(flatten)]
|
||||
pub inlay_hint_options: InlayHintOptions,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub text_document_registration_options: TextDocumentRegistrationOptions,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub static_registration_options: StaticRegistrationOptions,
|
||||
}
|
||||
|
||||
/// A parameter literal used in inlay hint requests.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct InlayHintParams {
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_params: WorkDoneProgressParams,
|
||||
|
||||
/// The text document.
|
||||
pub text_document: TextDocumentIdentifier,
|
||||
|
||||
/// The visible document range for which inlay hints should be computed.
|
||||
pub range: Range,
|
||||
}
|
||||
|
||||
/// Inlay hint information.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct InlayHint {
|
||||
/// The position of this hint.
|
||||
pub position: Position,
|
||||
|
||||
/// The label of this hint. A human readable string or an array of
|
||||
/// InlayHintLabelPart label parts.
|
||||
///
|
||||
/// *Note* that neither the string nor the label part can be empty.
|
||||
pub label: InlayHintLabel,
|
||||
|
||||
/// The kind of this hint. Can be omitted in which case the client
|
||||
/// should fall back to a reasonable default.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub kind: Option<InlayHintKind>,
|
||||
|
||||
/// Optional text edits that are performed when accepting this inlay hint.
|
||||
///
|
||||
/// *Note* that edits are expected to change the document so that the inlay
|
||||
/// hint (or its nearest variant) is now part of the document and the inlay
|
||||
/// hint itself is now obsolete.
|
||||
///
|
||||
/// Depending on the client capability `inlayHint.resolveSupport` clients
|
||||
/// might resolve this property late using the resolve request.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub text_edits: Option<Vec<TextEdit>>,
|
||||
|
||||
/// The tooltip text when you hover over this item.
|
||||
///
|
||||
/// Depending on the client capability `inlayHint.resolveSupport` clients
|
||||
/// might resolve this property late using the resolve request.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub tooltip: Option<InlayHintTooltip>,
|
||||
|
||||
/// Render padding before the hint.
|
||||
///
|
||||
/// Note: Padding should use the editor's background color, not the
|
||||
/// background color of the hint itself. That means padding can be used
|
||||
/// to visually align/separate an inlay hint.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub padding_left: Option<bool>,
|
||||
|
||||
/// Render padding after the hint.
|
||||
///
|
||||
/// Note: Padding should use the editor's background color, not the
|
||||
/// background color of the hint itself. That means padding can be used
|
||||
/// to visually align/separate an inlay hint.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub padding_right: Option<bool>,
|
||||
|
||||
/// A data entry field that is preserved on a inlay hint between
|
||||
/// a `textDocument/inlayHint` and a `inlayHint/resolve` request.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub data: Option<LSPAny>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum InlayHintLabel {
|
||||
String(String),
|
||||
LabelParts(Vec<InlayHintLabelPart>),
|
||||
}
|
||||
|
||||
impl From<String> for InlayHintLabel {
|
||||
#[inline]
|
||||
fn from(from: String) -> Self {
|
||||
Self::String(from)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<InlayHintLabelPart>> for InlayHintLabel {
|
||||
#[inline]
|
||||
fn from(from: Vec<InlayHintLabelPart>) -> Self {
|
||||
Self::LabelParts(from)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum InlayHintTooltip {
|
||||
String(String),
|
||||
MarkupContent(MarkupContent),
|
||||
}
|
||||
|
||||
impl From<String> for InlayHintTooltip {
|
||||
#[inline]
|
||||
fn from(from: String) -> Self {
|
||||
Self::String(from)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<MarkupContent> for InlayHintTooltip {
|
||||
#[inline]
|
||||
fn from(from: MarkupContent) -> Self {
|
||||
Self::MarkupContent(from)
|
||||
}
|
||||
}
|
||||
|
||||
/// An inlay hint label part allows for interactive and composite labels
|
||||
/// of inlay hints.
|
||||
#[derive(Debug, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct InlayHintLabelPart {
|
||||
/// The value of this label part.
|
||||
pub value: String,
|
||||
|
||||
/// The tooltip text when you hover over this label part. Depending on
|
||||
/// the client capability `inlayHint.resolveSupport` clients might resolve
|
||||
/// this property late using the resolve request.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub tooltip: Option<InlayHintLabelPartTooltip>,
|
||||
|
||||
/// An optional source code location that represents this
|
||||
/// label part.
|
||||
///
|
||||
/// The editor will use this location for the hover and for code navigation
|
||||
/// features: This part will become a clickable link that resolves to the
|
||||
/// definition of the symbol at the given location (not necessarily the
|
||||
/// location itself), it shows the hover that shows at the given location,
|
||||
/// and it shows a context menu with further code navigation commands.
|
||||
///
|
||||
/// Depending on the client capability `inlayHint.resolveSupport` clients
|
||||
/// might resolve this property late using the resolve request.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub location: Option<Location>,
|
||||
|
||||
/// An optional command for this label part.
|
||||
///
|
||||
/// Depending on the client capability `inlayHint.resolveSupport` clients
|
||||
/// might resolve this property late using the resolve request.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub command: Option<Command>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum InlayHintLabelPartTooltip {
|
||||
String(String),
|
||||
MarkupContent(MarkupContent),
|
||||
}
|
||||
|
||||
impl From<String> for InlayHintLabelPartTooltip {
|
||||
#[inline]
|
||||
fn from(from: String) -> Self {
|
||||
Self::String(from)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<MarkupContent> for InlayHintLabelPartTooltip {
|
||||
#[inline]
|
||||
fn from(from: MarkupContent) -> Self {
|
||||
Self::MarkupContent(from)
|
||||
}
|
||||
}
|
||||
|
||||
/// Inlay hint kinds.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Eq, PartialEq, Copy, Clone, Serialize, Deserialize)]
|
||||
#[serde(transparent)]
|
||||
pub struct InlayHintKind(i32);
|
||||
lsp_enum! {
|
||||
impl InlayHintKind {
|
||||
/// An inlay hint that for a type annotation.
|
||||
pub const TYPE: InlayHintKind = InlayHintKind(1);
|
||||
|
||||
/// An inlay hint that is for a parameter.
|
||||
pub const PARAMETER: InlayHintKind = InlayHintKind(2);
|
||||
}
|
||||
}
|
||||
|
||||
/// Inlay hint client capabilities.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct InlayHintResolveClientCapabilities {
|
||||
/// The properties that a client can resolve lazily.
|
||||
pub properties: Vec<String>,
|
||||
}
|
||||
|
||||
/// Client workspace capabilities specific to inlay hints.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct InlayHintWorkspaceClientCapabilities {
|
||||
/// Whether the client implementation supports a refresh request sent from
|
||||
/// the server to the client.
|
||||
///
|
||||
/// Note that this event is global and will force the client to refresh all
|
||||
/// inlay hints currently shown. It should be used with absolute care and
|
||||
/// is useful for situation where a server for example detects a project wide
|
||||
/// change that requires such a calculation.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub refresh_support: Option<bool>,
|
||||
}
|
||||
|
||||
// TODO(sno2): add tests once stabilized
|
162
helix-lsp-types/src/inline_completion.rs
Normal file
162
helix-lsp-types/src/inline_completion.rs
Normal file
@ -0,0 +1,162 @@
|
||||
use crate::{
|
||||
Command, InsertTextFormat, Range, StaticRegistrationOptions, TextDocumentPositionParams,
|
||||
TextDocumentRegistrationOptions, WorkDoneProgressOptions, WorkDoneProgressParams,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// Client capabilities specific to inline completions.
|
||||
///
|
||||
/// @since 3.18.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct InlineCompletionClientCapabilities {
|
||||
/// Whether implementation supports dynamic registration for inline completion providers.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub dynamic_registration: Option<bool>,
|
||||
}
|
||||
|
||||
/// Inline completion options used during static registration.
|
||||
///
|
||||
/// @since 3.18.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
pub struct InlineCompletionOptions {
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_options: WorkDoneProgressOptions,
|
||||
}
|
||||
|
||||
/// Inline completion options used during static or dynamic registration.
|
||||
///
|
||||
// @since 3.18.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
pub struct InlineCompletionRegistrationOptions {
|
||||
#[serde(flatten)]
|
||||
pub inline_completion_options: InlineCompletionOptions,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub text_document_registration_options: TextDocumentRegistrationOptions,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub static_registration_options: StaticRegistrationOptions,
|
||||
}
|
||||
|
||||
/// A parameter literal used in inline completion requests.
|
||||
///
|
||||
/// @since 3.18.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct InlineCompletionParams {
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_params: WorkDoneProgressParams,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub text_document_position: TextDocumentPositionParams,
|
||||
|
||||
/// Additional information about the context in which inline completions were requested.
|
||||
pub context: InlineCompletionContext,
|
||||
}
|
||||
|
||||
/// Describes how an [`InlineCompletionItemProvider`] was triggered.
|
||||
///
|
||||
/// @since 3.18.0
|
||||
#[derive(Eq, PartialEq, Clone, Copy, Deserialize, Serialize)]
|
||||
pub struct InlineCompletionTriggerKind(i32);
|
||||
lsp_enum! {
|
||||
impl InlineCompletionTriggerKind {
|
||||
/// Completion was triggered explicitly by a user gesture.
|
||||
/// Return multiple completion items to enable cycling through them.
|
||||
pub const Invoked: InlineCompletionTriggerKind = InlineCompletionTriggerKind(1);
|
||||
|
||||
/// Completion was triggered automatically while editing.
|
||||
/// It is sufficient to return a single completion item in this case.
|
||||
pub const Automatic: InlineCompletionTriggerKind = InlineCompletionTriggerKind(2);
|
||||
}
|
||||
}
|
||||
|
||||
/// Describes the currently selected completion item.
|
||||
///
|
||||
/// @since 3.18.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
pub struct SelectedCompletionInfo {
|
||||
/// The range that will be replaced if this completion item is accepted.
|
||||
pub range: Range,
|
||||
/// The text the range will be replaced with if this completion is
|
||||
/// accepted.
|
||||
pub text: String,
|
||||
}
|
||||
|
||||
/// Provides information about the context in which an inline completion was
|
||||
/// requested.
|
||||
///
|
||||
/// @since 3.18.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct InlineCompletionContext {
|
||||
/// Describes how the inline completion was triggered.
|
||||
pub trigger_kind: InlineCompletionTriggerKind,
|
||||
/// Provides information about the currently selected item in the
|
||||
/// autocomplete widget if it is visible.
|
||||
///
|
||||
/// If set, provided inline completions must extend the text of the
|
||||
/// selected item and use the same range, otherwise they are not shown as
|
||||
/// preview.
|
||||
/// As an example, if the document text is `console.` and the selected item
|
||||
/// is `.log` replacing the `.` in the document, the inline completion must
|
||||
/// also replace `.` and start with `.log`, for example `.log()`.
|
||||
///
|
||||
/// Inline completion providers are requested again whenever the selected
|
||||
/// item changes.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub selected_completion_info: Option<SelectedCompletionInfo>,
|
||||
}
|
||||
|
||||
/// InlineCompletion response can be multiple completion items, or a list of completion items
|
||||
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum InlineCompletionResponse {
|
||||
Array(Vec<InlineCompletionItem>),
|
||||
List(InlineCompletionList),
|
||||
}
|
||||
|
||||
/// Represents a collection of [`InlineCompletionItem`] to be presented in the editor.
|
||||
///
|
||||
/// @since 3.18.0
|
||||
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
|
||||
pub struct InlineCompletionList {
|
||||
/// The inline completion items
|
||||
pub items: Vec<InlineCompletionItem>,
|
||||
}
|
||||
|
||||
/// An inline completion item represents a text snippet that is proposed inline
|
||||
/// to complete text that is being typed.
|
||||
///
|
||||
/// @since 3.18.0
|
||||
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct InlineCompletionItem {
|
||||
/// The text to replace the range with. Must be set.
|
||||
/// Is used both for the preview and the accept operation.
|
||||
pub insert_text: String,
|
||||
/// A text that is used to decide if this inline completion should be
|
||||
/// shown. When `falsy` the [`InlineCompletionItem::insertText`] is
|
||||
/// used.
|
||||
///
|
||||
/// An inline completion is shown if the text to replace is a prefix of the
|
||||
/// filter text.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub filter_text: Option<String>,
|
||||
/// The range to replace.
|
||||
/// Must begin and end on the same line.
|
||||
///
|
||||
/// Prefer replacements over insertions to provide a better experience when
|
||||
/// the user deletes typed text.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub range: Option<Range>,
|
||||
/// An optional command that is executed *after* inserting this
|
||||
/// completion.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub command: Option<Command>,
|
||||
/// The format of the insert text. The format applies to the `insertText`.
|
||||
/// If omitted defaults to `InsertTextFormat.PlainText`.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub insert_text_format: Option<InsertTextFormat>,
|
||||
}
|
217
helix-lsp-types/src/inline_value.rs
Normal file
217
helix-lsp-types/src/inline_value.rs
Normal file
@ -0,0 +1,217 @@
|
||||
use crate::{
|
||||
DynamicRegistrationClientCapabilities, Range, StaticRegistrationOptions,
|
||||
TextDocumentIdentifier, TextDocumentRegistrationOptions, WorkDoneProgressOptions,
|
||||
WorkDoneProgressParams,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub type InlineValueClientCapabilities = DynamicRegistrationClientCapabilities;
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum InlineValueServerCapabilities {
|
||||
Options(InlineValueOptions),
|
||||
RegistrationOptions(InlineValueRegistrationOptions),
|
||||
}
|
||||
|
||||
/// Inline value options used during static registration.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
pub struct InlineValueOptions {
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_options: WorkDoneProgressOptions,
|
||||
}
|
||||
|
||||
/// Inline value options used during static or dynamic registration.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
pub struct InlineValueRegistrationOptions {
|
||||
#[serde(flatten)]
|
||||
pub inline_value_options: InlineValueOptions,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub text_document_registration_options: TextDocumentRegistrationOptions,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub static_registration_options: StaticRegistrationOptions,
|
||||
}
|
||||
|
||||
/// A parameter literal used in inline value requests.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct InlineValueParams {
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_params: WorkDoneProgressParams,
|
||||
|
||||
/// The text document.
|
||||
pub text_document: TextDocumentIdentifier,
|
||||
|
||||
/// The document range for which inline values should be computed.
|
||||
pub range: Range,
|
||||
|
||||
/// Additional information about the context in which inline values were
|
||||
/// requested.
|
||||
pub context: InlineValueContext,
|
||||
}
|
||||
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct InlineValueContext {
|
||||
/// The stack frame (as a DAP Id) where the execution has stopped.
|
||||
pub frame_id: i32,
|
||||
|
||||
/// The document range where execution has stopped.
|
||||
/// Typically the end position of the range denotes the line where the
|
||||
/// inline values are shown.
|
||||
pub stopped_location: Range,
|
||||
}
|
||||
|
||||
/// Provide inline value as text.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
pub struct InlineValueText {
|
||||
/// The document range for which the inline value applies.
|
||||
pub range: Range,
|
||||
|
||||
/// The text of the inline value.
|
||||
pub text: String,
|
||||
}
|
||||
|
||||
/// Provide inline value through a variable lookup.
|
||||
///
|
||||
/// If only a range is specified, the variable name will be extracted from
|
||||
/// the underlying document.
|
||||
///
|
||||
/// An optional variable name can be used to override the extracted name.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct InlineValueVariableLookup {
|
||||
/// The document range for which the inline value applies.
|
||||
/// The range is used to extract the variable name from the underlying
|
||||
/// document.
|
||||
pub range: Range,
|
||||
|
||||
/// If specified the name of the variable to look up.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub variable_name: Option<String>,
|
||||
|
||||
/// How to perform the lookup.
|
||||
pub case_sensitive_lookup: bool,
|
||||
}
|
||||
|
||||
/// Provide an inline value through an expression evaluation.
|
||||
///
|
||||
/// If only a range is specified, the expression will be extracted from the
|
||||
/// underlying document.
|
||||
///
|
||||
/// An optional expression can be used to override the extracted expression.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct InlineValueEvaluatableExpression {
|
||||
/// The document range for which the inline value applies.
|
||||
/// The range is used to extract the evaluatable expression from the
|
||||
/// underlying document.
|
||||
pub range: Range,
|
||||
|
||||
/// If specified the expression overrides the extracted expression.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub expression: Option<String>,
|
||||
}
|
||||
|
||||
/// Inline value information can be provided by different means:
|
||||
/// - directly as a text value (class InlineValueText).
|
||||
/// - as a name to use for a variable lookup (class InlineValueVariableLookup)
|
||||
/// - as an evaluatable expression (class InlineValueEvaluatableExpression)
|
||||
/// The InlineValue types combines all inline value types into one type.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum InlineValue {
|
||||
Text(InlineValueText),
|
||||
VariableLookup(InlineValueVariableLookup),
|
||||
EvaluatableExpression(InlineValueEvaluatableExpression),
|
||||
}
|
||||
|
||||
impl From<InlineValueText> for InlineValue {
|
||||
#[inline]
|
||||
fn from(from: InlineValueText) -> Self {
|
||||
Self::Text(from)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<InlineValueVariableLookup> for InlineValue {
|
||||
#[inline]
|
||||
fn from(from: InlineValueVariableLookup) -> Self {
|
||||
Self::VariableLookup(from)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<InlineValueEvaluatableExpression> for InlineValue {
|
||||
#[inline]
|
||||
fn from(from: InlineValueEvaluatableExpression) -> Self {
|
||||
Self::EvaluatableExpression(from)
|
||||
}
|
||||
}
|
||||
|
||||
/// Client workspace capabilities specific to inline values.
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct InlineValueWorkspaceClientCapabilities {
|
||||
/// Whether the client implementation supports a refresh request sent from
|
||||
/// the server to the client.
|
||||
///
|
||||
/// Note that this event is global and will force the client to refresh all
|
||||
/// inline values currently shown. It should be used with absolute care and
|
||||
/// is useful for situation where a server for example detect a project wide
|
||||
/// change that requires such a calculation.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub refresh_support: Option<bool>,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::tests::test_serialization;
|
||||
use crate::Position;
|
||||
|
||||
#[test]
|
||||
fn inline_values() {
|
||||
test_serialization(
|
||||
&InlineValueText {
|
||||
range: Range::new(Position::new(0, 0), Position::new(0, 4)),
|
||||
text: "one".to_owned(),
|
||||
},
|
||||
r#"{"range":{"start":{"line":0,"character":0},"end":{"line":0,"character":4}},"text":"one"}"#,
|
||||
);
|
||||
|
||||
test_serialization(
|
||||
&InlineValue::VariableLookup(InlineValueVariableLookup {
|
||||
range: Range::new(Position::new(1, 0), Position::new(1, 4)),
|
||||
variable_name: None,
|
||||
case_sensitive_lookup: false,
|
||||
}),
|
||||
r#"{"range":{"start":{"line":1,"character":0},"end":{"line":1,"character":4}},"caseSensitiveLookup":false}"#,
|
||||
);
|
||||
|
||||
test_serialization(
|
||||
&InlineValue::EvaluatableExpression(InlineValueEvaluatableExpression {
|
||||
range: Range::new(Position::new(2, 0), Position::new(2, 4)),
|
||||
expression: None,
|
||||
}),
|
||||
r#"{"range":{"start":{"line":2,"character":0},"end":{"line":2,"character":4}}}"#,
|
||||
);
|
||||
}
|
||||
}
|
2883
helix-lsp-types/src/lib.rs
Normal file
2883
helix-lsp-types/src/lib.rs
Normal file
File diff suppressed because it is too large
Load Diff
61
helix-lsp-types/src/linked_editing.rs
Normal file
61
helix-lsp-types/src/linked_editing.rs
Normal file
@ -0,0 +1,61 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
DynamicRegistrationClientCapabilities, Range, StaticRegistrationOptions,
|
||||
TextDocumentPositionParams, TextDocumentRegistrationOptions, WorkDoneProgressOptions,
|
||||
WorkDoneProgressParams,
|
||||
};
|
||||
|
||||
pub type LinkedEditingRangeClientCapabilities = DynamicRegistrationClientCapabilities;
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct LinkedEditingRangeOptions {
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_options: WorkDoneProgressOptions,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct LinkedEditingRangeRegistrationOptions {
|
||||
#[serde(flatten)]
|
||||
pub text_document_registration_options: TextDocumentRegistrationOptions,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub linked_editing_range_options: LinkedEditingRangeOptions,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub static_registration_options: StaticRegistrationOptions,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum LinkedEditingRangeServerCapabilities {
|
||||
Simple(bool),
|
||||
Options(LinkedEditingRangeOptions),
|
||||
RegistrationOptions(LinkedEditingRangeRegistrationOptions),
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct LinkedEditingRangeParams {
|
||||
#[serde(flatten)]
|
||||
pub text_document_position_params: TextDocumentPositionParams,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_params: WorkDoneProgressParams,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct LinkedEditingRanges {
|
||||
/// A list of ranges that can be renamed together. The ranges must have
|
||||
/// identical length and contain identical text content. The ranges cannot overlap.
|
||||
pub ranges: Vec<Range>,
|
||||
|
||||
/// An optional word pattern (regular expression) that describes valid contents for
|
||||
/// the given ranges. If no pattern is provided, the client configuration's word
|
||||
/// pattern will be used.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub word_pattern: Option<String>,
|
||||
}
|
336
helix-lsp-types/src/lsif.rs
Normal file
336
helix-lsp-types/src/lsif.rs
Normal file
@ -0,0 +1,336 @@
|
||||
//! Types of Language Server Index Format (LSIF). LSIF is a standard format
|
||||
//! for language servers or other programming tools to dump their knowledge
|
||||
//! about a workspace.
|
||||
//!
|
||||
//! Based on <https://microsoft.github.io/language-server-protocol/specifications/lsif/0.6.0/specification/>
|
||||
|
||||
use crate::{Range, Url};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub type Id = crate::NumberOrString;
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum LocationOrRangeId {
|
||||
Location(crate::Location),
|
||||
RangeId(Id),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Entry {
|
||||
pub id: Id,
|
||||
#[serde(flatten)]
|
||||
pub data: Element,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[serde(tag = "type")]
|
||||
pub enum Element {
|
||||
Vertex(Vertex),
|
||||
Edge(Edge),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct ToolInfo {
|
||||
pub name: String,
|
||||
#[serde(default = "Default::default")]
|
||||
#[serde(skip_serializing_if = "Vec::is_empty")]
|
||||
pub args: Vec<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub version: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone, Copy)]
|
||||
pub enum Encoding {
|
||||
/// Currently only 'utf-16' is supported due to the limitations in LSP.
|
||||
#[serde(rename = "utf-16")]
|
||||
Utf16,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct RangeBasedDocumentSymbol {
|
||||
pub id: Id,
|
||||
#[serde(default = "Default::default")]
|
||||
#[serde(skip_serializing_if = "Vec::is_empty")]
|
||||
pub children: Vec<RangeBasedDocumentSymbol>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[serde(untagged)]
|
||||
pub enum DocumentSymbolOrRangeBasedVec {
|
||||
DocumentSymbol(Vec<crate::DocumentSymbol>),
|
||||
RangeBased(Vec<RangeBasedDocumentSymbol>),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DefinitionTag {
|
||||
/// The text covered by the range
|
||||
text: String,
|
||||
/// The symbol kind.
|
||||
kind: crate::SymbolKind,
|
||||
/// Indicates if this symbol is deprecated.
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "std::ops::Not::not")]
|
||||
deprecated: bool,
|
||||
/// The full range of the definition not including leading/trailing whitespace but everything else, e.g comments and code.
|
||||
/// The range must be included in fullRange.
|
||||
full_range: Range,
|
||||
/// Optional detail information for the definition.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
detail: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DeclarationTag {
|
||||
/// The text covered by the range
|
||||
text: String,
|
||||
/// The symbol kind.
|
||||
kind: crate::SymbolKind,
|
||||
/// Indicates if this symbol is deprecated.
|
||||
#[serde(default)]
|
||||
deprecated: bool,
|
||||
/// The full range of the definition not including leading/trailing whitespace but everything else, e.g comments and code.
|
||||
/// The range must be included in fullRange.
|
||||
full_range: Range,
|
||||
/// Optional detail information for the definition.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
detail: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ReferenceTag {
|
||||
text: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct UnknownTag {
|
||||
text: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[serde(tag = "type")]
|
||||
pub enum RangeTag {
|
||||
Definition(DefinitionTag),
|
||||
Declaration(DeclarationTag),
|
||||
Reference(ReferenceTag),
|
||||
Unknown(UnknownTag),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[serde(tag = "label")]
|
||||
pub enum Vertex {
|
||||
MetaData(MetaData),
|
||||
/// <https://github.com/Microsoft/language-server-protocol/blob/master/indexFormat/specification.md#the-project-vertex>
|
||||
Project(Project),
|
||||
Document(Document),
|
||||
/// <https://github.com/Microsoft/language-server-protocol/blob/master/indexFormat/specification.md#ranges>
|
||||
Range {
|
||||
#[serde(flatten)]
|
||||
range: Range,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
tag: Option<RangeTag>,
|
||||
},
|
||||
/// <https://github.com/Microsoft/language-server-protocol/blob/master/indexFormat/specification.md#result-set>
|
||||
ResultSet(ResultSet),
|
||||
Moniker(crate::Moniker),
|
||||
PackageInformation(PackageInformation),
|
||||
|
||||
#[serde(rename = "$event")]
|
||||
Event(Event),
|
||||
|
||||
DefinitionResult,
|
||||
DeclarationResult,
|
||||
TypeDefinitionResult,
|
||||
ReferenceResult,
|
||||
ImplementationResult,
|
||||
FoldingRangeResult {
|
||||
result: Vec<crate::FoldingRange>,
|
||||
},
|
||||
HoverResult {
|
||||
result: crate::Hover,
|
||||
},
|
||||
DocumentSymbolResult {
|
||||
result: DocumentSymbolOrRangeBasedVec,
|
||||
},
|
||||
DocumentLinkResult {
|
||||
result: Vec<crate::DocumentLink>,
|
||||
},
|
||||
DiagnosticResult {
|
||||
result: Vec<crate::Diagnostic>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum EventKind {
|
||||
Begin,
|
||||
End,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum EventScope {
|
||||
Document,
|
||||
Project,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Event {
|
||||
pub kind: EventKind,
|
||||
pub scope: EventScope,
|
||||
pub data: Id,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[serde(tag = "label")]
|
||||
pub enum Edge {
|
||||
Contains(EdgeDataMultiIn),
|
||||
Moniker(EdgeData),
|
||||
NextMoniker(EdgeData),
|
||||
Next(EdgeData),
|
||||
PackageInformation(EdgeData),
|
||||
Item(Item),
|
||||
|
||||
// Methods
|
||||
#[serde(rename = "textDocument/definition")]
|
||||
Definition(EdgeData),
|
||||
#[serde(rename = "textDocument/declaration")]
|
||||
Declaration(EdgeData),
|
||||
#[serde(rename = "textDocument/hover")]
|
||||
Hover(EdgeData),
|
||||
#[serde(rename = "textDocument/references")]
|
||||
References(EdgeData),
|
||||
#[serde(rename = "textDocument/implementation")]
|
||||
Implementation(EdgeData),
|
||||
#[serde(rename = "textDocument/typeDefinition")]
|
||||
TypeDefinition(EdgeData),
|
||||
#[serde(rename = "textDocument/foldingRange")]
|
||||
FoldingRange(EdgeData),
|
||||
#[serde(rename = "textDocument/documentLink")]
|
||||
DocumentLink(EdgeData),
|
||||
#[serde(rename = "textDocument/documentSymbol")]
|
||||
DocumentSymbol(EdgeData),
|
||||
#[serde(rename = "textDocument/diagnostic")]
|
||||
Diagnostic(EdgeData),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct EdgeData {
|
||||
pub in_v: Id,
|
||||
pub out_v: Id,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct EdgeDataMultiIn {
|
||||
pub in_vs: Vec<Id>,
|
||||
pub out_v: Id,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum DefinitionResultType {
|
||||
Scalar(LocationOrRangeId),
|
||||
Array(LocationOrRangeId),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum ItemKind {
|
||||
Declarations,
|
||||
Definitions,
|
||||
References,
|
||||
ReferenceResults,
|
||||
ImplementationResults,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Item {
|
||||
pub document: Id,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub property: Option<ItemKind>,
|
||||
#[serde(flatten)]
|
||||
pub edge_data: EdgeDataMultiIn,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Document {
|
||||
pub uri: Url,
|
||||
pub language_id: String,
|
||||
}
|
||||
|
||||
/// <https://github.com/Microsoft/language-server-protocol/blob/master/indexFormat/specification.md#result-set>
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ResultSet {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub key: Option<String>,
|
||||
}
|
||||
|
||||
/// <https://github.com/Microsoft/language-server-protocol/blob/master/indexFormat/specification.md#the-project-vertex>
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Project {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub resource: Option<Url>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub content: Option<String>,
|
||||
pub kind: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct MetaData {
|
||||
/// The version of the LSIF format using semver notation. See <https://semver.org/>. Please note
|
||||
/// the version numbers starting with 0 don't adhere to semver and adopters have to assume
|
||||
/// that each new version is breaking.
|
||||
pub version: String,
|
||||
|
||||
/// The project root (in form of an URI) used to compute this dump.
|
||||
pub project_root: Url,
|
||||
|
||||
/// The string encoding used to compute line and character values in
|
||||
/// positions and ranges.
|
||||
pub position_encoding: Encoding,
|
||||
|
||||
/// Information about the tool that created the dump
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub tool_info: Option<ToolInfo>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Repository {
|
||||
pub r#type: String,
|
||||
pub url: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub commit_id: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PackageInformation {
|
||||
pub name: String,
|
||||
pub manager: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub uri: Option<Url>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub content: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub repository: Option<Repository>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub version: Option<String>,
|
||||
}
|
92
helix-lsp-types/src/moniker.rs
Normal file
92
helix-lsp-types/src/moniker.rs
Normal file
@ -0,0 +1,92 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
DynamicRegistrationClientCapabilities, PartialResultParams, TextDocumentPositionParams,
|
||||
TextDocumentRegistrationOptions, WorkDoneProgressOptions, WorkDoneProgressParams,
|
||||
};
|
||||
|
||||
pub type MonikerClientCapabilities = DynamicRegistrationClientCapabilities;
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum MonikerServerCapabilities {
|
||||
Options(MonikerOptions),
|
||||
RegistrationOptions(MonikerRegistrationOptions),
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
pub struct MonikerOptions {
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_options: WorkDoneProgressOptions,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct MonikerRegistrationOptions {
|
||||
#[serde(flatten)]
|
||||
pub text_document_registration_options: TextDocumentRegistrationOptions,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub moniker_options: MonikerOptions,
|
||||
}
|
||||
|
||||
/// Moniker uniqueness level to define scope of the moniker.
|
||||
#[derive(Debug, Eq, PartialEq, Deserialize, Serialize, Copy, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum UniquenessLevel {
|
||||
/// The moniker is only unique inside a document
|
||||
Document,
|
||||
/// The moniker is unique inside a project for which a dump got created
|
||||
Project,
|
||||
/// The moniker is unique inside the group to which a project belongs
|
||||
Group,
|
||||
/// The moniker is unique inside the moniker scheme.
|
||||
Scheme,
|
||||
/// The moniker is globally unique
|
||||
Global,
|
||||
}
|
||||
|
||||
/// The moniker kind.
|
||||
#[derive(Debug, Eq, PartialEq, Deserialize, Serialize, Copy, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum MonikerKind {
|
||||
/// The moniker represent a symbol that is imported into a project
|
||||
Import,
|
||||
/// The moniker represent a symbol that is exported into a project
|
||||
Export,
|
||||
/// The moniker represents a symbol that is local to a project (e.g. a local
|
||||
/// variable of a function, a class not visible outside the project, ...)
|
||||
Local,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct MonikerParams {
|
||||
#[serde(flatten)]
|
||||
pub text_document_position_params: TextDocumentPositionParams,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_params: WorkDoneProgressParams,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub partial_result_params: PartialResultParams,
|
||||
}
|
||||
|
||||
/// Moniker definition to match LSIF 0.5 moniker definition.
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Moniker {
|
||||
/// The scheme of the moniker. For example tsc or .Net
|
||||
pub scheme: String,
|
||||
|
||||
/// The identifier of the moniker. The value is opaque in LSIF however
|
||||
/// schema owners are allowed to define the structure if they want.
|
||||
pub identifier: String,
|
||||
|
||||
/// The scope in which the moniker is unique
|
||||
pub unique: UniquenessLevel,
|
||||
|
||||
/// The moniker kind if known.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub kind: Option<MonikerKind>,
|
||||
}
|
361
helix-lsp-types/src/notification.rs
Normal file
361
helix-lsp-types/src/notification.rs
Normal file
@ -0,0 +1,361 @@
|
||||
use super::*;
|
||||
|
||||
use serde::{de::DeserializeOwned, Serialize};
|
||||
|
||||
pub trait Notification {
|
||||
type Params: DeserializeOwned + Serialize + Send + Sync + 'static;
|
||||
const METHOD: &'static str;
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! lsp_notification {
|
||||
("$/cancelRequest") => {
|
||||
$crate::notification::Cancel
|
||||
};
|
||||
("$/setTrace") => {
|
||||
$crate::notification::SetTrace
|
||||
};
|
||||
("$/logTrace") => {
|
||||
$crate::notification::LogTrace
|
||||
};
|
||||
("initialized") => {
|
||||
$crate::notification::Initialized
|
||||
};
|
||||
("exit") => {
|
||||
$crate::notification::Exit
|
||||
};
|
||||
|
||||
("window/showMessage") => {
|
||||
$crate::notification::ShowMessage
|
||||
};
|
||||
("window/logMessage") => {
|
||||
$crate::notification::LogMessage
|
||||
};
|
||||
("window/workDoneProgress/cancel") => {
|
||||
$crate::notification::WorkDoneProgressCancel
|
||||
};
|
||||
|
||||
("telemetry/event") => {
|
||||
$crate::notification::TelemetryEvent
|
||||
};
|
||||
|
||||
("textDocument/didOpen") => {
|
||||
$crate::notification::DidOpenTextDocument
|
||||
};
|
||||
("textDocument/didChange") => {
|
||||
$crate::notification::DidChangeTextDocument
|
||||
};
|
||||
("textDocument/willSave") => {
|
||||
$crate::notification::WillSaveTextDocument
|
||||
};
|
||||
("textDocument/didSave") => {
|
||||
$crate::notification::DidSaveTextDocument
|
||||
};
|
||||
("textDocument/didClose") => {
|
||||
$crate::notification::DidCloseTextDocument
|
||||
};
|
||||
("textDocument/publishDiagnostics") => {
|
||||
$crate::notification::PublishDiagnostics
|
||||
};
|
||||
|
||||
("workspace/didChangeConfiguration") => {
|
||||
$crate::notification::DidChangeConfiguration
|
||||
};
|
||||
("workspace/didChangeWatchedFiles") => {
|
||||
$crate::notification::DidChangeWatchedFiles
|
||||
};
|
||||
("workspace/didChangeWorkspaceFolders") => {
|
||||
$crate::notification::DidChangeWorkspaceFolders
|
||||
};
|
||||
("$/progress") => {
|
||||
$crate::notification::Progress
|
||||
};
|
||||
("workspace/didCreateFiles") => {
|
||||
$crate::notification::DidCreateFiles
|
||||
};
|
||||
("workspace/didRenameFiles") => {
|
||||
$crate::notification::DidRenameFiles
|
||||
};
|
||||
("workspace/didDeleteFiles") => {
|
||||
$crate::notification::DidDeleteFiles
|
||||
};
|
||||
}
|
||||
|
||||
/// The base protocol now offers support for request cancellation. To cancel a request,
|
||||
/// a notification message with the following properties is sent:
|
||||
///
|
||||
/// A request that got canceled still needs to return from the server and send a response back.
|
||||
/// It can not be left open / hanging. This is in line with the JSON RPC protocol that requires
|
||||
/// that every request sends a response back. In addition it allows for returning partial results on cancel.
|
||||
#[derive(Debug)]
|
||||
pub enum Cancel {}
|
||||
|
||||
impl Notification for Cancel {
|
||||
type Params = CancelParams;
|
||||
const METHOD: &'static str = "$/cancelRequest";
|
||||
}
|
||||
|
||||
/// A notification that should be used by the client to modify the trace
|
||||
/// setting of the server.
|
||||
#[derive(Debug)]
|
||||
pub enum SetTrace {}
|
||||
|
||||
impl Notification for SetTrace {
|
||||
type Params = SetTraceParams;
|
||||
const METHOD: &'static str = "$/setTrace";
|
||||
}
|
||||
|
||||
/// A notification to log the trace of the server’s execution.
|
||||
/// The amount and content of these notifications depends on the current trace configuration.
|
||||
///
|
||||
/// `LogTrace` should be used for systematic trace reporting. For single debugging messages,
|
||||
/// the server should send `LogMessage` notifications.
|
||||
#[derive(Debug)]
|
||||
pub enum LogTrace {}
|
||||
|
||||
impl Notification for LogTrace {
|
||||
type Params = LogTraceParams;
|
||||
const METHOD: &'static str = "$/logTrace";
|
||||
}
|
||||
|
||||
/// The initialized notification is sent from the client to the server after the client received
|
||||
/// the result of the initialize request but before the client is sending any other request or
|
||||
/// notification to the server. The server can use the initialized notification for example to
|
||||
/// dynamically register capabilities.
|
||||
#[derive(Debug)]
|
||||
pub enum Initialized {}
|
||||
|
||||
impl Notification for Initialized {
|
||||
type Params = InitializedParams;
|
||||
const METHOD: &'static str = "initialized";
|
||||
}
|
||||
|
||||
/// A notification to ask the server to exit its process.
|
||||
/// The server should exit with success code 0 if the shutdown request has been received before;
|
||||
/// otherwise with error code 1.
|
||||
#[derive(Debug)]
|
||||
pub enum Exit {}
|
||||
|
||||
impl Notification for Exit {
|
||||
type Params = ();
|
||||
const METHOD: &'static str = "exit";
|
||||
}
|
||||
|
||||
/// The show message notification is sent from a server to a client to ask the client to display a particular message
|
||||
/// in the user interface.
|
||||
#[derive(Debug)]
|
||||
pub enum ShowMessage {}
|
||||
|
||||
impl Notification for ShowMessage {
|
||||
type Params = ShowMessageParams;
|
||||
const METHOD: &'static str = "window/showMessage";
|
||||
}
|
||||
|
||||
/// The log message notification is sent from the server to the client to ask the client to log a particular message.
|
||||
#[derive(Debug)]
|
||||
pub enum LogMessage {}
|
||||
|
||||
impl Notification for LogMessage {
|
||||
type Params = LogMessageParams;
|
||||
const METHOD: &'static str = "window/logMessage";
|
||||
}
|
||||
|
||||
/// The telemetry notification is sent from the server to the client to ask the client to log a telemetry event.
|
||||
/// The protocol doesn't specify the payload since no interpretation of the data happens in the protocol. Most clients even don't handle
|
||||
/// the event directly but forward them to the extensions owning the corresponding server issuing the event.
|
||||
#[derive(Debug)]
|
||||
pub enum TelemetryEvent {}
|
||||
|
||||
impl Notification for TelemetryEvent {
|
||||
type Params = OneOf<LSPObject, LSPArray>;
|
||||
const METHOD: &'static str = "telemetry/event";
|
||||
}
|
||||
|
||||
/// A notification sent from the client to the server to signal the change of configuration settings.
|
||||
#[derive(Debug)]
|
||||
pub enum DidChangeConfiguration {}
|
||||
|
||||
impl Notification for DidChangeConfiguration {
|
||||
type Params = DidChangeConfigurationParams;
|
||||
const METHOD: &'static str = "workspace/didChangeConfiguration";
|
||||
}
|
||||
|
||||
/// The document open notification is sent from the client to the server to signal newly opened text documents.
|
||||
/// The document's truth is now managed by the client and the server must not try to read the document's truth
|
||||
/// using the document's uri.
|
||||
#[derive(Debug)]
|
||||
pub enum DidOpenTextDocument {}
|
||||
|
||||
impl Notification for DidOpenTextDocument {
|
||||
type Params = DidOpenTextDocumentParams;
|
||||
const METHOD: &'static str = "textDocument/didOpen";
|
||||
}
|
||||
|
||||
/// The document change notification is sent from the client to the server to signal changes to a text document.
|
||||
/// In 2.0 the shape of the params has changed to include proper version numbers and language ids.
|
||||
#[derive(Debug)]
|
||||
pub enum DidChangeTextDocument {}
|
||||
|
||||
impl Notification for DidChangeTextDocument {
|
||||
type Params = DidChangeTextDocumentParams;
|
||||
const METHOD: &'static str = "textDocument/didChange";
|
||||
}
|
||||
|
||||
/// The document will save notification is sent from the client to the server before the document
|
||||
/// is actually saved.
|
||||
#[derive(Debug)]
|
||||
pub enum WillSaveTextDocument {}
|
||||
|
||||
impl Notification for WillSaveTextDocument {
|
||||
type Params = WillSaveTextDocumentParams;
|
||||
const METHOD: &'static str = "textDocument/willSave";
|
||||
}
|
||||
|
||||
/// The document close notification is sent from the client to the server when the document got closed in the client.
|
||||
/// The document's truth now exists where the document's uri points to (e.g. if the document's uri is a file uri
|
||||
/// the truth now exists on disk).
|
||||
#[derive(Debug)]
|
||||
pub enum DidCloseTextDocument {}
|
||||
|
||||
impl Notification for DidCloseTextDocument {
|
||||
type Params = DidCloseTextDocumentParams;
|
||||
const METHOD: &'static str = "textDocument/didClose";
|
||||
}
|
||||
|
||||
/// The document save notification is sent from the client to the server when the document was saved in the client.
|
||||
#[derive(Debug)]
|
||||
pub enum DidSaveTextDocument {}
|
||||
|
||||
impl Notification for DidSaveTextDocument {
|
||||
type Params = DidSaveTextDocumentParams;
|
||||
const METHOD: &'static str = "textDocument/didSave";
|
||||
}
|
||||
|
||||
/// The watched files notification is sent from the client to the server when the client detects changes to files and folders
|
||||
/// watched by the language client (note although the name suggest that only file events are sent it is about file system events which include folders as well).
|
||||
/// It is recommended that servers register for these file system events using the registration mechanism.
|
||||
/// In former implementations clients pushed file events without the server actively asking for it.
|
||||
#[derive(Debug)]
|
||||
pub enum DidChangeWatchedFiles {}
|
||||
|
||||
impl Notification for DidChangeWatchedFiles {
|
||||
type Params = DidChangeWatchedFilesParams;
|
||||
const METHOD: &'static str = "workspace/didChangeWatchedFiles";
|
||||
}
|
||||
|
||||
/// The workspace/didChangeWorkspaceFolders notification is sent from the client to the server to inform the server
|
||||
/// about workspace folder configuration changes
|
||||
#[derive(Debug)]
|
||||
pub enum DidChangeWorkspaceFolders {}
|
||||
|
||||
impl Notification for DidChangeWorkspaceFolders {
|
||||
type Params = DidChangeWorkspaceFoldersParams;
|
||||
const METHOD: &'static str = "workspace/didChangeWorkspaceFolders";
|
||||
}
|
||||
|
||||
/// Diagnostics notification are sent from the server to the client to signal results of validation runs.
|
||||
#[derive(Debug)]
|
||||
pub enum PublishDiagnostics {}
|
||||
|
||||
impl Notification for PublishDiagnostics {
|
||||
type Params = PublishDiagnosticsParams;
|
||||
const METHOD: &'static str = "textDocument/publishDiagnostics";
|
||||
}
|
||||
|
||||
/// The progress notification is sent from the server to the client to ask
|
||||
/// the client to indicate progress.
|
||||
#[derive(Debug)]
|
||||
pub enum Progress {}
|
||||
|
||||
impl Notification for Progress {
|
||||
type Params = ProgressParams;
|
||||
const METHOD: &'static str = "$/progress";
|
||||
}
|
||||
|
||||
/// The `window/workDoneProgress/cancel` notification is sent from the client
|
||||
/// to the server to cancel a progress initiated on the server side using the `window/workDoneProgress/create`.
|
||||
#[derive(Debug)]
|
||||
pub enum WorkDoneProgressCancel {}
|
||||
|
||||
impl Notification for WorkDoneProgressCancel {
|
||||
type Params = WorkDoneProgressCancelParams;
|
||||
const METHOD: &'static str = "window/workDoneProgress/cancel";
|
||||
}
|
||||
|
||||
/// The did create files notification is sent from the client to the server when files were created from within the client.
|
||||
#[derive(Debug)]
|
||||
pub enum DidCreateFiles {}
|
||||
|
||||
impl Notification for DidCreateFiles {
|
||||
type Params = CreateFilesParams;
|
||||
const METHOD: &'static str = "workspace/didCreateFiles";
|
||||
}
|
||||
|
||||
/// The did rename files notification is sent from the client to the server when files were renamed from within the client.
|
||||
#[derive(Debug)]
|
||||
pub enum DidRenameFiles {}
|
||||
|
||||
impl Notification for DidRenameFiles {
|
||||
type Params = RenameFilesParams;
|
||||
const METHOD: &'static str = "workspace/didRenameFiles";
|
||||
}
|
||||
|
||||
/// The did delete files notification is sent from the client to the server when files were deleted from within the client.
|
||||
#[derive(Debug)]
|
||||
pub enum DidDeleteFiles {}
|
||||
|
||||
impl Notification for DidDeleteFiles {
|
||||
type Params = DeleteFilesParams;
|
||||
const METHOD: &'static str = "workspace/didDeleteFiles";
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
fn fake_call<N>()
|
||||
where
|
||||
N: Notification,
|
||||
N::Params: serde::Serialize,
|
||||
{
|
||||
}
|
||||
|
||||
macro_rules! check_macro {
|
||||
($name:tt) => {
|
||||
// check whether the macro name matches the method
|
||||
assert_eq!(<lsp_notification!($name) as Notification>::METHOD, $name);
|
||||
// test whether type checking passes for each component
|
||||
fake_call::<lsp_notification!($name)>();
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_macro_definitions() {
|
||||
check_macro!("$/cancelRequest");
|
||||
check_macro!("$/progress");
|
||||
check_macro!("$/logTrace");
|
||||
check_macro!("$/setTrace");
|
||||
check_macro!("initialized");
|
||||
check_macro!("exit");
|
||||
check_macro!("window/showMessage");
|
||||
check_macro!("window/logMessage");
|
||||
check_macro!("window/workDoneProgress/cancel");
|
||||
check_macro!("telemetry/event");
|
||||
check_macro!("textDocument/didOpen");
|
||||
check_macro!("textDocument/didChange");
|
||||
check_macro!("textDocument/willSave");
|
||||
check_macro!("textDocument/didSave");
|
||||
check_macro!("textDocument/didClose");
|
||||
check_macro!("textDocument/publishDiagnostics");
|
||||
check_macro!("workspace/didChangeConfiguration");
|
||||
check_macro!("workspace/didChangeWatchedFiles");
|
||||
check_macro!("workspace/didChangeWorkspaceFolders");
|
||||
check_macro!("workspace/didCreateFiles");
|
||||
check_macro!("workspace/didRenameFiles");
|
||||
check_macro!("workspace/didDeleteFiles");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "proposed")]
|
||||
fn check_proposed_macro_definitions() {}
|
||||
}
|
134
helix-lsp-types/src/progress.rs
Normal file
134
helix-lsp-types/src/progress.rs
Normal file
@ -0,0 +1,134 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::NumberOrString;
|
||||
|
||||
pub type ProgressToken = NumberOrString;
|
||||
|
||||
/// The progress notification is sent from the server to the client to ask
|
||||
/// the client to indicate progress.
|
||||
#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ProgressParams {
|
||||
/// The progress token provided by the client.
|
||||
pub token: ProgressToken,
|
||||
|
||||
/// The progress data.
|
||||
pub value: ProgressParamsValue,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)]
|
||||
#[serde(untagged)]
|
||||
pub enum ProgressParamsValue {
|
||||
WorkDone(WorkDoneProgress),
|
||||
}
|
||||
|
||||
/// The `window/workDoneProgress/create` request is sent
|
||||
/// from the server to the client to ask the client to create a work done progress.
|
||||
#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct WorkDoneProgressCreateParams {
|
||||
/// The token to be used to report progress.
|
||||
pub token: ProgressToken,
|
||||
}
|
||||
|
||||
/// The `window/workDoneProgress/cancel` notification is sent from the client
|
||||
/// to the server to cancel a progress initiated on the server side using the `window/workDoneProgress/create`.
|
||||
#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct WorkDoneProgressCancelParams {
|
||||
/// The token to be used to report progress.
|
||||
pub token: ProgressToken,
|
||||
}
|
||||
|
||||
/// Options to signal work done progress support in server capabilities.
|
||||
#[derive(Debug, Eq, PartialEq, Default, Deserialize, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct WorkDoneProgressOptions {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub work_done_progress: Option<bool>,
|
||||
}
|
||||
|
||||
/// An optional token that a server can use to report work done progress
|
||||
#[derive(Debug, Eq, PartialEq, Default, Deserialize, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct WorkDoneProgressParams {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub work_done_token: Option<ProgressToken>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Default, Deserialize, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct WorkDoneProgressBegin {
|
||||
/// Mandatory title of the progress operation. Used to briefly inform
|
||||
/// about the kind of operation being performed.
|
||||
/// Examples: "Indexing" or "Linking dependencies".
|
||||
pub title: String,
|
||||
|
||||
/// Controls if a cancel button should show to allow the user to cancel the
|
||||
/// long running operation. Clients that don't support cancellation are allowed
|
||||
/// to ignore the setting.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub cancellable: Option<bool>,
|
||||
|
||||
/// Optional, more detailed associated progress message. Contains
|
||||
/// complementary information to the `title`.
|
||||
///
|
||||
/// Examples: "3/25 files", "project/src/module2", "node_modules/some_dep".
|
||||
/// If unset, the previous progress message (if any) is still valid.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub message: Option<String>,
|
||||
|
||||
/// Optional progress percentage to display (value 100 is considered 100%).
|
||||
/// If not provided infinite progress is assumed and clients are allowed
|
||||
/// to ignore the `percentage` value in subsequent in report notifications.
|
||||
///
|
||||
/// The value should be steadily rising. Clients are free to ignore values
|
||||
/// that are not following this rule. The value range is [0, 100]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub percentage: Option<u32>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Default, Deserialize, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct WorkDoneProgressReport {
|
||||
/// Controls if a cancel button should show to allow the user to cancel the
|
||||
/// long running operation. Clients that don't support cancellation are allowed
|
||||
/// to ignore the setting.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub cancellable: Option<bool>,
|
||||
|
||||
/// Optional, more detailed associated progress message. Contains
|
||||
/// complementary information to the `title`.
|
||||
/// Examples: "3/25 files", "project/src/module2", "node_modules/some_dep".
|
||||
/// If unset, the previous progress message (if any) is still valid.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub message: Option<String>,
|
||||
|
||||
/// Optional progress percentage to display (value 100 is considered 100%).
|
||||
/// If not provided infinite progress is assumed and clients are allowed
|
||||
/// to ignore the `percentage` value in subsequent in report notifications.
|
||||
///
|
||||
/// The value should be steadily rising. Clients are free to ignore values
|
||||
/// that are not following this rule. The value range is [0, 100]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub percentage: Option<u32>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Default, Deserialize, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct WorkDoneProgressEnd {
|
||||
/// Optional, more detailed associated progress message. Contains
|
||||
/// complementary information to the `title`.
|
||||
/// Examples: "3/25 files", "project/src/module2", "node_modules/some_dep".
|
||||
/// If unset, the previous progress message (if any) is still valid.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub message: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)]
|
||||
#[serde(tag = "kind", rename_all = "lowercase")]
|
||||
pub enum WorkDoneProgress {
|
||||
Begin(WorkDoneProgressBegin),
|
||||
Report(WorkDoneProgressReport),
|
||||
End(WorkDoneProgressEnd),
|
||||
}
|
30
helix-lsp-types/src/references.rs
Normal file
30
helix-lsp-types/src/references.rs
Normal file
@ -0,0 +1,30 @@
|
||||
use crate::{
|
||||
DynamicRegistrationClientCapabilities, PartialResultParams, TextDocumentPositionParams,
|
||||
WorkDoneProgressParams,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub type ReferenceClientCapabilities = DynamicRegistrationClientCapabilities;
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Copy, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ReferenceContext {
|
||||
/// Include the declaration of the current symbol.
|
||||
pub include_declaration: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ReferenceParams {
|
||||
// Text Document and Position fields
|
||||
#[serde(flatten)]
|
||||
pub text_document_position: TextDocumentPositionParams,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_params: WorkDoneProgressParams,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub partial_result_params: PartialResultParams,
|
||||
|
||||
// ReferenceParams properties:
|
||||
pub context: ReferenceContext,
|
||||
}
|
88
helix-lsp-types/src/rename.rs
Normal file
88
helix-lsp-types/src/rename.rs
Normal file
@ -0,0 +1,88 @@
|
||||
use crate::{Range, TextDocumentPositionParams, WorkDoneProgressOptions, WorkDoneProgressParams};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RenameParams {
|
||||
/// Text Document and Position fields
|
||||
#[serde(flatten)]
|
||||
pub text_document_position: TextDocumentPositionParams,
|
||||
|
||||
/// The new name of the symbol. If the given name is not valid the
|
||||
/// request must return a [ResponseError](#ResponseError) with an
|
||||
/// appropriate message set.
|
||||
pub new_name: String,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_params: WorkDoneProgressParams,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RenameOptions {
|
||||
/// Renames should be checked and tested before being executed.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub prepare_provider: Option<bool>,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_options: WorkDoneProgressOptions,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RenameClientCapabilities {
|
||||
/// Whether rename supports dynamic registration.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub dynamic_registration: Option<bool>,
|
||||
|
||||
/// Client supports testing for validity of rename operations before execution.
|
||||
///
|
||||
/// @since 3.12.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub prepare_support: Option<bool>,
|
||||
|
||||
/// Client supports the default behavior result.
|
||||
///
|
||||
/// The value indicates the default behavior used by the
|
||||
/// client.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub prepare_support_default_behavior: Option<PrepareSupportDefaultBehavior>,
|
||||
|
||||
/// Whether the client honors the change annotations in
|
||||
/// text edits and resource operations returned via the
|
||||
/// rename request's workspace edit by for example presenting
|
||||
/// the workspace edit in the user interface and asking
|
||||
/// for confirmation.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub honors_change_annotations: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq, Copy, Clone, Serialize, Deserialize)]
|
||||
#[serde(transparent)]
|
||||
pub struct PrepareSupportDefaultBehavior(i32);
|
||||
lsp_enum! {
|
||||
impl PrepareSupportDefaultBehavior {
|
||||
/// The client's default behavior is to select the identifier
|
||||
/// according the to language's syntax rule
|
||||
pub const IDENTIFIER: PrepareSupportDefaultBehavior = PrepareSupportDefaultBehavior(1);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(untagged)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum PrepareRenameResponse {
|
||||
Range(Range),
|
||||
RangeWithPlaceholder {
|
||||
range: Range,
|
||||
placeholder: String,
|
||||
},
|
||||
#[serde(rename_all = "camelCase")]
|
||||
DefaultBehavior {
|
||||
default_behavior: bool,
|
||||
},
|
||||
}
|
1068
helix-lsp-types/src/request.rs
Normal file
1068
helix-lsp-types/src/request.rs
Normal file
File diff suppressed because it is too large
Load Diff
86
helix-lsp-types/src/selection_range.rs
Normal file
86
helix-lsp-types/src/selection_range.rs
Normal file
@ -0,0 +1,86 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
PartialResultParams, Position, Range, StaticTextDocumentRegistrationOptions,
|
||||
TextDocumentIdentifier, WorkDoneProgressOptions, WorkDoneProgressParams,
|
||||
};
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SelectionRangeClientCapabilities {
|
||||
/// Whether implementation supports dynamic registration for selection range
|
||||
/// providers. If this is set to `true` the client supports the new
|
||||
/// `SelectionRangeRegistrationOptions` return value for the corresponding
|
||||
/// server capability as well.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub dynamic_registration: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
pub struct SelectionRangeOptions {
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_options: WorkDoneProgressOptions,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
pub struct SelectionRangeRegistrationOptions {
|
||||
#[serde(flatten)]
|
||||
pub selection_range_options: SelectionRangeOptions,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub registration_options: StaticTextDocumentRegistrationOptions,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum SelectionRangeProviderCapability {
|
||||
Simple(bool),
|
||||
Options(SelectionRangeOptions),
|
||||
RegistrationOptions(SelectionRangeRegistrationOptions),
|
||||
}
|
||||
|
||||
impl From<SelectionRangeRegistrationOptions> for SelectionRangeProviderCapability {
|
||||
fn from(from: SelectionRangeRegistrationOptions) -> Self {
|
||||
Self::RegistrationOptions(from)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SelectionRangeOptions> for SelectionRangeProviderCapability {
|
||||
fn from(from: SelectionRangeOptions) -> Self {
|
||||
Self::Options(from)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<bool> for SelectionRangeProviderCapability {
|
||||
fn from(from: bool) -> Self {
|
||||
Self::Simple(from)
|
||||
}
|
||||
}
|
||||
|
||||
/// A parameter literal used in selection range requests.
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SelectionRangeParams {
|
||||
/// The text document.
|
||||
pub text_document: TextDocumentIdentifier,
|
||||
|
||||
/// The positions inside the text document.
|
||||
pub positions: Vec<Position>,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_params: WorkDoneProgressParams,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub partial_result_params: PartialResultParams,
|
||||
}
|
||||
|
||||
/// Represents a selection range.
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SelectionRange {
|
||||
/// Range of the selection.
|
||||
pub range: Range,
|
||||
|
||||
/// The parent selection range containing this range.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub parent: Option<Box<SelectionRange>>,
|
||||
}
|
734
helix-lsp-types/src/semantic_tokens.rs
Normal file
734
helix-lsp-types/src/semantic_tokens.rs
Normal file
@ -0,0 +1,734 @@
|
||||
use std::borrow::Cow;
|
||||
|
||||
use serde::ser::SerializeSeq;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
PartialResultParams, Range, StaticRegistrationOptions, TextDocumentIdentifier,
|
||||
TextDocumentRegistrationOptions, WorkDoneProgressOptions, WorkDoneProgressParams,
|
||||
};
|
||||
/// A set of predefined token types. This set is not fixed
|
||||
/// and clients can specify additional token types via the
|
||||
/// corresponding client capabilities.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[derive(Debug, Eq, PartialEq, Hash, PartialOrd, Clone, Deserialize, Serialize)]
|
||||
pub struct SemanticTokenType(Cow<'static, str>);
|
||||
|
||||
impl SemanticTokenType {
|
||||
pub const NAMESPACE: SemanticTokenType = SemanticTokenType::new("namespace");
|
||||
pub const TYPE: SemanticTokenType = SemanticTokenType::new("type");
|
||||
pub const CLASS: SemanticTokenType = SemanticTokenType::new("class");
|
||||
pub const ENUM: SemanticTokenType = SemanticTokenType::new("enum");
|
||||
pub const INTERFACE: SemanticTokenType = SemanticTokenType::new("interface");
|
||||
pub const STRUCT: SemanticTokenType = SemanticTokenType::new("struct");
|
||||
pub const TYPE_PARAMETER: SemanticTokenType = SemanticTokenType::new("typeParameter");
|
||||
pub const PARAMETER: SemanticTokenType = SemanticTokenType::new("parameter");
|
||||
pub const VARIABLE: SemanticTokenType = SemanticTokenType::new("variable");
|
||||
pub const PROPERTY: SemanticTokenType = SemanticTokenType::new("property");
|
||||
pub const ENUM_MEMBER: SemanticTokenType = SemanticTokenType::new("enumMember");
|
||||
pub const EVENT: SemanticTokenType = SemanticTokenType::new("event");
|
||||
pub const FUNCTION: SemanticTokenType = SemanticTokenType::new("function");
|
||||
pub const METHOD: SemanticTokenType = SemanticTokenType::new("method");
|
||||
pub const MACRO: SemanticTokenType = SemanticTokenType::new("macro");
|
||||
pub const KEYWORD: SemanticTokenType = SemanticTokenType::new("keyword");
|
||||
pub const MODIFIER: SemanticTokenType = SemanticTokenType::new("modifier");
|
||||
pub const COMMENT: SemanticTokenType = SemanticTokenType::new("comment");
|
||||
pub const STRING: SemanticTokenType = SemanticTokenType::new("string");
|
||||
pub const NUMBER: SemanticTokenType = SemanticTokenType::new("number");
|
||||
pub const REGEXP: SemanticTokenType = SemanticTokenType::new("regexp");
|
||||
pub const OPERATOR: SemanticTokenType = SemanticTokenType::new("operator");
|
||||
|
||||
/// @since 3.17.0
|
||||
pub const DECORATOR: SemanticTokenType = SemanticTokenType::new("decorator");
|
||||
|
||||
pub const fn new(tag: &'static str) -> Self {
|
||||
SemanticTokenType(Cow::Borrowed(tag))
|
||||
}
|
||||
|
||||
pub fn as_str(&self) -> &str {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for SemanticTokenType {
|
||||
fn from(from: String) -> Self {
|
||||
SemanticTokenType(Cow::from(from))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'static str> for SemanticTokenType {
|
||||
fn from(from: &'static str) -> Self {
|
||||
SemanticTokenType::new(from)
|
||||
}
|
||||
}
|
||||
|
||||
/// A set of predefined token modifiers. This set is not fixed
|
||||
/// and clients can specify additional token types via the
|
||||
/// corresponding client capabilities.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[derive(Debug, Eq, PartialEq, Hash, PartialOrd, Clone, Deserialize, Serialize)]
|
||||
pub struct SemanticTokenModifier(Cow<'static, str>);
|
||||
|
||||
impl SemanticTokenModifier {
|
||||
pub const DECLARATION: SemanticTokenModifier = SemanticTokenModifier::new("declaration");
|
||||
pub const DEFINITION: SemanticTokenModifier = SemanticTokenModifier::new("definition");
|
||||
pub const READONLY: SemanticTokenModifier = SemanticTokenModifier::new("readonly");
|
||||
pub const STATIC: SemanticTokenModifier = SemanticTokenModifier::new("static");
|
||||
pub const DEPRECATED: SemanticTokenModifier = SemanticTokenModifier::new("deprecated");
|
||||
pub const ABSTRACT: SemanticTokenModifier = SemanticTokenModifier::new("abstract");
|
||||
pub const ASYNC: SemanticTokenModifier = SemanticTokenModifier::new("async");
|
||||
pub const MODIFICATION: SemanticTokenModifier = SemanticTokenModifier::new("modification");
|
||||
pub const DOCUMENTATION: SemanticTokenModifier = SemanticTokenModifier::new("documentation");
|
||||
pub const DEFAULT_LIBRARY: SemanticTokenModifier = SemanticTokenModifier::new("defaultLibrary");
|
||||
|
||||
pub const fn new(tag: &'static str) -> Self {
|
||||
SemanticTokenModifier(Cow::Borrowed(tag))
|
||||
}
|
||||
|
||||
pub fn as_str(&self) -> &str {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for SemanticTokenModifier {
|
||||
fn from(from: String) -> Self {
|
||||
SemanticTokenModifier(Cow::from(from))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'static str> for SemanticTokenModifier {
|
||||
fn from(from: &'static str) -> Self {
|
||||
SemanticTokenModifier::new(from)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Hash, PartialOrd, Clone, Deserialize, Serialize)]
|
||||
pub struct TokenFormat(Cow<'static, str>);
|
||||
|
||||
impl TokenFormat {
|
||||
pub const RELATIVE: TokenFormat = TokenFormat::new("relative");
|
||||
|
||||
pub const fn new(tag: &'static str) -> Self {
|
||||
TokenFormat(Cow::Borrowed(tag))
|
||||
}
|
||||
|
||||
pub fn as_str(&self) -> &str {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for TokenFormat {
|
||||
fn from(from: String) -> Self {
|
||||
TokenFormat(Cow::from(from))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'static str> for TokenFormat {
|
||||
fn from(from: &'static str) -> Self {
|
||||
TokenFormat::new(from)
|
||||
}
|
||||
}
|
||||
|
||||
/// @since 3.16.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SemanticTokensLegend {
|
||||
/// The token types a server uses.
|
||||
pub token_types: Vec<SemanticTokenType>,
|
||||
|
||||
/// The token modifiers a server uses.
|
||||
pub token_modifiers: Vec<SemanticTokenModifier>,
|
||||
}
|
||||
|
||||
/// The actual tokens.
|
||||
#[derive(Debug, Eq, PartialEq, Copy, Clone, Default)]
|
||||
pub struct SemanticToken {
|
||||
pub delta_line: u32,
|
||||
pub delta_start: u32,
|
||||
pub length: u32,
|
||||
pub token_type: u32,
|
||||
pub token_modifiers_bitset: u32,
|
||||
}
|
||||
|
||||
impl SemanticToken {
|
||||
fn deserialize_tokens<'de, D>(deserializer: D) -> Result<Vec<SemanticToken>, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
let data = Vec::<u32>::deserialize(deserializer)?;
|
||||
let chunks = data.chunks_exact(5);
|
||||
|
||||
if !chunks.remainder().is_empty() {
|
||||
return Result::Err(serde::de::Error::custom("Length is not divisible by 5"));
|
||||
}
|
||||
|
||||
Result::Ok(
|
||||
chunks
|
||||
.map(|chunk| SemanticToken {
|
||||
delta_line: chunk[0],
|
||||
delta_start: chunk[1],
|
||||
length: chunk[2],
|
||||
token_type: chunk[3],
|
||||
token_modifiers_bitset: chunk[4],
|
||||
})
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
|
||||
fn serialize_tokens<S>(tokens: &[SemanticToken], serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
let mut seq = serializer.serialize_seq(Some(tokens.len() * 5))?;
|
||||
for token in tokens.iter() {
|
||||
seq.serialize_element(&token.delta_line)?;
|
||||
seq.serialize_element(&token.delta_start)?;
|
||||
seq.serialize_element(&token.length)?;
|
||||
seq.serialize_element(&token.token_type)?;
|
||||
seq.serialize_element(&token.token_modifiers_bitset)?;
|
||||
}
|
||||
seq.end()
|
||||
}
|
||||
|
||||
fn deserialize_tokens_opt<'de, D>(
|
||||
deserializer: D,
|
||||
) -> Result<Option<Vec<SemanticToken>>, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
#[derive(Deserialize)]
|
||||
#[serde(transparent)]
|
||||
struct Wrapper {
|
||||
#[serde(deserialize_with = "SemanticToken::deserialize_tokens")]
|
||||
tokens: Vec<SemanticToken>,
|
||||
}
|
||||
|
||||
Ok(Option::<Wrapper>::deserialize(deserializer)?.map(|wrapper| wrapper.tokens))
|
||||
}
|
||||
|
||||
fn serialize_tokens_opt<S>(
|
||||
data: &Option<Vec<SemanticToken>>,
|
||||
serializer: S,
|
||||
) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
#[derive(Serialize)]
|
||||
#[serde(transparent)]
|
||||
struct Wrapper {
|
||||
#[serde(serialize_with = "SemanticToken::serialize_tokens")]
|
||||
tokens: Vec<SemanticToken>,
|
||||
}
|
||||
|
||||
let opt = data.as_ref().map(|t| Wrapper { tokens: t.to_vec() });
|
||||
|
||||
opt.serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
/// @since 3.16.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SemanticTokens {
|
||||
/// An optional result id. If provided and clients support delta updating
|
||||
/// the client will include the result id in the next semantic token request.
|
||||
/// A server can then instead of computing all semantic tokens again simply
|
||||
/// send a delta.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub result_id: Option<String>,
|
||||
|
||||
/// The actual tokens. For a detailed description about how the data is
|
||||
/// structured please see
|
||||
/// <https://github.com/microsoft/vscode-extension-samples/blob/5ae1f7787122812dcc84e37427ca90af5ee09f14/semantic-tokens-sample/vscode.proposed.d.ts#L71>
|
||||
#[serde(
|
||||
deserialize_with = "SemanticToken::deserialize_tokens",
|
||||
serialize_with = "SemanticToken::serialize_tokens"
|
||||
)]
|
||||
pub data: Vec<SemanticToken>,
|
||||
}
|
||||
|
||||
/// @since 3.16.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SemanticTokensPartialResult {
|
||||
#[serde(
|
||||
deserialize_with = "SemanticToken::deserialize_tokens",
|
||||
serialize_with = "SemanticToken::serialize_tokens"
|
||||
)]
|
||||
pub data: Vec<SemanticToken>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[serde(untagged)]
|
||||
pub enum SemanticTokensResult {
|
||||
Tokens(SemanticTokens),
|
||||
Partial(SemanticTokensPartialResult),
|
||||
}
|
||||
|
||||
impl From<SemanticTokens> for SemanticTokensResult {
|
||||
fn from(from: SemanticTokens) -> Self {
|
||||
SemanticTokensResult::Tokens(from)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SemanticTokensPartialResult> for SemanticTokensResult {
|
||||
fn from(from: SemanticTokensPartialResult) -> Self {
|
||||
SemanticTokensResult::Partial(from)
|
||||
}
|
||||
}
|
||||
|
||||
/// @since 3.16.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SemanticTokensEdit {
|
||||
pub start: u32,
|
||||
pub delete_count: u32,
|
||||
|
||||
#[serde(
|
||||
default,
|
||||
skip_serializing_if = "Option::is_none",
|
||||
deserialize_with = "SemanticToken::deserialize_tokens_opt",
|
||||
serialize_with = "SemanticToken::serialize_tokens_opt"
|
||||
)]
|
||||
pub data: Option<Vec<SemanticToken>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[serde(untagged)]
|
||||
pub enum SemanticTokensFullDeltaResult {
|
||||
Tokens(SemanticTokens),
|
||||
TokensDelta(SemanticTokensDelta),
|
||||
PartialTokensDelta { edits: Vec<SemanticTokensEdit> },
|
||||
}
|
||||
|
||||
impl From<SemanticTokens> for SemanticTokensFullDeltaResult {
|
||||
fn from(from: SemanticTokens) -> Self {
|
||||
SemanticTokensFullDeltaResult::Tokens(from)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SemanticTokensDelta> for SemanticTokensFullDeltaResult {
|
||||
fn from(from: SemanticTokensDelta) -> Self {
|
||||
SemanticTokensFullDeltaResult::TokensDelta(from)
|
||||
}
|
||||
}
|
||||
|
||||
/// @since 3.16.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SemanticTokensDelta {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub result_id: Option<String>,
|
||||
/// For a detailed description how these edits are structured please see
|
||||
/// <https://github.com/microsoft/vscode-extension-samples/blob/5ae1f7787122812dcc84e37427ca90af5ee09f14/semantic-tokens-sample/vscode.proposed.d.ts#L131>
|
||||
pub edits: Vec<SemanticTokensEdit>,
|
||||
}
|
||||
|
||||
/// Capabilities specific to the `textDocument/semanticTokens/*` requests.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SemanticTokensClientCapabilities {
|
||||
/// Whether implementation supports dynamic registration. If this is set to `true`
|
||||
/// the client supports the new `(TextDocumentRegistrationOptions & StaticRegistrationOptions)`
|
||||
/// return value for the corresponding server capability as well.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub dynamic_registration: Option<bool>,
|
||||
|
||||
/// Which requests the client supports and might send to the server
|
||||
/// depending on the server's capability. Please note that clients might not
|
||||
/// show semantic tokens or degrade some of the user experience if a range
|
||||
/// or full request is advertised by the client but not provided by the
|
||||
/// server. If for example the client capability `requests.full` and
|
||||
/// `request.range` are both set to true but the server only provides a
|
||||
/// range provider the client might not render a minimap correctly or might
|
||||
/// even decide to not show any semantic tokens at all.
|
||||
pub requests: SemanticTokensClientCapabilitiesRequests,
|
||||
|
||||
/// The token types that the client supports.
|
||||
pub token_types: Vec<SemanticTokenType>,
|
||||
|
||||
/// The token modifiers that the client supports.
|
||||
pub token_modifiers: Vec<SemanticTokenModifier>,
|
||||
|
||||
/// The token formats the clients supports.
|
||||
pub formats: Vec<TokenFormat>,
|
||||
|
||||
/// Whether the client supports tokens that can overlap each other.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub overlapping_token_support: Option<bool>,
|
||||
|
||||
/// Whether the client supports tokens that can span multiple lines.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub multiline_token_support: Option<bool>,
|
||||
|
||||
/// Whether the client allows the server to actively cancel a
|
||||
/// semantic token request, e.g. supports returning
|
||||
/// ErrorCodes.ServerCancelled. If a server does the client
|
||||
/// needs to retrigger the request.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub server_cancel_support: Option<bool>,
|
||||
|
||||
/// Whether the client uses semantic tokens to augment existing
|
||||
/// syntax tokens. If set to `true` client side created syntax
|
||||
/// tokens and semantic tokens are both used for colorization. If
|
||||
/// set to `false` the client only uses the returned semantic tokens
|
||||
/// for colorization.
|
||||
///
|
||||
/// If the value is `undefined` then the client behavior is not
|
||||
/// specified.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub augments_syntax_tokens: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SemanticTokensClientCapabilitiesRequests {
|
||||
/// The client will send the `textDocument/semanticTokens/range` request if the server provides a corresponding handler.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub range: Option<bool>,
|
||||
|
||||
/// The client will send the `textDocument/semanticTokens/full` request if the server provides a corresponding handler.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub full: Option<SemanticTokensFullOptions>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[serde(untagged)]
|
||||
pub enum SemanticTokensFullOptions {
|
||||
Bool(bool),
|
||||
Delta {
|
||||
/// The client will send the `textDocument/semanticTokens/full/delta` request if the server provides a corresponding handler.
|
||||
/// The server supports deltas for full documents.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
delta: Option<bool>,
|
||||
},
|
||||
}
|
||||
|
||||
/// @since 3.16.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SemanticTokensOptions {
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_options: WorkDoneProgressOptions,
|
||||
|
||||
/// The legend used by the server
|
||||
pub legend: SemanticTokensLegend,
|
||||
|
||||
/// Server supports providing semantic tokens for a specific range
|
||||
/// of a document.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub range: Option<bool>,
|
||||
|
||||
/// Server supports providing semantic tokens for a full document.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub full: Option<SemanticTokensFullOptions>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SemanticTokensRegistrationOptions {
|
||||
#[serde(flatten)]
|
||||
pub text_document_registration_options: TextDocumentRegistrationOptions,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub semantic_tokens_options: SemanticTokensOptions,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub static_registration_options: StaticRegistrationOptions,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[serde(untagged)]
|
||||
pub enum SemanticTokensServerCapabilities {
|
||||
SemanticTokensOptions(SemanticTokensOptions),
|
||||
SemanticTokensRegistrationOptions(SemanticTokensRegistrationOptions),
|
||||
}
|
||||
|
||||
impl From<SemanticTokensOptions> for SemanticTokensServerCapabilities {
|
||||
fn from(from: SemanticTokensOptions) -> Self {
|
||||
SemanticTokensServerCapabilities::SemanticTokensOptions(from)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SemanticTokensRegistrationOptions> for SemanticTokensServerCapabilities {
|
||||
fn from(from: SemanticTokensRegistrationOptions) -> Self {
|
||||
SemanticTokensServerCapabilities::SemanticTokensRegistrationOptions(from)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SemanticTokensWorkspaceClientCapabilities {
|
||||
/// Whether the client implementation supports a refresh request sent from
|
||||
/// the server to the client.
|
||||
///
|
||||
/// Note that this event is global and will force the client to refresh all
|
||||
/// semantic tokens currently shown. It should be used with absolute care
|
||||
/// and is useful for situation where a server for example detect a project
|
||||
/// wide change that requires such a calculation.
|
||||
pub refresh_support: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SemanticTokensParams {
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_params: WorkDoneProgressParams,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub partial_result_params: PartialResultParams,
|
||||
|
||||
/// The text document.
|
||||
pub text_document: TextDocumentIdentifier,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SemanticTokensDeltaParams {
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_params: WorkDoneProgressParams,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub partial_result_params: PartialResultParams,
|
||||
|
||||
/// The text document.
|
||||
pub text_document: TextDocumentIdentifier,
|
||||
|
||||
/// The result id of a previous response. The result Id can either point to a full response
|
||||
/// or a delta response depending on what was received last.
|
||||
pub previous_result_id: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SemanticTokensRangeParams {
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_params: WorkDoneProgressParams,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub partial_result_params: PartialResultParams,
|
||||
|
||||
/// The text document.
|
||||
pub text_document: TextDocumentIdentifier,
|
||||
|
||||
/// The range the semantic tokens are requested for.
|
||||
pub range: Range,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[serde(untagged)]
|
||||
pub enum SemanticTokensRangeResult {
|
||||
Tokens(SemanticTokens),
|
||||
Partial(SemanticTokensPartialResult),
|
||||
}
|
||||
|
||||
impl From<SemanticTokens> for SemanticTokensRangeResult {
|
||||
fn from(tokens: SemanticTokens) -> Self {
|
||||
SemanticTokensRangeResult::Tokens(tokens)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SemanticTokensPartialResult> for SemanticTokensRangeResult {
|
||||
fn from(partial: SemanticTokensPartialResult) -> Self {
|
||||
SemanticTokensRangeResult::Partial(partial)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::tests::{test_deserialization, test_serialization};
|
||||
|
||||
#[test]
|
||||
fn test_semantic_tokens_support_serialization() {
|
||||
test_serialization(
|
||||
&SemanticTokens {
|
||||
result_id: None,
|
||||
data: vec![],
|
||||
},
|
||||
r#"{"data":[]}"#,
|
||||
);
|
||||
|
||||
test_serialization(
|
||||
&SemanticTokens {
|
||||
result_id: None,
|
||||
data: vec![SemanticToken {
|
||||
delta_line: 2,
|
||||
delta_start: 5,
|
||||
length: 3,
|
||||
token_type: 0,
|
||||
token_modifiers_bitset: 3,
|
||||
}],
|
||||
},
|
||||
r#"{"data":[2,5,3,0,3]}"#,
|
||||
);
|
||||
|
||||
test_serialization(
|
||||
&SemanticTokens {
|
||||
result_id: None,
|
||||
data: vec![
|
||||
SemanticToken {
|
||||
delta_line: 2,
|
||||
delta_start: 5,
|
||||
length: 3,
|
||||
token_type: 0,
|
||||
token_modifiers_bitset: 3,
|
||||
},
|
||||
SemanticToken {
|
||||
delta_line: 0,
|
||||
delta_start: 5,
|
||||
length: 4,
|
||||
token_type: 1,
|
||||
token_modifiers_bitset: 0,
|
||||
},
|
||||
],
|
||||
},
|
||||
r#"{"data":[2,5,3,0,3,0,5,4,1,0]}"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_semantic_tokens_support_deserialization() {
|
||||
test_deserialization(
|
||||
r#"{"data":[]}"#,
|
||||
&SemanticTokens {
|
||||
result_id: None,
|
||||
data: vec![],
|
||||
},
|
||||
);
|
||||
|
||||
test_deserialization(
|
||||
r#"{"data":[2,5,3,0,3]}"#,
|
||||
&SemanticTokens {
|
||||
result_id: None,
|
||||
data: vec![SemanticToken {
|
||||
delta_line: 2,
|
||||
delta_start: 5,
|
||||
length: 3,
|
||||
token_type: 0,
|
||||
token_modifiers_bitset: 3,
|
||||
}],
|
||||
},
|
||||
);
|
||||
|
||||
test_deserialization(
|
||||
r#"{"data":[2,5,3,0,3,0,5,4,1,0]}"#,
|
||||
&SemanticTokens {
|
||||
result_id: None,
|
||||
data: vec![
|
||||
SemanticToken {
|
||||
delta_line: 2,
|
||||
delta_start: 5,
|
||||
length: 3,
|
||||
token_type: 0,
|
||||
token_modifiers_bitset: 3,
|
||||
},
|
||||
SemanticToken {
|
||||
delta_line: 0,
|
||||
delta_start: 5,
|
||||
length: 4,
|
||||
token_type: 1,
|
||||
token_modifiers_bitset: 0,
|
||||
},
|
||||
],
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_semantic_tokens_support_deserialization_err() {
|
||||
test_deserialization(
|
||||
r#"{"data":[1]}"#,
|
||||
&SemanticTokens {
|
||||
result_id: None,
|
||||
data: vec![],
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_semantic_tokens_edit_support_deserialization() {
|
||||
test_deserialization(
|
||||
r#"{"start":0,"deleteCount":1,"data":[2,5,3,0,3,0,5,4,1,0]}"#,
|
||||
&SemanticTokensEdit {
|
||||
start: 0,
|
||||
delete_count: 1,
|
||||
data: Some(vec![
|
||||
SemanticToken {
|
||||
delta_line: 2,
|
||||
delta_start: 5,
|
||||
length: 3,
|
||||
token_type: 0,
|
||||
token_modifiers_bitset: 3,
|
||||
},
|
||||
SemanticToken {
|
||||
delta_line: 0,
|
||||
delta_start: 5,
|
||||
length: 4,
|
||||
token_type: 1,
|
||||
token_modifiers_bitset: 0,
|
||||
},
|
||||
]),
|
||||
},
|
||||
);
|
||||
|
||||
test_deserialization(
|
||||
r#"{"start":0,"deleteCount":1}"#,
|
||||
&SemanticTokensEdit {
|
||||
start: 0,
|
||||
delete_count: 1,
|
||||
data: None,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_semantic_tokens_edit_support_serialization() {
|
||||
test_serialization(
|
||||
&SemanticTokensEdit {
|
||||
start: 0,
|
||||
delete_count: 1,
|
||||
data: Some(vec![
|
||||
SemanticToken {
|
||||
delta_line: 2,
|
||||
delta_start: 5,
|
||||
length: 3,
|
||||
token_type: 0,
|
||||
token_modifiers_bitset: 3,
|
||||
},
|
||||
SemanticToken {
|
||||
delta_line: 0,
|
||||
delta_start: 5,
|
||||
length: 4,
|
||||
token_type: 1,
|
||||
token_modifiers_bitset: 0,
|
||||
},
|
||||
]),
|
||||
},
|
||||
r#"{"start":0,"deleteCount":1,"data":[2,5,3,0,3,0,5,4,1,0]}"#,
|
||||
);
|
||||
|
||||
test_serialization(
|
||||
&SemanticTokensEdit {
|
||||
start: 0,
|
||||
delete_count: 1,
|
||||
data: None,
|
||||
},
|
||||
r#"{"start":0,"deleteCount":1}"#,
|
||||
);
|
||||
}
|
||||
}
|
207
helix-lsp-types/src/signature_help.rs
Normal file
207
helix-lsp-types/src/signature_help.rs
Normal file
@ -0,0 +1,207 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
Documentation, MarkupKind, TextDocumentPositionParams, TextDocumentRegistrationOptions,
|
||||
WorkDoneProgressOptions, WorkDoneProgressParams,
|
||||
};
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SignatureInformationSettings {
|
||||
/// Client supports the follow content formats for the documentation
|
||||
/// property. The order describes the preferred format of the client.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub documentation_format: Option<Vec<MarkupKind>>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub parameter_information: Option<ParameterInformationSettings>,
|
||||
|
||||
/// The client support the `activeParameter` property on `SignatureInformation`
|
||||
/// literal.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub active_parameter_support: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ParameterInformationSettings {
|
||||
/// The client supports processing label offsets instead of a
|
||||
/// simple label string.
|
||||
///
|
||||
/// @since 3.14.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub label_offset_support: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SignatureHelpClientCapabilities {
|
||||
/// Whether completion supports dynamic registration.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub dynamic_registration: Option<bool>,
|
||||
|
||||
/// The client supports the following `SignatureInformation`
|
||||
/// specific properties.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub signature_information: Option<SignatureInformationSettings>,
|
||||
|
||||
/// The client supports to send additional context information for a
|
||||
/// `textDocument/signatureHelp` request. A client that opts into
|
||||
/// contextSupport will also support the `retriggerCharacters` on
|
||||
/// `SignatureHelpOptions`.
|
||||
///
|
||||
/// @since 3.15.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub context_support: Option<bool>,
|
||||
}
|
||||
|
||||
/// Signature help options.
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SignatureHelpOptions {
|
||||
/// The characters that trigger signature help automatically.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub trigger_characters: Option<Vec<String>>,
|
||||
|
||||
/// List of characters that re-trigger signature help.
|
||||
/// These trigger characters are only active when signature help is already showing. All trigger characters
|
||||
/// are also counted as re-trigger characters.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub retrigger_characters: Option<Vec<String>>,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_options: WorkDoneProgressOptions,
|
||||
}
|
||||
|
||||
/// Signature help options.
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
pub struct SignatureHelpRegistrationOptions {
|
||||
#[serde(flatten)]
|
||||
pub text_document_registration_options: TextDocumentRegistrationOptions,
|
||||
}
|
||||
|
||||
/// Signature help options.
|
||||
#[derive(Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(transparent)]
|
||||
pub struct SignatureHelpTriggerKind(i32);
|
||||
lsp_enum! {
|
||||
impl SignatureHelpTriggerKind {
|
||||
/// Signature help was invoked manually by the user or by a command.
|
||||
pub const INVOKED: SignatureHelpTriggerKind = SignatureHelpTriggerKind(1);
|
||||
/// Signature help was triggered by a trigger character.
|
||||
pub const TRIGGER_CHARACTER: SignatureHelpTriggerKind = SignatureHelpTriggerKind(2);
|
||||
/// Signature help was triggered by the cursor moving or by the document content changing.
|
||||
pub const CONTENT_CHANGE: SignatureHelpTriggerKind = SignatureHelpTriggerKind(3);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SignatureHelpParams {
|
||||
/// The signature help context. This is only available if the client specifies
|
||||
/// to send this using the client capability `textDocument.signatureHelp.contextSupport === true`
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub context: Option<SignatureHelpContext>,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub text_document_position_params: TextDocumentPositionParams,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_params: WorkDoneProgressParams,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SignatureHelpContext {
|
||||
/// Action that caused signature help to be triggered.
|
||||
pub trigger_kind: SignatureHelpTriggerKind,
|
||||
|
||||
/// Character that caused signature help to be triggered.
|
||||
/// This is undefined when `triggerKind !== SignatureHelpTriggerKind.TriggerCharacter`
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub trigger_character: Option<String>,
|
||||
|
||||
/// `true` if signature help was already showing when it was triggered.
|
||||
/// Retriggers occur when the signature help is already active and can be caused by actions such as
|
||||
/// typing a trigger character, a cursor move, or document content changes.
|
||||
pub is_retrigger: bool,
|
||||
|
||||
/// The currently active `SignatureHelp`.
|
||||
/// The `activeSignatureHelp` has its `SignatureHelp.activeSignature` field updated based on
|
||||
/// the user navigating through available signatures.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub active_signature_help: Option<SignatureHelp>,
|
||||
}
|
||||
|
||||
/// Signature help represents the signature of something
|
||||
/// callable. There can be multiple signature but only one
|
||||
/// active and only one active parameter.
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SignatureHelp {
|
||||
/// One or more signatures.
|
||||
pub signatures: Vec<SignatureInformation>,
|
||||
|
||||
/// The active signature.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub active_signature: Option<u32>,
|
||||
|
||||
/// The active parameter of the active signature.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub active_parameter: Option<u32>,
|
||||
}
|
||||
|
||||
/// Represents the signature of something callable. A signature
|
||||
/// can have a label, like a function-name, a doc-comment, and
|
||||
/// a set of parameters.
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SignatureInformation {
|
||||
/// The label of this signature. Will be shown in
|
||||
/// the UI.
|
||||
pub label: String,
|
||||
|
||||
/// The human-readable doc-comment of this signature. Will be shown
|
||||
/// in the UI but can be omitted.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub documentation: Option<Documentation>,
|
||||
|
||||
/// The parameters of this signature.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub parameters: Option<Vec<ParameterInformation>>,
|
||||
|
||||
/// The index of the active parameter.
|
||||
///
|
||||
/// If provided, this is used in place of `SignatureHelp.activeParameter`.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub active_parameter: Option<u32>,
|
||||
}
|
||||
|
||||
/// Represents a parameter of a callable-signature. A parameter can
|
||||
/// have a label and a doc-comment.
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ParameterInformation {
|
||||
/// The label of this parameter information.
|
||||
///
|
||||
/// Either a string or an inclusive start and exclusive end offsets within its containing
|
||||
/// signature label. (see SignatureInformation.label). *Note*: A label of type string must be
|
||||
/// a substring of its containing signature label.
|
||||
pub label: ParameterLabel,
|
||||
|
||||
/// The human-readable doc-comment of this parameter. Will be shown
|
||||
/// in the UI but can be omitted.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub documentation: Option<Documentation>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum ParameterLabel {
|
||||
Simple(String),
|
||||
LabelOffsets([u32; 2]),
|
||||
}
|
77
helix-lsp-types/src/trace.rs
Normal file
77
helix-lsp-types/src/trace.rs
Normal file
@ -0,0 +1,77 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
pub struct SetTraceParams {
|
||||
/// The new value that should be assigned to the trace setting.
|
||||
pub value: TraceValue,
|
||||
}
|
||||
|
||||
/// A TraceValue represents the level of verbosity with which the server systematically
|
||||
/// reports its execution trace using `LogTrace` notifications.
|
||||
///
|
||||
/// The initial trace value is set by the client at initialization and can be modified
|
||||
/// later using the `SetTrace` notification.
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Copy, Deserialize, Serialize, Default)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum TraceValue {
|
||||
/// The server should not send any `$/logTrace` notification
|
||||
#[default]
|
||||
Off,
|
||||
/// The server should not add the 'verbose' field in the `LogTraceParams`
|
||||
Messages,
|
||||
Verbose,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct LogTraceParams {
|
||||
/// The message to be logged.
|
||||
pub message: String,
|
||||
/// Additional information that can be computed if the `trace` configuration
|
||||
/// is set to `'verbose'`
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub verbose: Option<String>,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::tests::test_serialization;
|
||||
|
||||
#[test]
|
||||
fn test_set_trace_params() {
|
||||
test_serialization(
|
||||
&SetTraceParams {
|
||||
value: TraceValue::Off,
|
||||
},
|
||||
r#"{"value":"off"}"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_log_trace_params() {
|
||||
test_serialization(
|
||||
&LogTraceParams {
|
||||
message: "message".into(),
|
||||
verbose: None,
|
||||
},
|
||||
r#"{"message":"message"}"#,
|
||||
);
|
||||
|
||||
test_serialization(
|
||||
&LogTraceParams {
|
||||
message: "message".into(),
|
||||
verbose: Some("verbose".into()),
|
||||
},
|
||||
r#"{"message":"message","verbose":"verbose"}"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_trace_value() {
|
||||
test_serialization(
|
||||
&vec![TraceValue::Off, TraceValue::Messages, TraceValue::Verbose],
|
||||
r#"["off","messages","verbose"]"#,
|
||||
);
|
||||
}
|
||||
}
|
90
helix-lsp-types/src/type_hierarchy.rs
Normal file
90
helix-lsp-types/src/type_hierarchy.rs
Normal file
@ -0,0 +1,90 @@
|
||||
use crate::{
|
||||
DynamicRegistrationClientCapabilities, LSPAny, PartialResultParams, Range,
|
||||
StaticRegistrationOptions, SymbolKind, SymbolTag, TextDocumentPositionParams,
|
||||
TextDocumentRegistrationOptions, Url, WorkDoneProgressOptions, WorkDoneProgressParams,
|
||||
};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub type TypeHierarchyClientCapabilities = DynamicRegistrationClientCapabilities;
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
pub struct TypeHierarchyOptions {
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_options: WorkDoneProgressOptions,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
pub struct TypeHierarchyRegistrationOptions {
|
||||
#[serde(flatten)]
|
||||
pub text_document_registration_options: TextDocumentRegistrationOptions,
|
||||
#[serde(flatten)]
|
||||
pub type_hierarchy_options: TypeHierarchyOptions,
|
||||
#[serde(flatten)]
|
||||
pub static_registration_options: StaticRegistrationOptions,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
pub struct TypeHierarchyPrepareParams {
|
||||
#[serde(flatten)]
|
||||
pub text_document_position_params: TextDocumentPositionParams,
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_params: WorkDoneProgressParams,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
pub struct TypeHierarchySupertypesParams {
|
||||
pub item: TypeHierarchyItem,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_params: WorkDoneProgressParams,
|
||||
#[serde(flatten)]
|
||||
pub partial_result_params: PartialResultParams,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
pub struct TypeHierarchySubtypesParams {
|
||||
pub item: TypeHierarchyItem,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_params: WorkDoneProgressParams,
|
||||
#[serde(flatten)]
|
||||
pub partial_result_params: PartialResultParams,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct TypeHierarchyItem {
|
||||
/// The name of this item.
|
||||
pub name: String,
|
||||
|
||||
/// The kind of this item.
|
||||
pub kind: SymbolKind,
|
||||
|
||||
/// Tags for this item.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub tags: Option<SymbolTag>,
|
||||
|
||||
/// More detail for this item, e.g. the signature of a function.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub detail: Option<String>,
|
||||
|
||||
/// The resource identifier of this item.
|
||||
pub uri: Url,
|
||||
|
||||
/// The range enclosing this symbol not including leading/trailing whitespace
|
||||
/// but everything else, e.g. comments and code.
|
||||
pub range: Range,
|
||||
|
||||
/// The range that should be selected and revealed when this symbol is being
|
||||
/// picked, e.g. the name of a function. Must be contained by the
|
||||
/// [`range`](#TypeHierarchyItem.range).
|
||||
pub selection_range: Range,
|
||||
|
||||
/// A data entry field that is preserved between a type hierarchy prepare and
|
||||
/// supertypes or subtypes requests. It could also be used to identify the
|
||||
/// type hierarchy in the server, helping improve the performance on
|
||||
/// resolving supertypes and subtypes.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub data: Option<LSPAny>,
|
||||
}
|
173
helix-lsp-types/src/window.rs
Normal file
173
helix-lsp-types/src/window.rs
Normal file
@ -0,0 +1,173 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use serde_json::Value;
|
||||
|
||||
use url::Url;
|
||||
|
||||
use crate::Range;
|
||||
|
||||
#[derive(Eq, PartialEq, Clone, Copy, Deserialize, Serialize)]
|
||||
#[serde(transparent)]
|
||||
pub struct MessageType(i32);
|
||||
lsp_enum! {
|
||||
impl MessageType {
|
||||
/// An error message.
|
||||
pub const ERROR: MessageType = MessageType(1);
|
||||
/// A warning message.
|
||||
pub const WARNING: MessageType = MessageType(2);
|
||||
/// An information message;
|
||||
pub const INFO: MessageType = MessageType(3);
|
||||
/// A log message.
|
||||
pub const LOG: MessageType = MessageType(4);
|
||||
}
|
||||
}
|
||||
|
||||
/// Window specific client capabilities.
|
||||
#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct WindowClientCapabilities {
|
||||
/// Whether client supports handling progress notifications. If set
|
||||
/// servers are allowed to report in `workDoneProgress` property in the
|
||||
/// request specific server capabilities.
|
||||
///
|
||||
/// @since 3.15.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub work_done_progress: Option<bool>,
|
||||
|
||||
/// Capabilities specific to the showMessage request.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub show_message: Option<ShowMessageRequestClientCapabilities>,
|
||||
|
||||
/// Client capabilities for the show document request.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub show_document: Option<ShowDocumentClientCapabilities>,
|
||||
}
|
||||
|
||||
/// Show message request client capabilities
|
||||
#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ShowMessageRequestClientCapabilities {
|
||||
/// Capabilities specific to the `MessageActionItem` type.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub message_action_item: Option<MessageActionItemCapabilities>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct MessageActionItemCapabilities {
|
||||
/// Whether the client supports additional attributes which
|
||||
/// are preserved and send back to the server in the
|
||||
/// request's response.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub additional_properties_support: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct MessageActionItem {
|
||||
/// A short title like 'Retry', 'Open Log' etc.
|
||||
pub title: String,
|
||||
|
||||
/// Additional attributes that the client preserves and
|
||||
/// sends back to the server. This depends on the client
|
||||
/// capability window.messageActionItem.additionalPropertiesSupport
|
||||
#[serde(flatten)]
|
||||
pub properties: HashMap<String, MessageActionItemProperty>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum MessageActionItemProperty {
|
||||
String(String),
|
||||
Boolean(bool),
|
||||
Integer(i32),
|
||||
Object(Value),
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
pub struct LogMessageParams {
|
||||
/// The message type. See {@link MessageType}
|
||||
#[serde(rename = "type")]
|
||||
pub typ: MessageType,
|
||||
|
||||
/// The actual message
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
pub struct ShowMessageParams {
|
||||
/// The message type. See {@link MessageType}.
|
||||
#[serde(rename = "type")]
|
||||
pub typ: MessageType,
|
||||
|
||||
/// The actual message.
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
pub struct ShowMessageRequestParams {
|
||||
/// The message type. See {@link MessageType}
|
||||
#[serde(rename = "type")]
|
||||
pub typ: MessageType,
|
||||
|
||||
/// The actual message
|
||||
pub message: String,
|
||||
|
||||
/// The message action items to present.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub actions: Option<Vec<MessageActionItem>>,
|
||||
}
|
||||
|
||||
/// Client capabilities for the show document request.
|
||||
#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ShowDocumentClientCapabilities {
|
||||
/// The client has support for the show document request.
|
||||
pub support: bool,
|
||||
}
|
||||
|
||||
/// Params to show a document.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ShowDocumentParams {
|
||||
/// The document uri to show.
|
||||
pub uri: Url,
|
||||
|
||||
/// Indicates to show the resource in an external program.
|
||||
/// To show for example `https://code.visualstudio.com/`
|
||||
/// in the default WEB browser set `external` to `true`.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub external: Option<bool>,
|
||||
|
||||
/// An optional property to indicate whether the editor
|
||||
/// showing the document should take focus or not.
|
||||
/// Clients might ignore this property if an external
|
||||
/// program in started.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub take_focus: Option<bool>,
|
||||
|
||||
/// An optional selection range if the document is a text
|
||||
/// document. Clients might ignore the property if an
|
||||
/// external program is started or the file is not a text
|
||||
/// file.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub selection: Option<Range>,
|
||||
}
|
||||
|
||||
/// The result of an show document request.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ShowDocumentResult {
|
||||
/// A boolean indicating if the show was successful.
|
||||
pub success: bool,
|
||||
}
|
149
helix-lsp-types/src/workspace_diagnostic.rs
Normal file
149
helix-lsp-types/src/workspace_diagnostic.rs
Normal file
@ -0,0 +1,149 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use url::Url;
|
||||
|
||||
use crate::{
|
||||
FullDocumentDiagnosticReport, PartialResultParams, UnchangedDocumentDiagnosticReport,
|
||||
WorkDoneProgressParams,
|
||||
};
|
||||
|
||||
/// Workspace client capabilities specific to diagnostic pull requests.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DiagnosticWorkspaceClientCapabilities {
|
||||
/// Whether the client implementation supports a refresh request sent from
|
||||
/// the server to the client.
|
||||
///
|
||||
/// Note that this event is global and will force the client to refresh all
|
||||
/// pulled diagnostics currently shown. It should be used with absolute care
|
||||
/// and is useful for situation where a server for example detects a project
|
||||
/// wide change that requires such a calculation.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub refresh_support: Option<bool>,
|
||||
}
|
||||
|
||||
/// A previous result ID in a workspace pull request.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
pub struct PreviousResultId {
|
||||
/// The URI for which the client knows a result ID.
|
||||
pub uri: Url,
|
||||
|
||||
/// The value of the previous result ID.
|
||||
pub value: String,
|
||||
}
|
||||
|
||||
/// Parameters of the workspace diagnostic request.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct WorkspaceDiagnosticParams {
|
||||
/// The additional identifier provided during registration.
|
||||
pub identifier: Option<String>,
|
||||
|
||||
/// The currently known diagnostic reports with their
|
||||
/// previous result ids.
|
||||
pub previous_result_ids: Vec<PreviousResultId>,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_params: WorkDoneProgressParams,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub partial_result_params: PartialResultParams,
|
||||
}
|
||||
|
||||
/// A full document diagnostic report for a workspace diagnostic result.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct WorkspaceFullDocumentDiagnosticReport {
|
||||
/// The URI for which diagnostic information is reported.
|
||||
pub uri: Url,
|
||||
|
||||
/// The version number for which the diagnostics are reported.
|
||||
///
|
||||
/// If the document is not marked as open, `None` can be provided.
|
||||
pub version: Option<i64>,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub full_document_diagnostic_report: FullDocumentDiagnosticReport,
|
||||
}
|
||||
|
||||
/// An unchanged document diagnostic report for a workspace diagnostic result.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct WorkspaceUnchangedDocumentDiagnosticReport {
|
||||
/// The URI for which diagnostic information is reported.
|
||||
pub uri: Url,
|
||||
|
||||
/// The version number for which the diagnostics are reported.
|
||||
///
|
||||
/// If the document is not marked as open, `None` can be provided.
|
||||
pub version: Option<i64>,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub unchanged_document_diagnostic_report: UnchangedDocumentDiagnosticReport,
|
||||
}
|
||||
|
||||
/// A workspace diagnostic document report.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)]
|
||||
#[serde(tag = "kind", rename_all = "lowercase")]
|
||||
pub enum WorkspaceDocumentDiagnosticReport {
|
||||
Full(WorkspaceFullDocumentDiagnosticReport),
|
||||
Unchanged(WorkspaceUnchangedDocumentDiagnosticReport),
|
||||
}
|
||||
|
||||
impl From<WorkspaceFullDocumentDiagnosticReport> for WorkspaceDocumentDiagnosticReport {
|
||||
fn from(from: WorkspaceFullDocumentDiagnosticReport) -> Self {
|
||||
WorkspaceDocumentDiagnosticReport::Full(from)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<WorkspaceUnchangedDocumentDiagnosticReport> for WorkspaceDocumentDiagnosticReport {
|
||||
fn from(from: WorkspaceUnchangedDocumentDiagnosticReport) -> Self {
|
||||
WorkspaceDocumentDiagnosticReport::Unchanged(from)
|
||||
}
|
||||
}
|
||||
|
||||
/// A workspace diagnostic report.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, PartialEq, Default, Deserialize, Serialize, Clone)]
|
||||
pub struct WorkspaceDiagnosticReport {
|
||||
pub items: Vec<WorkspaceDocumentDiagnosticReport>,
|
||||
}
|
||||
|
||||
/// A partial result for a workspace diagnostic report.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, PartialEq, Default, Deserialize, Serialize, Clone)]
|
||||
pub struct WorkspaceDiagnosticReportPartialResult {
|
||||
pub items: Vec<WorkspaceDocumentDiagnosticReport>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)]
|
||||
#[serde(untagged)]
|
||||
pub enum WorkspaceDiagnosticReportResult {
|
||||
Report(WorkspaceDiagnosticReport),
|
||||
Partial(WorkspaceDiagnosticReportPartialResult),
|
||||
}
|
||||
|
||||
impl From<WorkspaceDiagnosticReport> for WorkspaceDiagnosticReportResult {
|
||||
fn from(from: WorkspaceDiagnosticReport) -> Self {
|
||||
WorkspaceDiagnosticReportResult::Report(from)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<WorkspaceDiagnosticReportPartialResult> for WorkspaceDiagnosticReportResult {
|
||||
fn from(from: WorkspaceDiagnosticReportPartialResult) -> Self {
|
||||
WorkspaceDiagnosticReportResult::Partial(from)
|
||||
}
|
||||
}
|
49
helix-lsp-types/src/workspace_folders.rs
Normal file
49
helix-lsp-types/src/workspace_folders.rs
Normal file
@ -0,0 +1,49 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use url::Url;
|
||||
|
||||
use crate::OneOf;
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct WorkspaceFoldersServerCapabilities {
|
||||
/// The server has support for workspace folders
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub supported: Option<bool>,
|
||||
|
||||
/// Whether the server wants to receive workspace folder
|
||||
/// change notifications.
|
||||
///
|
||||
/// If a string is provided, the string is treated as an ID
|
||||
/// under which the notification is registered on the client
|
||||
/// side. The ID can be used to unregister for these events
|
||||
/// using the `client/unregisterCapability` request.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub change_notifications: Option<OneOf<bool, String>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct WorkspaceFolder {
|
||||
/// The associated URI for this workspace folder.
|
||||
pub uri: Url,
|
||||
/// The name of the workspace folder. Defaults to the uri's basename.
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DidChangeWorkspaceFoldersParams {
|
||||
/// The actual workspace folder change event.
|
||||
pub event: WorkspaceFoldersChangeEvent,
|
||||
}
|
||||
|
||||
/// The workspace folder change event.
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct WorkspaceFoldersChangeEvent {
|
||||
/// The array of added workspace folders
|
||||
pub added: Vec<WorkspaceFolder>,
|
||||
|
||||
/// The array of the removed workspace folders
|
||||
pub removed: Vec<WorkspaceFolder>,
|
||||
}
|
105
helix-lsp-types/src/workspace_symbols.rs
Normal file
105
helix-lsp-types/src/workspace_symbols.rs
Normal file
@ -0,0 +1,105 @@
|
||||
use crate::{
|
||||
LSPAny, Location, OneOf, PartialResultParams, SymbolInformation, SymbolKind,
|
||||
SymbolKindCapability, SymbolTag, TagSupport, Url, WorkDoneProgressParams,
|
||||
};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct WorkspaceSymbolClientCapabilities {
|
||||
/// This capability supports dynamic registration.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub dynamic_registration: Option<bool>,
|
||||
|
||||
/// Specific capabilities for the `SymbolKind` in the `workspace/symbol` request.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub symbol_kind: Option<SymbolKindCapability>,
|
||||
|
||||
/// The client supports tags on `SymbolInformation`.
|
||||
/// Clients supporting tags have to handle unknown tags gracefully.
|
||||
///
|
||||
/// @since 3.16.0
|
||||
#[serde(
|
||||
default,
|
||||
skip_serializing_if = "Option::is_none",
|
||||
deserialize_with = "TagSupport::deserialize_compat"
|
||||
)]
|
||||
pub tag_support: Option<TagSupport<SymbolTag>>,
|
||||
|
||||
/// The client support partial workspace symbols. The client will send the
|
||||
/// request `workspaceSymbol/resolve` to the server to resolve additional
|
||||
/// properties.
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub resolve_support: Option<WorkspaceSymbolResolveSupportCapability>,
|
||||
}
|
||||
|
||||
/// The parameters of a Workspace Symbol Request.
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
pub struct WorkspaceSymbolParams {
|
||||
#[serde(flatten)]
|
||||
pub partial_result_params: PartialResultParams,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub work_done_progress_params: WorkDoneProgressParams,
|
||||
|
||||
/// A non-empty query string
|
||||
pub query: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
pub struct WorkspaceSymbolResolveSupportCapability {
|
||||
/// The properties that a client can resolve lazily. Usually
|
||||
/// `location.range`
|
||||
pub properties: Vec<String>,
|
||||
}
|
||||
|
||||
/// A special workspace symbol that supports locations without a range
|
||||
///
|
||||
/// @since 3.17.0
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct WorkspaceSymbol {
|
||||
/// The name of this symbol.
|
||||
pub name: String,
|
||||
|
||||
/// The kind of this symbol.
|
||||
pub kind: SymbolKind,
|
||||
|
||||
/// Tags for this completion item.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub tags: Option<Vec<SymbolTag>>,
|
||||
|
||||
/// The name of the symbol containing this symbol. This information is for
|
||||
/// user interface purposes (e.g. to render a qualifier in the user interface
|
||||
/// if necessary). It can't be used to re-infer a hierarchy for the document
|
||||
/// symbols.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub container_name: Option<String>,
|
||||
|
||||
/// The location of this symbol. Whether a server is allowed to
|
||||
/// return a location without a range depends on the client
|
||||
/// capability `workspace.symbol.resolveSupport`.
|
||||
///
|
||||
/// See also `SymbolInformation.location`.
|
||||
pub location: OneOf<Location, WorkspaceLocation>,
|
||||
|
||||
/// A data entry field that is preserved on a workspace symbol between a
|
||||
/// workspace symbol request and a workspace symbol resolve request.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub data: Option<LSPAny>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
|
||||
pub struct WorkspaceLocation {
|
||||
pub uri: Url,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Serialize, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum WorkspaceSymbolResponse {
|
||||
Flat(Vec<SymbolInformation>),
|
||||
Nested(Vec<WorkspaceSymbol>),
|
||||
}
|
@ -17,16 +17,16 @@ helix-stdx = { path = "../helix-stdx" }
|
||||
helix-core = { path = "../helix-core" }
|
||||
helix-loader = { path = "../helix-loader" }
|
||||
helix-parsec = { path = "../helix-parsec" }
|
||||
helix-lsp-types = { path = "../helix-lsp-types" }
|
||||
|
||||
anyhow = "1.0"
|
||||
futures-executor = "0.3"
|
||||
futures-util = { version = "0.3", features = ["std", "async-await"], default-features = false }
|
||||
globset = "0.4.14"
|
||||
log = "0.4"
|
||||
lsp-types = { version = "0.95" }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
tokio = { version = "1.38", features = ["rt", "rt-multi-thread", "io-util", "io-std", "time", "process", "macros", "fs", "parking_lot", "sync"] }
|
||||
tokio = { version = "1.39", features = ["rt", "rt-multi-thread", "io-util", "io-std", "time", "process", "macros", "fs", "parking_lot", "sync"] }
|
||||
tokio-stream = "0.1.15"
|
||||
parking_lot = "0.12.3"
|
||||
arc-swap = "1"
|
||||
|
@ -5,15 +5,14 @@
|
||||
Call, Error, LanguageServerId, OffsetEncoding, Result,
|
||||
};
|
||||
|
||||
use helix_core::{find_workspace, syntax::LanguageServerFeature, ChangeSet, Rope};
|
||||
use helix_loader::VERSION_AND_GIT_HASH;
|
||||
use helix_stdx::path;
|
||||
use lsp::{
|
||||
notification::DidChangeWorkspaceFolders, CodeActionCapabilityResolveSupport,
|
||||
use crate::lsp::{
|
||||
self, notification::DidChangeWorkspaceFolders, CodeActionCapabilityResolveSupport,
|
||||
DidChangeWorkspaceFoldersParams, OneOf, PositionEncodingKind, SignatureHelp, Url,
|
||||
WorkspaceFolder, WorkspaceFoldersChangeEvent,
|
||||
};
|
||||
use lsp_types as lsp;
|
||||
use helix_core::{find_workspace, syntax::LanguageServerFeature, ChangeSet, Rope};
|
||||
use helix_loader::VERSION_AND_GIT_HASH;
|
||||
use helix_stdx::path;
|
||||
use parking_lot::Mutex;
|
||||
use serde::Deserialize;
|
||||
use serde_json::Value;
|
||||
@ -994,7 +993,7 @@ pub fn text_document_did_save(
|
||||
..
|
||||
}) => match options.as_ref()? {
|
||||
lsp::TextDocumentSyncSaveOptions::Supported(true) => false,
|
||||
lsp::TextDocumentSyncSaveOptions::SaveOptions(lsp_types::SaveOptions {
|
||||
lsp::TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
|
||||
include_text,
|
||||
}) => include_text.unwrap_or(false),
|
||||
lsp::TextDocumentSyncSaveOptions::Supported(false) => return None,
|
||||
|
@ -8,9 +8,9 @@
|
||||
use arc_swap::ArcSwap;
|
||||
pub use client::Client;
|
||||
pub use futures_executor::block_on;
|
||||
pub use helix_lsp_types as lsp;
|
||||
pub use jsonrpc::Call;
|
||||
pub use lsp::{Position, Url};
|
||||
pub use lsp_types as lsp;
|
||||
|
||||
use futures_util::stream::select_all::SelectAll;
|
||||
use helix_core::syntax::{
|
||||
@ -503,7 +503,7 @@ pub fn generate_transaction_from_edits(
|
||||
) -> Transaction {
|
||||
// Sort edits by start range, since some LSPs (Omnisharp) send them
|
||||
// in reverse order.
|
||||
edits.sort_unstable_by_key(|edit| edit.range.start);
|
||||
edits.sort_by_key(|edit| edit.range.start);
|
||||
|
||||
// Generate a diff if the edit is a full document replacement.
|
||||
#[allow(clippy::collapsible_if)]
|
||||
@ -1113,7 +1113,7 @@ macro_rules! test_case {
|
||||
|
||||
#[test]
|
||||
fn emoji_format_gh_4791() {
|
||||
use lsp_types::{Position, Range, TextEdit};
|
||||
use lsp::{Position, Range, TextEdit};
|
||||
|
||||
let edits = vec![
|
||||
TextEdit {
|
||||
|
@ -1,4 +1,8 @@
|
||||
use crate::{jsonrpc, Error, LanguageServerId, Result};
|
||||
use crate::{
|
||||
jsonrpc,
|
||||
lsp::{self, notification::Notification as _},
|
||||
Error, LanguageServerId, Result,
|
||||
};
|
||||
use anyhow::Context;
|
||||
use log::{error, info};
|
||||
use serde::{Deserialize, Serialize};
|
||||
@ -289,11 +293,10 @@ async fn recv(
|
||||
}
|
||||
|
||||
// Hack: inject a terminated notification so we trigger code that needs to happen after exit
|
||||
use lsp_types::notification::Notification as _;
|
||||
let notification =
|
||||
ServerMessage::Call(jsonrpc::Call::Notification(jsonrpc::Notification {
|
||||
jsonrpc: None,
|
||||
method: lsp_types::notification::Exit::METHOD.to_string(),
|
||||
method: lsp::notification::Exit::METHOD.to_string(),
|
||||
params: jsonrpc::Params::None,
|
||||
}));
|
||||
match transport
|
||||
@ -338,8 +341,8 @@ async fn send(
|
||||
|
||||
// Determine if a message is allowed to be sent early
|
||||
fn is_initialize(payload: &Payload) -> bool {
|
||||
use lsp_types::{
|
||||
notification::{Initialized, Notification},
|
||||
use lsp::{
|
||||
notification::Initialized,
|
||||
request::{Initialize, Request},
|
||||
};
|
||||
match payload {
|
||||
@ -357,7 +360,7 @@ fn is_initialize(payload: &Payload) -> bool {
|
||||
}
|
||||
|
||||
fn is_shutdown(payload: &Payload) -> bool {
|
||||
use lsp_types::request::{Request, Shutdown};
|
||||
use lsp::request::{Request, Shutdown};
|
||||
matches!(payload, Payload::Request { value: jsonrpc::MethodCall { method, .. }, .. } if method == Shutdown::METHOD)
|
||||
}
|
||||
|
||||
@ -370,12 +373,11 @@ fn is_shutdown(payload: &Payload) -> bool {
|
||||
// server successfully initialized
|
||||
is_pending = false;
|
||||
|
||||
use lsp_types::notification::Notification;
|
||||
// Hack: inject an initialized notification so we trigger code that needs to happen after init
|
||||
let notification = ServerMessage::Call(jsonrpc::Call::Notification(jsonrpc::Notification {
|
||||
jsonrpc: None,
|
||||
|
||||
method: lsp_types::notification::Initialized::METHOD.to_string(),
|
||||
method: lsp::notification::Initialized::METHOD.to_string(),
|
||||
params: jsonrpc::Params::None,
|
||||
}));
|
||||
let language_server_name = &transport.name;
|
||||
|
@ -20,10 +20,10 @@ regex-cursor = "0.1.4"
|
||||
bitflags = "2.6"
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
windows-sys = { version = "0.52", features = ["Win32_Security", "Win32_Security_Authorization", "Win32_System_Threading"] }
|
||||
windows-sys = { version = "0.59", features = ["Win32_Foundation", "Win32_Security", "Win32_Security_Authorization", "Win32_Storage_FileSystem", "Win32_System_Threading"] }
|
||||
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
rustix = { version = "0.38", features = ["fs"] }
|
||||
|
||||
[dev-dependencies]
|
||||
tempfile = "3.10"
|
||||
tempfile = "3.12"
|
||||
|
@ -85,7 +85,7 @@ pub fn hardlink_count(p: &Path) -> std::io::Result<u64> {
|
||||
#[cfg(windows)]
|
||||
mod imp {
|
||||
|
||||
use windows_sys::Win32::Foundation::{CloseHandle, LocalFree, ERROR_SUCCESS, HANDLE, PSID};
|
||||
use windows_sys::Win32::Foundation::{CloseHandle, LocalFree, ERROR_SUCCESS, HANDLE};
|
||||
use windows_sys::Win32::Security::Authorization::{
|
||||
GetNamedSecurityInfoW, SetNamedSecurityInfoW, SE_FILE_OBJECT,
|
||||
};
|
||||
@ -95,7 +95,7 @@ mod imp {
|
||||
SecurityImpersonation, ACCESS_ALLOWED_CALLBACK_ACE, ACL, ACL_SIZE_INFORMATION,
|
||||
DACL_SECURITY_INFORMATION, GENERIC_MAPPING, GROUP_SECURITY_INFORMATION, INHERITED_ACE,
|
||||
LABEL_SECURITY_INFORMATION, OBJECT_SECURITY_INFORMATION, OWNER_SECURITY_INFORMATION,
|
||||
PRIVILEGE_SET, PROTECTED_DACL_SECURITY_INFORMATION, PSECURITY_DESCRIPTOR,
|
||||
PRIVILEGE_SET, PROTECTED_DACL_SECURITY_INFORMATION, PSECURITY_DESCRIPTOR, PSID,
|
||||
SID_IDENTIFIER_AUTHORITY, TOKEN_DUPLICATE, TOKEN_QUERY,
|
||||
};
|
||||
use windows_sys::Win32::Storage::FileSystem::{
|
||||
@ -295,21 +295,21 @@ fn eaccess(p: &Path, mut mode: FILE_ACCESS_RIGHTS) -> io::Result<()> {
|
||||
let mut privileges_length = std::mem::size_of::<PRIVILEGE_SET>() as u32;
|
||||
let mut result = 0;
|
||||
|
||||
let mut mapping = GENERIC_MAPPING {
|
||||
let mapping = GENERIC_MAPPING {
|
||||
GenericRead: FILE_GENERIC_READ,
|
||||
GenericWrite: FILE_GENERIC_WRITE,
|
||||
GenericExecute: FILE_GENERIC_EXECUTE,
|
||||
GenericAll: FILE_ALL_ACCESS,
|
||||
};
|
||||
|
||||
unsafe { MapGenericMask(&mut mode, &mut mapping) };
|
||||
unsafe { MapGenericMask(&mut mode, &mapping) };
|
||||
|
||||
if unsafe {
|
||||
AccessCheck(
|
||||
*sd.descriptor(),
|
||||
*token.as_handle(),
|
||||
mode,
|
||||
&mut mapping,
|
||||
&mapping,
|
||||
&mut privileges,
|
||||
&mut privileges_length,
|
||||
&mut granted_access,
|
||||
@ -419,7 +419,7 @@ pub fn copy_metadata(from: &Path, to: &Path) -> io::Result<()> {
|
||||
|
||||
pub fn hardlink_count(p: &Path) -> std::io::Result<u64> {
|
||||
let file = std::fs::File::open(p)?;
|
||||
let handle = file.as_raw_handle() as isize;
|
||||
let handle = file.as_raw_handle();
|
||||
let mut info: BY_HANDLE_FILE_INFORMATION = unsafe { std::mem::zeroed() };
|
||||
|
||||
if unsafe { GetFileInformationByHandle(handle, &mut info) } == 0 {
|
||||
|
@ -37,7 +37,7 @@ once_cell = "1.19"
|
||||
|
||||
tokio = { version = "1", features = ["rt", "rt-multi-thread", "io-util", "io-std", "time", "process", "macros", "fs", "parking_lot"] }
|
||||
tui = { path = "../helix-tui", package = "helix-tui", default-features = false, features = ["crossterm"] }
|
||||
crossterm = { version = "0.27", features = ["event-stream"] }
|
||||
crossterm = { version = "0.28", features = ["event-stream"] }
|
||||
signal-hook = "0.3"
|
||||
tokio-stream = "0.1"
|
||||
futures-util = { version = "0.3", features = ["std", "async-await"], default-features = false }
|
||||
@ -53,7 +53,7 @@ log = "0.4"
|
||||
nucleo.workspace = true
|
||||
ignore = "0.4"
|
||||
# markdown doc rendering
|
||||
pulldown-cmark = { version = "0.11", default-features = false }
|
||||
pulldown-cmark = { version = "0.12", default-features = false }
|
||||
# file type detection
|
||||
content_inspector = "0.2.4"
|
||||
thiserror = "1.0"
|
||||
@ -74,10 +74,10 @@ grep-searcher = "0.1.13"
|
||||
|
||||
[target.'cfg(not(windows))'.dependencies] # https://github.com/vorner/signal-hook/issues/100
|
||||
signal-hook-tokio = { version = "0.3", features = ["futures-v0_3"] }
|
||||
libc = "0.2.155"
|
||||
libc = "0.2.158"
|
||||
|
||||
[target.'cfg(target_os = "macos")'.dependencies]
|
||||
crossterm = { version = "0.27", features = ["event-stream", "use-dev-tty"] }
|
||||
crossterm = { version = "0.28", features = ["event-stream", "use-dev-tty", "libc"] }
|
||||
|
||||
[build-dependencies]
|
||||
helix-loader = { path = "../helix-loader" }
|
||||
@ -85,5 +85,5 @@ helix-loader = { path = "../helix-loader" }
|
||||
[dev-dependencies]
|
||||
smallvec = "1.13"
|
||||
indoc = "2.0.5"
|
||||
tempfile = "3.10.1"
|
||||
tempfile = "3.12.0"
|
||||
same-file = "1.0.1"
|
||||
|
@ -66,18 +66,16 @@ fn find_rc_exe() -> io::Result<PathBuf> {
|
||||
.output();
|
||||
|
||||
match find_reg_key {
|
||||
Err(find_reg_key) => {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("Failed to run registry query: {}", find_reg_key),
|
||||
))
|
||||
}
|
||||
Err(find_reg_key) => Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("Failed to run registry query: {}", find_reg_key),
|
||||
)),
|
||||
Ok(find_reg_key) => {
|
||||
if find_reg_key.status.code().unwrap() != 0 {
|
||||
return Err(io::Error::new(
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
"Can not find Windows SDK",
|
||||
));
|
||||
))
|
||||
} else {
|
||||
let lines = String::from_utf8(find_reg_key.stdout)
|
||||
.expect("Should be able to parse the output");
|
||||
|
@ -35,7 +35,9 @@
|
||||
use std::io::stdout;
|
||||
use std::{collections::btree_map::Entry, io::stdin, path::Path, sync::Arc};
|
||||
|
||||
use anyhow::{Context, Error};
|
||||
#[cfg(not(windows))]
|
||||
use anyhow::Context;
|
||||
use anyhow::Error;
|
||||
|
||||
use crossterm::{event::Event as CrosstermEvent, tty::IsTty};
|
||||
#[cfg(not(windows))]
|
||||
|
@ -176,9 +176,16 @@ fn make_job_callback<T, F>(
|
||||
|
||||
use helix_view::{align_view, Align};
|
||||
|
||||
/// A MappableCommand is either a static command like "jump_view_up" or a Typable command like
|
||||
/// :format. It causes a side-effect on the state (usually by creating and applying a transaction).
|
||||
/// Both of these types of commands can be mapped with keybindings in the config.toml.
|
||||
/// MappableCommands are commands that can be bound to keys, executable in
|
||||
/// normal, insert or select mode.
|
||||
///
|
||||
/// There are three kinds:
|
||||
///
|
||||
/// * Static: commands usually bound to keys and used for editing, movement,
|
||||
/// etc., for example `move_char_left`.
|
||||
/// * Typable: commands executable from command mode, prefixed with a `:`,
|
||||
/// for example `:write!`.
|
||||
/// * Macro: a sequence of keys to execute, for example `@miw`.
|
||||
#[derive(Clone)]
|
||||
pub enum MappableCommand {
|
||||
Typable {
|
||||
@ -191,6 +198,10 @@ pub enum MappableCommand {
|
||||
fun: fn(cx: &mut Context),
|
||||
doc: &'static str,
|
||||
},
|
||||
Macro {
|
||||
name: String,
|
||||
keys: Vec<KeyEvent>,
|
||||
},
|
||||
}
|
||||
|
||||
macro_rules! static_commands {
|
||||
@ -227,6 +238,23 @@ pub fn execute(&self, cx: &mut Context) {
|
||||
}
|
||||
}
|
||||
Self::Static { fun, .. } => (fun)(cx),
|
||||
Self::Macro { keys, .. } => {
|
||||
// Protect against recursive macros.
|
||||
if cx.editor.macro_replaying.contains(&'@') {
|
||||
cx.editor.set_error(
|
||||
"Cannot execute macro because the [@] register is already playing a macro",
|
||||
);
|
||||
return;
|
||||
}
|
||||
cx.editor.macro_replaying.push('@');
|
||||
let keys = keys.clone();
|
||||
cx.callback.push(Box::new(move |compositor, cx| {
|
||||
for key in keys.into_iter() {
|
||||
compositor.handle_event(&compositor::Event::Key(key), cx);
|
||||
}
|
||||
cx.editor.macro_replaying.pop();
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -234,6 +262,7 @@ pub fn name(&self) -> &str {
|
||||
match &self {
|
||||
Self::Typable { name, .. } => name,
|
||||
Self::Static { name, .. } => name,
|
||||
Self::Macro { name, .. } => name,
|
||||
}
|
||||
}
|
||||
|
||||
@ -241,6 +270,7 @@ pub fn doc(&self) -> &str {
|
||||
match &self {
|
||||
Self::Typable { doc, .. } => doc,
|
||||
Self::Static { doc, .. } => doc,
|
||||
Self::Macro { name, .. } => name,
|
||||
}
|
||||
}
|
||||
|
||||
@ -269,6 +299,10 @@ pub fn doc(&self) -> &str {
|
||||
move_prev_long_word_start, "Move to start of previous long word",
|
||||
move_next_long_word_end, "Move to end of next long word",
|
||||
move_prev_long_word_end, "Move to end of previous long word",
|
||||
move_next_sub_word_start, "Move to start of next sub word",
|
||||
move_prev_sub_word_start, "Move to start of previous sub word",
|
||||
move_next_sub_word_end, "Move to end of next sub word",
|
||||
move_prev_sub_word_end, "Move to end of previous sub word",
|
||||
move_parent_node_end, "Move to end of the parent node",
|
||||
move_parent_node_start, "Move to beginning of the parent node",
|
||||
extend_next_word_start, "Extend to start of next word",
|
||||
@ -279,6 +313,10 @@ pub fn doc(&self) -> &str {
|
||||
extend_prev_long_word_start, "Extend to start of previous long word",
|
||||
extend_next_long_word_end, "Extend to end of next long word",
|
||||
extend_prev_long_word_end, "Extend to end of prev long word",
|
||||
extend_next_sub_word_start, "Extend to start of next sub word",
|
||||
extend_prev_sub_word_start, "Extend to start of previous sub word",
|
||||
extend_next_sub_word_end, "Extend to end of next sub word",
|
||||
extend_prev_sub_word_end, "Extend to end of prev sub word",
|
||||
extend_parent_node_end, "Extend to end of the parent node",
|
||||
extend_parent_node_start, "Extend to beginning of the parent node",
|
||||
find_till_char, "Move till next occurrence of char",
|
||||
@ -543,6 +581,11 @@ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
.field(name)
|
||||
.field(args)
|
||||
.finish(),
|
||||
MappableCommand::Macro { name, keys, .. } => f
|
||||
.debug_tuple("MappableCommand")
|
||||
.field(name)
|
||||
.field(keys)
|
||||
.finish(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -573,6 +616,11 @@ fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
args,
|
||||
})
|
||||
.ok_or_else(|| anyhow!("No TypableCommand named '{}'", s))
|
||||
} else if let Some(suffix) = s.strip_prefix('@') {
|
||||
helix_view::input::parse_macro(suffix).map(|keys| Self::Macro {
|
||||
name: s.to_string(),
|
||||
keys,
|
||||
})
|
||||
} else {
|
||||
MappableCommand::STATIC_COMMAND_LIST
|
||||
.iter()
|
||||
@ -1126,6 +1174,22 @@ fn move_next_long_word_end(cx: &mut Context) {
|
||||
move_word_impl(cx, movement::move_next_long_word_end)
|
||||
}
|
||||
|
||||
fn move_next_sub_word_start(cx: &mut Context) {
|
||||
move_word_impl(cx, movement::move_next_sub_word_start)
|
||||
}
|
||||
|
||||
fn move_prev_sub_word_start(cx: &mut Context) {
|
||||
move_word_impl(cx, movement::move_prev_sub_word_start)
|
||||
}
|
||||
|
||||
fn move_prev_sub_word_end(cx: &mut Context) {
|
||||
move_word_impl(cx, movement::move_prev_sub_word_end)
|
||||
}
|
||||
|
||||
fn move_next_sub_word_end(cx: &mut Context) {
|
||||
move_word_impl(cx, movement::move_next_sub_word_end)
|
||||
}
|
||||
|
||||
fn goto_para_impl<F>(cx: &mut Context, move_fn: F)
|
||||
where
|
||||
F: Fn(RopeSlice, Range, usize, Movement) -> Range + 'static,
|
||||
@ -1362,6 +1426,22 @@ fn extend_next_long_word_end(cx: &mut Context) {
|
||||
extend_word_impl(cx, movement::move_next_long_word_end)
|
||||
}
|
||||
|
||||
fn extend_next_sub_word_start(cx: &mut Context) {
|
||||
extend_word_impl(cx, movement::move_next_sub_word_start)
|
||||
}
|
||||
|
||||
fn extend_prev_sub_word_start(cx: &mut Context) {
|
||||
extend_word_impl(cx, movement::move_prev_sub_word_start)
|
||||
}
|
||||
|
||||
fn extend_prev_sub_word_end(cx: &mut Context) {
|
||||
extend_word_impl(cx, movement::move_prev_sub_word_end)
|
||||
}
|
||||
|
||||
fn extend_next_sub_word_end(cx: &mut Context) {
|
||||
extend_word_impl(cx, movement::move_next_sub_word_end)
|
||||
}
|
||||
|
||||
/// Separate branch to find_char designed only for `<ret>` char.
|
||||
//
|
||||
// This is necessary because the one document can have different line endings inside. And we
|
||||
@ -1939,6 +2019,8 @@ fn select_regex(cx: &mut Context) {
|
||||
selection::select_on_matches(text, doc.selection(view.id), ®ex)
|
||||
{
|
||||
doc.set_selection(view.id, selection);
|
||||
} else {
|
||||
cx.editor.set_error("nothing selected");
|
||||
}
|
||||
},
|
||||
);
|
||||
@ -3143,6 +3225,9 @@ pub fn command_palette(cx: &mut Context) {
|
||||
ui::PickerColumn::new("name", |item, _| match item {
|
||||
MappableCommand::Typable { name, .. } => format!(":{name}").into(),
|
||||
MappableCommand::Static { name, .. } => (*name).into(),
|
||||
MappableCommand::Macro { .. } => {
|
||||
unreachable!("macros aren't included in the command palette")
|
||||
}
|
||||
}),
|
||||
ui::PickerColumn::new(
|
||||
"bindings",
|
||||
@ -4624,6 +4709,8 @@ fn keep_or_remove_selections_impl(cx: &mut Context, remove: bool) {
|
||||
selection::keep_or_remove_matches(text, doc.selection(view.id), ®ex, remove)
|
||||
{
|
||||
doc.set_selection(view.id, selection);
|
||||
} else {
|
||||
cx.editor.set_error("no selections remaining");
|
||||
}
|
||||
},
|
||||
)
|
||||
@ -5051,6 +5138,8 @@ fn jump_forward(cx: &mut Context) {
|
||||
}
|
||||
|
||||
doc.set_selection(view.id, selection);
|
||||
// Document we switch to might not have been opened in the view before
|
||||
doc.ensure_view_init(view.id);
|
||||
view.ensure_cursor_in_view_center(doc, config.scrolloff);
|
||||
};
|
||||
}
|
||||
@ -5071,6 +5160,8 @@ fn jump_backward(cx: &mut Context) {
|
||||
}
|
||||
|
||||
doc.set_selection(view.id, selection);
|
||||
// Document we switch to might not have been opened in the view before
|
||||
doc.ensure_view_init(view.id);
|
||||
view.ensure_cursor_in_view_center(doc, config.scrolloff);
|
||||
};
|
||||
}
|
||||
@ -5716,27 +5807,24 @@ async fn shell_impl_async(
|
||||
process.wait_with_output().await?
|
||||
};
|
||||
|
||||
if !output.status.success() {
|
||||
if !output.stderr.is_empty() {
|
||||
let err = String::from_utf8_lossy(&output.stderr).to_string();
|
||||
log::error!("Shell error: {}", err);
|
||||
bail!("Shell error: {}", err);
|
||||
}
|
||||
match output.status.code() {
|
||||
Some(exit_code) => bail!("Shell command failed: status {}", exit_code),
|
||||
None => bail!("Shell command failed"),
|
||||
let output = if !output.status.success() {
|
||||
if output.stderr.is_empty() {
|
||||
match output.status.code() {
|
||||
Some(exit_code) => bail!("Shell command failed: status {}", exit_code),
|
||||
None => bail!("Shell command failed"),
|
||||
}
|
||||
}
|
||||
String::from_utf8_lossy(&output.stderr)
|
||||
// Prioritize `stderr` output over `stdout`
|
||||
} else if !output.stderr.is_empty() {
|
||||
log::debug!(
|
||||
"Command printed to stderr: {}",
|
||||
String::from_utf8_lossy(&output.stderr).to_string()
|
||||
);
|
||||
}
|
||||
let stderr = String::from_utf8_lossy(&output.stderr);
|
||||
log::debug!("Command printed to stderr: {stderr}");
|
||||
stderr
|
||||
} else {
|
||||
String::from_utf8_lossy(&output.stdout)
|
||||
};
|
||||
|
||||
let str = std::str::from_utf8(&output.stdout)
|
||||
.map_err(|_| anyhow!("Process did not output valid UTF-8"))?;
|
||||
let tendril = Tendril::from(str);
|
||||
Ok(tendril)
|
||||
Ok(Tendril::from(output))
|
||||
}
|
||||
|
||||
fn shell(cx: &mut compositor::Context, cmd: &str, behavior: &ShellBehavior) {
|
||||
|
@ -34,7 +34,7 @@
|
||||
use std::{
|
||||
cmp::Ordering,
|
||||
collections::{BTreeMap, HashSet},
|
||||
fmt::Write,
|
||||
fmt::{Display, Write},
|
||||
future::Future,
|
||||
path::Path,
|
||||
};
|
||||
@ -832,13 +832,13 @@ pub enum ApplyEditErrorKind {
|
||||
// InvalidEdit,
|
||||
}
|
||||
|
||||
impl ToString for ApplyEditErrorKind {
|
||||
fn to_string(&self) -> String {
|
||||
impl Display for ApplyEditErrorKind {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
ApplyEditErrorKind::DocumentChanged => "document has changed".to_string(),
|
||||
ApplyEditErrorKind::FileNotFound => "file not found".to_string(),
|
||||
ApplyEditErrorKind::UnknownURISchema => "URI schema not supported".to_string(),
|
||||
ApplyEditErrorKind::IoError(err) => err.to_string(),
|
||||
ApplyEditErrorKind::DocumentChanged => f.write_str("document has changed"),
|
||||
ApplyEditErrorKind::FileNotFound => f.write_str("file not found"),
|
||||
ApplyEditErrorKind::UnknownURISchema => f.write_str("URI schema not supported"),
|
||||
ApplyEditErrorKind::IoError(err) => f.write_str(&format!("{err}")),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1360,7 +1360,7 @@ fn compute_inlay_hints_for_view(
|
||||
|
||||
// Most language servers will already send them sorted but ensure this is the case to
|
||||
// avoid errors on our end.
|
||||
hints.sort_unstable_by_key(|inlay_hint| inlay_hint.position);
|
||||
hints.sort_by_key(|inlay_hint| inlay_hint.position);
|
||||
|
||||
let mut padding_before_inlay_hints = Vec::new();
|
||||
let mut type_inlay_hints = Vec::new();
|
||||
|
@ -2300,7 +2300,7 @@ fn run_shell_command(
|
||||
move |editor: &mut Editor, compositor: &mut Compositor| {
|
||||
if !output.is_empty() {
|
||||
let contents = ui::Markdown::new(
|
||||
format!("```sh\n{}\n```", output),
|
||||
format!("```sh\n{}\n```", output.trim_end()),
|
||||
editor.syn_loader.clone(),
|
||||
);
|
||||
let popup = Popup::new("shell", contents).position(Some(
|
||||
@ -2308,7 +2308,7 @@ fn run_shell_command(
|
||||
));
|
||||
compositor.replace_or_push("shell", popup);
|
||||
}
|
||||
editor.set_status("Command succeeded");
|
||||
editor.set_status("Command run");
|
||||
},
|
||||
));
|
||||
Ok(call)
|
||||
@ -2498,7 +2498,7 @@ fn read(cx: &mut compositor::Context, args: &[Cow<str>], event: PromptEvent) ->
|
||||
ensure!(!args.is_empty(), "file name is expected");
|
||||
ensure!(args.len() == 1, "only the file name is expected");
|
||||
|
||||
let filename = args.get(0).unwrap();
|
||||
let filename = args.first().unwrap();
|
||||
let path = PathBuf::from(filename.to_string());
|
||||
ensure!(
|
||||
path.exists() && path.is_file(),
|
||||
|
@ -177,6 +177,19 @@ fn visit_seq<S>(self, mut seq: S) -> Result<Self::Value, S::Error>
|
||||
.map_err(serde::de::Error::custom)?,
|
||||
)
|
||||
}
|
||||
|
||||
// Prevent macro keybindings from being used in command sequences.
|
||||
// This is meant to be a temporary restriction pending a larger
|
||||
// refactor of how command sequences are executed.
|
||||
if commands
|
||||
.iter()
|
||||
.any(|cmd| matches!(cmd, MappableCommand::Macro { .. }))
|
||||
{
|
||||
return Err(serde::de::Error::custom(
|
||||
"macro keybindings may not be used in command sequences",
|
||||
));
|
||||
}
|
||||
|
||||
Ok(KeyTrie::Sequence(commands))
|
||||
}
|
||||
|
||||
@ -199,6 +212,7 @@ pub fn reverse_map(&self) -> ReverseKeymap {
|
||||
// recursively visit all nodes in keymap
|
||||
fn map_node(cmd_map: &mut ReverseKeymap, node: &KeyTrie, keys: &mut Vec<KeyEvent>) {
|
||||
match node {
|
||||
KeyTrie::MappableCommand(MappableCommand::Macro { .. }) => {}
|
||||
KeyTrie::MappableCommand(cmd) => {
|
||||
let name = cmd.name();
|
||||
if name != "no_op" {
|
||||
|
@ -117,10 +117,9 @@ async fn main_impl() -> Result<i32> {
|
||||
setup_logging(args.verbosity).context("failed to initialize logging")?;
|
||||
|
||||
// Before setting the working directory, resolve all the paths in args.files
|
||||
for (path, _) in args.files.iter_mut() {
|
||||
*path = helix_stdx::path::canonicalize(&path);
|
||||
for (path, _) in &mut args.files {
|
||||
*path = helix_stdx::path::canonicalize(&*path);
|
||||
}
|
||||
|
||||
// NOTE: Set the working directory early so the correct configuration is loaded. Be aware that
|
||||
// Application::new() depends on this logic so it must be updated if this changes.
|
||||
if let Some(path) = &args.working_directory {
|
||||
|
@ -799,21 +799,25 @@ fn render_picker(&mut self, area: Rect, surface: &mut Surface, cx: &mut Context)
|
||||
if self.columns.len() > 1 {
|
||||
let active_column = self.query.active_column(self.prompt.position());
|
||||
let header_style = cx.editor.theme.get("ui.picker.header");
|
||||
let header_column_style = cx.editor.theme.get("ui.picker.header.column");
|
||||
|
||||
table = table.header(Row::new(self.columns.iter().map(|column| {
|
||||
if column.hidden {
|
||||
Cell::default()
|
||||
} else {
|
||||
let style = if active_column.is_some_and(|name| Arc::ptr_eq(name, &column.name))
|
||||
{
|
||||
cx.editor.theme.get("ui.picker.header.active")
|
||||
table = table.header(
|
||||
Row::new(self.columns.iter().map(|column| {
|
||||
if column.hidden {
|
||||
Cell::default()
|
||||
} else {
|
||||
header_style
|
||||
};
|
||||
let style =
|
||||
if active_column.is_some_and(|name| Arc::ptr_eq(name, &column.name)) {
|
||||
cx.editor.theme.get("ui.picker.header.column.active")
|
||||
} else {
|
||||
header_column_style
|
||||
};
|
||||
|
||||
Cell::from(Span::styled(Cow::from(&*column.name), style))
|
||||
}
|
||||
})));
|
||||
Cell::from(Span::styled(Cow::from(&*column.name), style))
|
||||
}
|
||||
}))
|
||||
.style(header_style),
|
||||
);
|
||||
}
|
||||
|
||||
use tui::widgets::TableState;
|
||||
|
@ -58,11 +58,16 @@ macro_rules! finish_field {
|
||||
() => {
|
||||
let key = field.take().unwrap_or(primary_field);
|
||||
|
||||
// Trims one space from the end, enabling leading and trailing
|
||||
// spaces in search patterns, while also retaining spaces as separators
|
||||
// between column filters.
|
||||
let pat = text.strip_suffix(' ').unwrap_or(&text);
|
||||
|
||||
if let Some(pattern) = fields.get_mut(key) {
|
||||
pattern.push(' ');
|
||||
pattern.push_str(text.trim());
|
||||
pattern.push_str(pat);
|
||||
} else {
|
||||
fields.insert(key.clone(), text.trim().to_string());
|
||||
fields.insert(key.clone(), pat.to_string());
|
||||
}
|
||||
text.clear();
|
||||
};
|
||||
|
@ -21,7 +21,7 @@ helix-core = { path = "../helix-core" }
|
||||
bitflags = "2.6"
|
||||
cassowary = "0.3"
|
||||
unicode-segmentation = "1.11"
|
||||
crossterm = { version = "0.27", optional = true }
|
||||
crossterm = { version = "0.28", optional = true }
|
||||
termini = "1.0"
|
||||
serde = { version = "1", "optional" = true, features = ["derive"]}
|
||||
once_cell = "1.19"
|
||||
|
@ -8,8 +8,8 @@
|
||||
},
|
||||
execute, queue,
|
||||
style::{
|
||||
Attribute as CAttribute, Color as CColor, Print, SetAttribute, SetBackgroundColor,
|
||||
SetForegroundColor,
|
||||
Attribute as CAttribute, Color as CColor, Colors, Print, SetAttribute, SetBackgroundColor,
|
||||
SetColors, SetForegroundColor,
|
||||
},
|
||||
terminal::{self, Clear, ClearType},
|
||||
Command,
|
||||
@ -260,14 +260,12 @@ fn draw<'a, I>(&mut self, content: I) -> io::Result<()>
|
||||
diff.queue(&mut self.buffer)?;
|
||||
modifier = cell.modifier;
|
||||
}
|
||||
if cell.fg != fg {
|
||||
let color = CColor::from(cell.fg);
|
||||
queue!(self.buffer, SetForegroundColor(color))?;
|
||||
if cell.fg != fg || cell.bg != bg {
|
||||
queue!(
|
||||
self.buffer,
|
||||
SetColors(Colors::new(cell.fg.into(), cell.bg.into()))
|
||||
)?;
|
||||
fg = cell.fg;
|
||||
}
|
||||
if cell.bg != bg {
|
||||
let color = CColor::from(cell.bg);
|
||||
queue!(self.buffer, SetBackgroundColor(color))?;
|
||||
bg = cell.bg;
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
//! - A single line string where all graphemes have the same style is represented by a [`Span`].
|
||||
//! - A single line string where each grapheme may have its own style is represented by [`Spans`].
|
||||
//! - A multiple line string where each grapheme may have its own style is represented by a
|
||||
//! [`Text`].
|
||||
//! [`Text`].
|
||||
//!
|
||||
//! These types form a hierarchy: [`Spans`] is a collection of [`Span`] and each line of [`Text`]
|
||||
//! is a [`Spans`].
|
||||
|
@ -19,8 +19,8 @@ tokio = { version = "1", features = ["rt", "rt-multi-thread", "time", "sync", "p
|
||||
parking_lot = "0.12"
|
||||
arc-swap = { version = "1.7.1" }
|
||||
|
||||
gix = { version = "0.63.0", features = ["attributes", "status"], default-features = false, optional = true }
|
||||
imara-diff = "0.1.6"
|
||||
gix = { version = "0.66.0", features = ["attributes", "status"], default-features = false, optional = true }
|
||||
imara-diff = "0.1.7"
|
||||
anyhow = "1"
|
||||
|
||||
log = "0.4"
|
||||
@ -29,4 +29,4 @@ log = "0.4"
|
||||
git = ["gix"]
|
||||
|
||||
[dev-dependencies]
|
||||
tempfile = "3.10"
|
||||
tempfile = "3.12"
|
||||
|
@ -5,7 +5,7 @@
|
||||
use helix_core::Rope;
|
||||
use helix_event::RenderLockGuard;
|
||||
use imara_diff::Algorithm;
|
||||
use parking_lot::{Mutex, MutexGuard};
|
||||
use parking_lot::{RwLock, RwLockReadGuard};
|
||||
use tokio::sync::mpsc::{unbounded_channel, UnboundedSender};
|
||||
use tokio::task::JoinHandle;
|
||||
use tokio::time::Instant;
|
||||
@ -37,7 +37,7 @@ struct DiffInner {
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct DiffHandle {
|
||||
channel: UnboundedSender<Event>,
|
||||
diff: Arc<Mutex<DiffInner>>,
|
||||
diff: Arc<RwLock<DiffInner>>,
|
||||
inverted: bool,
|
||||
}
|
||||
|
||||
@ -48,7 +48,7 @@ pub fn new(diff_base: Rope, doc: Rope) -> DiffHandle {
|
||||
|
||||
fn new_with_handle(diff_base: Rope, doc: Rope) -> (DiffHandle, JoinHandle<()>) {
|
||||
let (sender, receiver) = unbounded_channel();
|
||||
let diff: Arc<Mutex<DiffInner>> = Arc::default();
|
||||
let diff: Arc<RwLock<DiffInner>> = Arc::default();
|
||||
let worker = DiffWorker {
|
||||
channel: receiver,
|
||||
diff: diff.clone(),
|
||||
@ -70,7 +70,7 @@ pub fn invert(&mut self) {
|
||||
|
||||
pub fn load(&self) -> Diff {
|
||||
Diff {
|
||||
diff: self.diff.lock(),
|
||||
diff: self.diff.read(),
|
||||
inverted: self.inverted,
|
||||
}
|
||||
}
|
||||
@ -164,7 +164,7 @@ pub fn is_pure_removal(&self) -> bool {
|
||||
/// non-overlapping order
|
||||
#[derive(Debug)]
|
||||
pub struct Diff<'a> {
|
||||
diff: MutexGuard<'a, DiffInner>,
|
||||
diff: RwLockReadGuard<'a, DiffInner>,
|
||||
inverted: bool,
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
use helix_core::{Rope, RopeSlice};
|
||||
use imara_diff::intern::InternedInput;
|
||||
use parking_lot::Mutex;
|
||||
use parking_lot::RwLock;
|
||||
use tokio::sync::mpsc::UnboundedReceiver;
|
||||
use tokio::sync::Notify;
|
||||
use tokio::time::{timeout, timeout_at, Duration};
|
||||
@ -21,7 +21,7 @@
|
||||
|
||||
pub(super) struct DiffWorker {
|
||||
pub channel: UnboundedReceiver<Event>,
|
||||
pub diff: Arc<Mutex<DiffInner>>,
|
||||
pub diff: Arc<RwLock<DiffInner>>,
|
||||
pub new_hunks: Vec<Hunk>,
|
||||
pub diff_finished_notify: Arc<Notify>,
|
||||
}
|
||||
@ -73,7 +73,7 @@ pub async fn run(mut self, diff_base: Rope, doc: Rope) {
|
||||
/// `self.new_hunks` is always empty after this function runs.
|
||||
/// To improve performance this function tries to reuse the allocation of the old diff previously stored in `self.line_diffs`
|
||||
fn apply_hunks(&mut self, diff_base: Rope, doc: Rope) {
|
||||
let mut diff = self.diff.lock();
|
||||
let mut diff = self.diff.write();
|
||||
diff.diff_base = diff_base;
|
||||
diff.doc = doc;
|
||||
swap(&mut diff.hunks, &mut self.new_hunks);
|
||||
|
@ -12,7 +12,7 @@ async fn into_diff(self, handle: JoinHandle<()>) -> Vec<Hunk> {
|
||||
// dropping the channel terminates the task
|
||||
drop(self.channel);
|
||||
handle.await.unwrap();
|
||||
let diff = diff.lock();
|
||||
let diff = diff.read();
|
||||
Vec::clone(&diff.hunks)
|
||||
}
|
||||
}
|
||||
|
@ -26,9 +26,9 @@ helix-vcs = { path = "../helix-vcs" }
|
||||
|
||||
bitflags = "2.6"
|
||||
anyhow = "1"
|
||||
crossterm = { version = "0.27", optional = true }
|
||||
crossterm = { version = "0.28", optional = true }
|
||||
|
||||
tempfile = "3.9"
|
||||
tempfile = "3.12"
|
||||
|
||||
# Conversion traits
|
||||
once_cell = "1.19"
|
||||
|
@ -1080,22 +1080,21 @@ pub fn detect_indent_and_line_ending(&mut self) {
|
||||
}
|
||||
|
||||
pub fn pickup_last_saved_time(&mut self) {
|
||||
self.last_saved_time = match self.path.as_mut().unwrap().metadata() {
|
||||
Ok(metadata) => match metadata.modified() {
|
||||
Ok(mtime) => mtime,
|
||||
Err(_) => {
|
||||
log::error!(
|
||||
"Use a system time instead of fs' mtime not supported on this platform"
|
||||
);
|
||||
self.last_saved_time = match self.path() {
|
||||
Some(path) => match path.metadata() {
|
||||
Ok(metadata) => match metadata.modified() {
|
||||
Ok(mtime) => mtime,
|
||||
Err(err) => {
|
||||
log::debug!("Could not fetch file system's mtime, falling back to current system time: {}", err);
|
||||
SystemTime::now()
|
||||
}
|
||||
},
|
||||
Err(err) => {
|
||||
log::debug!("Could not fetch file system's mtime, falling back to current system time: {}", err);
|
||||
SystemTime::now()
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
log::error!(
|
||||
"Use a system time instead of fs' mtime: failed to file's metadata: {e}"
|
||||
);
|
||||
SystemTime::now()
|
||||
}
|
||||
None => SystemTime::now(),
|
||||
};
|
||||
}
|
||||
|
||||
@ -1246,7 +1245,7 @@ pub fn reset_selection(&mut self, view_id: ViewId) {
|
||||
/// Initializes a new selection and view_data for the given view
|
||||
/// if it does not already have them.
|
||||
pub fn ensure_view_init(&mut self, view_id: ViewId) {
|
||||
if self.selections.get(&view_id).is_none() {
|
||||
if !self.selections.contains_key(&view_id) {
|
||||
self.reset_selection(view_id);
|
||||
}
|
||||
|
||||
@ -1921,12 +1920,15 @@ pub fn lsp_diagnostic_to_diagnostic(
|
||||
return None;
|
||||
};
|
||||
|
||||
let severity = diagnostic.severity.map(|severity| match severity {
|
||||
lsp::DiagnosticSeverity::ERROR => Error,
|
||||
lsp::DiagnosticSeverity::WARNING => Warning,
|
||||
lsp::DiagnosticSeverity::INFORMATION => Info,
|
||||
lsp::DiagnosticSeverity::HINT => Hint,
|
||||
severity => unreachable!("unrecognized diagnostic severity: {:?}", severity),
|
||||
let severity = diagnostic.severity.and_then(|severity| match severity {
|
||||
lsp::DiagnosticSeverity::ERROR => Some(Error),
|
||||
lsp::DiagnosticSeverity::WARNING => Some(Warning),
|
||||
lsp::DiagnosticSeverity::INFORMATION => Some(Info),
|
||||
lsp::DiagnosticSeverity::HINT => Some(Hint),
|
||||
severity => {
|
||||
log::error!("unrecognized diagnostic severity: {:?}", severity);
|
||||
None
|
||||
}
|
||||
});
|
||||
|
||||
if let Some(lang_conf) = language_config {
|
||||
|
@ -1376,6 +1376,11 @@ pub fn move_path(&mut self, old_path: &Path, new_path: &Path) -> io::Result<()>
|
||||
}
|
||||
let is_dir = new_path.is_dir();
|
||||
for ls in self.language_servers.iter_clients() {
|
||||
// A new language server might have been started in `set_doc_path` and won't
|
||||
// be initialized yet. Skip the `did_rename` notification for this server.
|
||||
if !ls.is_initialized() {
|
||||
continue;
|
||||
}
|
||||
if let Some(notification) = ls.did_rename(old_path, &new_path, is_dir) {
|
||||
tokio::spawn(notification);
|
||||
};
|
||||
|
@ -37,7 +37,7 @@ pub async fn select_thread_id(editor: &mut Editor, thread_id: ThreadId, force: b
|
||||
debugger.thread_id = Some(thread_id);
|
||||
fetch_stack_trace(debugger, thread_id).await;
|
||||
|
||||
let frame = debugger.stack_frames[&thread_id].get(0).cloned();
|
||||
let frame = debugger.stack_frames[&thread_id].first().cloned();
|
||||
if let Some(frame) = &frame {
|
||||
jump_to_stack_frame(editor, frame);
|
||||
}
|
||||
|
@ -1,3 +1,5 @@
|
||||
use std::fmt::Display;
|
||||
|
||||
use crate::editor::Action;
|
||||
use crate::Editor;
|
||||
use crate::{DocumentId, ViewId};
|
||||
@ -73,13 +75,13 @@ fn from(err: helix_core::uri::UrlConversionError) -> Self {
|
||||
}
|
||||
}
|
||||
|
||||
impl ToString for ApplyEditErrorKind {
|
||||
fn to_string(&self) -> String {
|
||||
impl Display for ApplyEditErrorKind {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
ApplyEditErrorKind::DocumentChanged => "document has changed".to_string(),
|
||||
ApplyEditErrorKind::FileNotFound => "file not found".to_string(),
|
||||
ApplyEditErrorKind::InvalidUrl(err) => err.to_string(),
|
||||
ApplyEditErrorKind::IoError(err) => err.to_string(),
|
||||
ApplyEditErrorKind::DocumentChanged => f.write_str("document has changed"),
|
||||
ApplyEditErrorKind::FileNotFound => f.write_str("file not found"),
|
||||
ApplyEditErrorKind::InvalidUrl(err) => f.write_str(&format!("{err}")),
|
||||
ApplyEditErrorKind::IoError(err) => f.write_str(&format!("{err}")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -44,6 +44,7 @@ haskell-language-server = { command = "haskell-language-server-wrapper", args =
|
||||
idris2-lsp = { command = "idris2-lsp" }
|
||||
intelephense = { command = "intelephense", args = ["--stdio"] }
|
||||
jdtls = { command = "jdtls" }
|
||||
jq-lsp = { command = "jq-lsp" }
|
||||
jsonnet-language-server = { command = "jsonnet-language-server", args= ["-t", "--lint"] }
|
||||
julia = { command = "julia", timeout = 60, args = [ "--startup-file=no", "--history-file=no", "--quiet", "-e", "using LanguageServer; runserver()", ] }
|
||||
koka = { command = "koka", args = ["--language-server", "--lsstdio"] }
|
||||
@ -54,11 +55,13 @@ markdoc-ls = { command = "markdoc-ls", args = ["--stdio"] }
|
||||
markdown-oxide = { command = "markdown-oxide" }
|
||||
marksman = { command = "marksman", args = ["server"] }
|
||||
metals = { command = "metals", config = { "isHttpEnabled" = true, metals = { inlayHints = { typeParameters = {enable = true} , hintsInPatternMatch = {enable = true} } } } }
|
||||
mesonlsp = { command = "mesonlsp", args = ["--lsp"] }
|
||||
mint = { command = "mint", args = ["ls"] }
|
||||
mojo-lsp = { command = "mojo-lsp-server" }
|
||||
nil = { command = "nil" }
|
||||
nimlangserver = { command = "nimlangserver" }
|
||||
nimlsp = { command = "nimlsp" }
|
||||
nixd = { command = "nixd" }
|
||||
nls = { command = "nls" }
|
||||
nu-lsp = { command = "nu", args = [ "--lsp" ] }
|
||||
ocamllsp = { command = "ocamllsp" }
|
||||
@ -93,6 +96,7 @@ taplo = { command = "taplo", args = ["lsp", "stdio"] }
|
||||
templ = { command = "templ", args = ["lsp"] }
|
||||
terraform-ls = { command = "terraform-ls", args = ["serve"] }
|
||||
texlab = { command = "texlab" }
|
||||
typespec = { command = "tsp-server", args = ["--stdio"] }
|
||||
vala-language-server = { command = "vala-language-server" }
|
||||
vhdl_ls = { command = "vhdl_ls", args = [] }
|
||||
vlang-language-server = { command = "v-analyzer" }
|
||||
@ -766,6 +770,23 @@ indent = { tab-width = 2, unit = " " }
|
||||
name = "typescript"
|
||||
source = { git = "https://github.com/tree-sitter/tree-sitter-typescript", rev = "b1bf4825d9eaa0f3bdeb1e52f099533328acfbdf", subpath = "typescript" }
|
||||
|
||||
[[language]]
|
||||
name = "typespec"
|
||||
scope = "source.typespec"
|
||||
injection-regex = "(tsp|typespec)"
|
||||
language-id = "typespec"
|
||||
file-types = ["tsp"]
|
||||
roots = ["tspconfig.yaml"]
|
||||
auto-format = true
|
||||
comment-token = "//"
|
||||
block-comment-tokens = { start = "/*", end = "*/" }
|
||||
language-servers = ["typespec"]
|
||||
indent = { tab-width = 2, unit = " " }
|
||||
|
||||
[[grammar]]
|
||||
name = "typespec"
|
||||
source = { git = "https://github.com/happenslol/tree-sitter-typespec", rev = "0ee05546d73d8eb64635ed8125de6f35c77759fe" }
|
||||
|
||||
[[language]]
|
||||
name = "tsx"
|
||||
scope = "source.tsx"
|
||||
@ -813,7 +834,7 @@ source = { git = "https://github.com/serenadeai/tree-sitter-scss", rev = "c478c6
|
||||
name = "html"
|
||||
scope = "text.html.basic"
|
||||
injection-regex = "html"
|
||||
file-types = ["html", "htm", "shtml", "xhtml", "xht", "jsp", "asp", "aspx", "jshtm", "volt", "rhtml"]
|
||||
file-types = ["html", "htm", "shtml", "xhtml", "xht", "jsp", "asp", "aspx", "jshtm", "volt", "rhtml", "cshtml"]
|
||||
block-comment-tokens = { start = "<!--", end = "-->" }
|
||||
language-servers = [ "vscode-html-language-server" ]
|
||||
auto-format = true
|
||||
@ -866,7 +887,7 @@ injection-regex = "nix"
|
||||
file-types = ["nix"]
|
||||
shebangs = []
|
||||
comment-token = "#"
|
||||
language-servers = [ "nil" ]
|
||||
language-servers = [ "nil", "nixd" ]
|
||||
indent = { tab-width = 2, unit = " " }
|
||||
|
||||
[[grammar]]
|
||||
@ -948,6 +969,8 @@ file-types = [
|
||||
"tcshrc",
|
||||
"bashrc_Apple_Terminal",
|
||||
"zshrc_Apple_Terminal",
|
||||
{ glob = "i3/config" },
|
||||
{ glob = "sway/config" },
|
||||
{ glob = "tmux.conf" },
|
||||
{ glob = ".bash_history" },
|
||||
{ glob = ".bash_login" },
|
||||
@ -1855,7 +1878,7 @@ auto-format = true
|
||||
|
||||
[[grammar]]
|
||||
name = "gleam"
|
||||
source = { git = "https://github.com/gleam-lang/tree-sitter-gleam", rev = "bcf9c45b56cbe46e9dac5eee0aee75df270000ac" }
|
||||
source = { git = "https://github.com/gleam-lang/tree-sitter-gleam", rev = "426e67087fd62be5f4533581b5916b2cf010fb5b" }
|
||||
|
||||
[[language]]
|
||||
name = "ron"
|
||||
@ -1995,12 +2018,12 @@ shebangs = []
|
||||
roots = ["project.godot"]
|
||||
auto-format = true
|
||||
formatter = { command = "gdformat", args = ["-"] }
|
||||
comment-token = "#"
|
||||
comment-tokens = ["#", "##"]
|
||||
indent = { tab-width = 4, unit = "\t" }
|
||||
|
||||
[[grammar]]
|
||||
name = "gdscript"
|
||||
source = { git = "https://github.com/PrestonKnopp/tree-sitter-gdscript", rev = "a4b57cc3bcbfc24550e858159647e9238e7ad1ac" }
|
||||
source = { git = "https://github.com/PrestonKnopp/tree-sitter-gdscript", rev = "1f1e782fe2600f50ae57b53876505b8282388d77" }
|
||||
|
||||
[[language]]
|
||||
name = "godot-resource"
|
||||
@ -2015,7 +2038,7 @@ indent = { tab-width = 4, unit = "\t" }
|
||||
|
||||
[[grammar]]
|
||||
name = "godot-resource"
|
||||
source = { git = "https://github.com/PrestonKnopp/tree-sitter-godot-resource", rev = "b6ef0768711086a86b3297056f9ffb5cc1d77b4a" }
|
||||
source = { git = "https://github.com/PrestonKnopp/tree-sitter-godot-resource", rev = "2ffb90de47417018651fc3b970e5f6b67214dc9d" }
|
||||
|
||||
[[language]]
|
||||
name = "nu"
|
||||
@ -2143,6 +2166,7 @@ injection-regex = "meson"
|
||||
file-types = [{ glob = "meson.build" }, { glob = "meson.options" }, { glob = "meson_options.txt" }]
|
||||
comment-token = "#"
|
||||
indent = { tab-width = 2, unit = " " }
|
||||
language-servers = ["mesonlsp"]
|
||||
|
||||
[[grammar]]
|
||||
name = "meson"
|
||||
@ -3082,7 +3106,7 @@ indent = { tab-width = 4, unit = " " }
|
||||
|
||||
[[grammar]]
|
||||
name = "just"
|
||||
source = { git = "https://github.com/IndianBoy42/tree-sitter-just", rev = "379fbe36d1e441bc9414ea050ad0c85c9d6935ea" }
|
||||
source = { git = "https://github.com/poliorcetics/tree-sitter-just", rev = "f58a8fd869035ac4653081401e6c2030251240ab" }
|
||||
|
||||
[[language]]
|
||||
name = "gn"
|
||||
@ -3139,7 +3163,7 @@ language-servers = ["fsharp-ls"]
|
||||
|
||||
[[grammar]]
|
||||
name = "fsharp"
|
||||
source = { git = "https://github.com/kaashyapan/tree-sitter-fsharp", rev = "18da392fd9bd5e79f357abcce13f61f3a15e3951" }
|
||||
source = { git = "https://github.com/ionide/tree-sitter-fsharp", rev = "996ea9982bd4e490029f84682016b6793940113b" }
|
||||
|
||||
[[language]]
|
||||
name = "t32"
|
||||
@ -3216,6 +3240,19 @@ text-width = 72
|
||||
name = "jjdescription"
|
||||
source = { git = "https://github.com/kareigu/tree-sitter-jjdescription", rev = "2ddec6cad07b366aee276a608e1daa2c29d3caf2" }
|
||||
|
||||
[[language]]
|
||||
name = "jq"
|
||||
scope = "source.jq"
|
||||
injection-regex = "jq"
|
||||
file-types = ["jq"]
|
||||
comment-token = "#"
|
||||
language-servers = ["jq-lsp"]
|
||||
indent = { tab-width = 2, unit = " " }
|
||||
|
||||
[[grammar]]
|
||||
name = "jq"
|
||||
source = { git = "https://github.com/flurie/tree-sitter-jq", rev = "13990f530e8e6709b7978503da9bc8701d366791" }
|
||||
|
||||
[[grammar]]
|
||||
name = "wren"
|
||||
source = { git = "https://git.sr.ht/~jummit/tree-sitter-wren", rev = "6748694be32f11e7ec6b5faeb1b48ca6156d4e06" }
|
||||
@ -3490,7 +3527,7 @@ name = "tcl"
|
||||
scope = "source.tcl"
|
||||
injection-regex = "tcl"
|
||||
file-types = [ "tcl" ]
|
||||
shebangs = [ "tclish", "jimsh", "wish" ]
|
||||
shebangs = [ "tclsh", "tclish", "jimsh", "wish" ]
|
||||
comment-token = '#'
|
||||
|
||||
[[grammar]]
|
||||
@ -3726,3 +3763,26 @@ grammar = "typescript"
|
||||
"{" = "}"
|
||||
"(" = ")"
|
||||
'"' = '"'
|
||||
|
||||
[[language]]
|
||||
name = "gherkin"
|
||||
scope = "source.feature"
|
||||
file-types = ["feature"]
|
||||
comment-token = "#"
|
||||
indent = { tab-width = 2, unit = " " }
|
||||
|
||||
[[grammar]]
|
||||
name = "gherkin"
|
||||
source = { git = "https://github.com/SamyAB/tree-sitter-gherkin", rev = "43873ee8de16476635b48d52c46f5b6407cb5c09" }
|
||||
|
||||
[[language]]
|
||||
name = "thrift"
|
||||
scope = "source.thrift"
|
||||
file-types = ["thrift"]
|
||||
comment-token = "//"
|
||||
block-comment-tokens = { start = "/*", end = "*/" }
|
||||
indent = { tab-width = 2, unit = " " }
|
||||
|
||||
[[grammar]]
|
||||
name = "thrift"
|
||||
source = { git = "https://github.com/tree-sitter-grammars/tree-sitter-thrift" , rev = "68fd0d80943a828d9e6f49c58a74be1e9ca142cf" }
|
1
runtime/queries/docker-compose/textobjects.scm
Normal file
1
runtime/queries/docker-compose/textobjects.scm
Normal file
@ -0,0 +1 @@
|
||||
; inherits: yaml
|
4
runtime/queries/dockerfile/textobjects.scm
Normal file
4
runtime/queries/dockerfile/textobjects.scm
Normal file
@ -0,0 +1,4 @@
|
||||
(comment) @comment.inside
|
||||
|
||||
(comment)+ @comment.around
|
||||
|
6
runtime/queries/env/textobjects.scm
vendored
Normal file
6
runtime/queries/env/textobjects.scm
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
(comment) @comment.inside
|
||||
|
||||
(comment)+ @comment.around
|
||||
|
||||
(variable_assignment
|
||||
(_) @entry.inside) @entry.around
|
@ -1,16 +1,176 @@
|
||||
;; ----------------------------------------------------------------------------
|
||||
;; Literals and comments
|
||||
|
||||
[
|
||||
(line_comment)
|
||||
(block_comment)
|
||||
(block_comment_content)
|
||||
] @comment
|
||||
(line_comment) @comment.line
|
||||
|
||||
(block_comment) @comment.block
|
||||
|
||||
(xml_doc) @comment.block.documentation
|
||||
|
||||
(const
|
||||
[
|
||||
(_) @constant
|
||||
(unit) @constant.builtin
|
||||
])
|
||||
|
||||
(primary_constr_args (_) @variable.parameter)
|
||||
|
||||
((identifier_pattern (long_identifier (identifier) @special))
|
||||
(#match? @special "^\_.*"))
|
||||
|
||||
((long_identifier
|
||||
(identifier)+
|
||||
.
|
||||
(identifier) @variable.other.member))
|
||||
|
||||
;; ----------------------------------------------------------------------------
|
||||
;; Punctuation
|
||||
|
||||
(wildcard_pattern) @string.special
|
||||
|
||||
(type_name type_name: (_) @type)
|
||||
|
||||
[
|
||||
(type)
|
||||
(atomic_type)
|
||||
] @type
|
||||
|
||||
(member_signature
|
||||
.
|
||||
(identifier) @function.method
|
||||
(curried_spec
|
||||
(arguments_spec
|
||||
"*"* @operator
|
||||
(argument_spec
|
||||
(argument_name_spec
|
||||
"?"? @special
|
||||
name: (_) @variable.parameter)))))
|
||||
|
||||
(union_type_case) @constant
|
||||
|
||||
(rules
|
||||
(rule
|
||||
pattern: (_) @constant
|
||||
block: (_)))
|
||||
|
||||
(identifier_pattern
|
||||
.
|
||||
(_) @constant
|
||||
.
|
||||
(_) @variable)
|
||||
|
||||
(fsi_directive_decl . (string) @namespace)
|
||||
|
||||
(import_decl . (_) @namespace)
|
||||
(named_module
|
||||
name: (_) @namespace)
|
||||
(namespace
|
||||
name: (_) @namespace)
|
||||
(module_defn
|
||||
.
|
||||
(_) @namespace)
|
||||
|
||||
(ce_expression
|
||||
.
|
||||
(_) @function.macro)
|
||||
|
||||
(field_initializer
|
||||
field: (_) @variable.other.member)
|
||||
|
||||
(record_fields
|
||||
(record_field
|
||||
.
|
||||
(identifier) @variable.other.member))
|
||||
|
||||
(dot_expression
|
||||
base: (_) @namespace
|
||||
field: (_) @variable.other.member)
|
||||
|
||||
(value_declaration_left . (_) @variable)
|
||||
|
||||
(function_declaration_left
|
||||
. (_) @function
|
||||
[
|
||||
(argument_patterns)
|
||||
(argument_patterns (long_identifier (identifier)))
|
||||
] @variable.parameter)
|
||||
|
||||
(member_defn
|
||||
(method_or_prop_defn
|
||||
[
|
||||
(property_or_ident) @function
|
||||
(property_or_ident
|
||||
instance: (identifier) @variable.builtin
|
||||
method: (identifier) @function.method)
|
||||
]
|
||||
args: (_)* @variable.parameter))
|
||||
|
||||
(application_expression
|
||||
.
|
||||
[
|
||||
(long_identifier_or_op [
|
||||
(long_identifier (identifier)* (identifier) @function)
|
||||
(identifier) @function
|
||||
])
|
||||
(typed_expression . (long_identifier_or_op (long_identifier (identifier)* . (identifier) @function.call)))
|
||||
(dot_expression base: (_) @variable.other.member field: (_) @function)
|
||||
] @function)
|
||||
|
||||
((infix_expression
|
||||
.
|
||||
(_)
|
||||
.
|
||||
(infix_op) @operator
|
||||
.
|
||||
(_) @function
|
||||
)
|
||||
(#eq? @operator "|>")
|
||||
)
|
||||
|
||||
((infix_expression
|
||||
.
|
||||
(_) @function
|
||||
.
|
||||
(infix_op) @operator
|
||||
.
|
||||
(_)
|
||||
)
|
||||
(#eq? @operator "<|")
|
||||
)
|
||||
|
||||
[
|
||||
(xint)
|
||||
(int)
|
||||
(int16)
|
||||
(uint16)
|
||||
(int32)
|
||||
(uint32)
|
||||
(int64)
|
||||
(uint64)
|
||||
(nativeint)
|
||||
(unativeint)
|
||||
] @constant.numeric.integer
|
||||
|
||||
[
|
||||
(ieee32)
|
||||
(ieee64)
|
||||
(float)
|
||||
(decimal)
|
||||
] @constant.numeric.float
|
||||
|
||||
(bool) @constant.builtin.boolean
|
||||
|
||||
([
|
||||
(string)
|
||||
(triple_quoted_string)
|
||||
(verbatim_string)
|
||||
(char)
|
||||
] @string)
|
||||
|
||||
(compiler_directive_decl) @keyword.directive
|
||||
|
||||
(attribute) @attribute
|
||||
|
||||
[
|
||||
"("
|
||||
")"
|
||||
@ -20,10 +180,18 @@
|
||||
"]"
|
||||
"[|"
|
||||
"|]"
|
||||
"{|"
|
||||
"|}"
|
||||
"[<"
|
||||
">]"
|
||||
] @punctuation.bracket
|
||||
|
||||
(format_string_eval
|
||||
[
|
||||
"{"
|
||||
"}"
|
||||
] @punctuation.special)
|
||||
|
||||
[
|
||||
","
|
||||
";"
|
||||
@ -36,15 +204,16 @@
|
||||
"<"
|
||||
"-"
|
||||
"~"
|
||||
"->"
|
||||
"<-"
|
||||
"&&"
|
||||
"||"
|
||||
":>"
|
||||
":?>"
|
||||
(infix_op)
|
||||
(prefix_op)
|
||||
(symbolic_op)
|
||||
] @operator
|
||||
|
||||
|
||||
|
||||
(attribute) @attribute
|
||||
|
||||
[
|
||||
"if"
|
||||
"then"
|
||||
@ -53,22 +222,29 @@
|
||||
"when"
|
||||
"match"
|
||||
"match!"
|
||||
] @keyword.control.conditional
|
||||
|
||||
[
|
||||
"and"
|
||||
"or"
|
||||
"&&"
|
||||
"||"
|
||||
"then"
|
||||
] @keyword.control.conditional
|
||||
"not"
|
||||
"upcast"
|
||||
"downcast"
|
||||
] @keyword.operator
|
||||
|
||||
[
|
||||
"return"
|
||||
"return!"
|
||||
"yield"
|
||||
"yield!"
|
||||
] @keyword.control.return
|
||||
|
||||
[
|
||||
"for"
|
||||
"while"
|
||||
] @keyword.control.return
|
||||
"downto"
|
||||
"to"
|
||||
] @keyword.control.repeat
|
||||
|
||||
|
||||
[
|
||||
@ -82,115 +258,93 @@
|
||||
"delegate"
|
||||
"static"
|
||||
"inline"
|
||||
"internal"
|
||||
"mutable"
|
||||
"override"
|
||||
"private"
|
||||
"public"
|
||||
"rec"
|
||||
"global"
|
||||
(access_modifier)
|
||||
] @keyword.storage.modifier
|
||||
|
||||
[
|
||||
"enum"
|
||||
"let"
|
||||
"let!"
|
||||
"use"
|
||||
"use!"
|
||||
"member"
|
||||
"module"
|
||||
"namespace"
|
||||
] @keyword.function
|
||||
|
||||
[
|
||||
"enum"
|
||||
"type"
|
||||
] @keyword.storage
|
||||
"inherit"
|
||||
"interface"
|
||||
] @keyword.storage.type
|
||||
|
||||
(try_expression
|
||||
[
|
||||
"try"
|
||||
"with"
|
||||
"finally"
|
||||
] @keyword.control.exception)
|
||||
|
||||
((identifier) @keyword.control.exception
|
||||
(#any-of? @keyword.control.exception "failwith" "failwithf" "raise" "reraise"))
|
||||
|
||||
[
|
||||
"as"
|
||||
"assert"
|
||||
"begin"
|
||||
"end"
|
||||
"done"
|
||||
"default"
|
||||
"in"
|
||||
"do"
|
||||
"do!"
|
||||
"done"
|
||||
"downcast"
|
||||
"downto"
|
||||
"end"
|
||||
"event"
|
||||
"field"
|
||||
"finally"
|
||||
"fun"
|
||||
"function"
|
||||
"get"
|
||||
"global"
|
||||
"inherit"
|
||||
"interface"
|
||||
"set"
|
||||
"lazy"
|
||||
"new"
|
||||
"not"
|
||||
"null"
|
||||
"of"
|
||||
"param"
|
||||
"property"
|
||||
"set"
|
||||
"struct"
|
||||
"try"
|
||||
"upcast"
|
||||
"use"
|
||||
"use!"
|
||||
"val"
|
||||
"module"
|
||||
"namespace"
|
||||
"with"
|
||||
"yield"
|
||||
"yield!"
|
||||
] @keyword
|
||||
|
||||
[
|
||||
"true"
|
||||
"false"
|
||||
"unit"
|
||||
] @constant.builtin
|
||||
"null"
|
||||
] @constant.builtin
|
||||
|
||||
[
|
||||
(type)
|
||||
(const)
|
||||
] @constant
|
||||
(match_expression "with" @keyword.control.conditional)
|
||||
|
||||
[
|
||||
(union_type_case)
|
||||
(rules (rule (identifier_pattern)))
|
||||
] @type.enum
|
||||
((type
|
||||
(long_identifier (identifier) @type.builtin))
|
||||
(#any-of? @type.builtin "bool" "byte" "sbyte" "int16" "uint16" "int" "uint" "int64" "uint64" "nativeint" "unativeint" "decimal" "float" "double" "float32" "single" "char" "string" "unit"))
|
||||
|
||||
(fsi_directive_decl (string) @namespace)
|
||||
(preproc_if
|
||||
[
|
||||
"#if" @keyword.directive
|
||||
"#endif" @keyword.directive
|
||||
]
|
||||
condition: (_)? @keyword.directive)
|
||||
|
||||
[
|
||||
(import_decl (long_identifier))
|
||||
(named_module (long_identifier))
|
||||
(namespace (long_identifier))
|
||||
(named_module
|
||||
name: (long_identifier) )
|
||||
(namespace
|
||||
name: (long_identifier) )
|
||||
] @namespace
|
||||
(preproc_else
|
||||
"#else" @keyword.directive)
|
||||
|
||||
((long_identifier
|
||||
(identifier)+ @namespace
|
||||
.
|
||||
(identifier)))
|
||||
|
||||
(dot_expression
|
||||
base: (long_identifier_or_op) @variable.other.member
|
||||
field: (long_identifier_or_op) @function)
|
||||
|
||||
[
|
||||
;;(value_declaration_left (identifier_pattern) )
|
||||
(function_declaration_left (identifier) )
|
||||
(call_expression (long_identifier_or_op (long_identifier)))
|
||||
;;(application_expression (long_identifier_or_op (long_identifier)))
|
||||
] @function
|
||||
|
||||
[
|
||||
(string)
|
||||
(triple_quoted_string)
|
||||
] @string
|
||||
|
||||
[
|
||||
(int)
|
||||
(int16)
|
||||
(int32)
|
||||
(int64)
|
||||
(float)
|
||||
(decimal)
|
||||
] @constant.numeric
|
||||
|
||||
(long_identifier_or_op
|
||||
(op_identifier) @operator)
|
||||
|
||||
((identifier) @namespace
|
||||
(#any-of? @namespace "Array" "Async" "Directory" "File" "List" "Option" "Path" "Map" "Set" "Lazy" "Seq" "Task" "String" "Result" ))
|
||||
|
8
runtime/queries/fsharp/injections.scm
Normal file
8
runtime/queries/fsharp/injections.scm
Normal file
@ -0,0 +1,8 @@
|
||||
([
|
||||
(line_comment)
|
||||
(block_comment_content)
|
||||
] @injection.content
|
||||
(#set! injection.language "comment"))
|
||||
|
||||
((xml_doc (xml_doc_content) @injection.content)
|
||||
(#set! injection.language "xml"))
|
@ -1,25 +1,32 @@
|
||||
; Scopes
|
||||
;-------
|
||||
(identifier) @local.reference
|
||||
|
||||
[
|
||||
(ce_expression)
|
||||
(module_defn)
|
||||
(for_expression)
|
||||
(do_expression)
|
||||
(fun_expression)
|
||||
(function_expression)
|
||||
(try_expression)
|
||||
(match_expression)
|
||||
(elif_expression)
|
||||
(if_expression)
|
||||
(namespace)
|
||||
(named_module)
|
||||
(function_or_value_defn)
|
||||
] @local.scope
|
||||
|
||||
; Definitions
|
||||
;------------
|
||||
(value_declaration_left
|
||||
.
|
||||
[
|
||||
(_ (identifier) @local.definition)
|
||||
(_ (_ (identifier) @local.definition))
|
||||
(_ (_ (_ (identifier) @local.definition)))
|
||||
(_ (_ (_ (_ (identifier) @local.definition))))
|
||||
(_ (_ (_ (_ (_ (identifier) @local.definition)))))
|
||||
(_ (_ (_ (_ (_ (_ (identifier) @local.definition))))))
|
||||
])
|
||||
|
||||
(function_or_value_defn) @local.definition
|
||||
|
||||
; References
|
||||
;-----------
|
||||
|
||||
(identifier) @local.reference
|
||||
(function_declaration_left
|
||||
.
|
||||
((_) @local.definition)
|
||||
((argument_patterns
|
||||
[
|
||||
(_ (identifier) @local.definition)
|
||||
(_ (_ (identifier) @local.definition))
|
||||
(_ (_ (_ (identifier) @local.definition)))
|
||||
(_ (_ (_ (_ (identifier) @local.definition))))
|
||||
(_ (_ (_ (_ (_ (identifier) @local.definition)))))
|
||||
(_ (_ (_ (_ (_ (_ (identifier) @local.definition))))))
|
||||
])
|
||||
))
|
||||
|
@ -14,6 +14,7 @@
|
||||
(attribute_call (identifier) @function)
|
||||
(base_call (identifier) @function)
|
||||
(call (identifier) @function)
|
||||
(lambda (name) @function)
|
||||
|
||||
; Function definitions
|
||||
|
||||
@ -88,6 +89,7 @@
|
||||
"<<"
|
||||
">>"
|
||||
":="
|
||||
":"
|
||||
] @operator
|
||||
|
||||
(annotation (identifier) @keyword.storage.modifier)
|
||||
@ -97,6 +99,7 @@
|
||||
"else"
|
||||
"elif"
|
||||
"match"
|
||||
"when"
|
||||
] @keyword.control.conditional
|
||||
|
||||
[
|
||||
|
@ -6,6 +6,7 @@
|
||||
(pattern_section)
|
||||
|
||||
(function_definition)
|
||||
(lambda)
|
||||
(constructor_definition)
|
||||
(class_definition)
|
||||
(enum_definition)
|
||||
|
@ -5,6 +5,8 @@
|
||||
(function_definition
|
||||
(body) @function.inside) @function.around
|
||||
|
||||
(lambda (body) @function.inside) @function.around
|
||||
|
||||
(parameters
|
||||
[
|
||||
(identifier)
|
||||
@ -15,5 +17,12 @@
|
||||
|
||||
(arguments (_expression) @parameter.inside @parameter.around)
|
||||
|
||||
[
|
||||
(const_statement)
|
||||
(variable_statement)
|
||||
(pair)
|
||||
(enumerator)
|
||||
] @entry.around
|
||||
|
||||
(comment) @comment.inside
|
||||
(comment)+ @comment.around
|
||||
|
17
runtime/queries/gherkin/highlights.scm
Normal file
17
runtime/queries/gherkin/highlights.scm
Normal file
@ -0,0 +1,17 @@
|
||||
[
|
||||
(feature_keyword)
|
||||
(rule_keyword)
|
||||
(background_keyword)
|
||||
(scenario_keyword)
|
||||
(given_keyword)
|
||||
(when_keyword)
|
||||
(then_keyword)
|
||||
(and_keyword)
|
||||
(but_keyword)
|
||||
(asterisk_keyword)
|
||||
] @keyword
|
||||
|
||||
(tag) @function
|
||||
(doc_string) @string
|
||||
(data_table) @special
|
||||
(comment) @comment
|
6
runtime/queries/git-config/textobjects.scm
Normal file
6
runtime/queries/git-config/textobjects.scm
Normal file
@ -0,0 +1,6 @@
|
||||
(comment) @comment.inside
|
||||
|
||||
(comment)+ @comment.around
|
||||
|
||||
(variable
|
||||
(_) @entry.inside) @entry.around
|
@ -11,8 +11,41 @@
|
||||
(property
|
||||
(path) @_is_code
|
||||
(string) @injection.content))
|
||||
(#match? @_type "type")
|
||||
(#eq? @_type "type")
|
||||
(#match? @_is_shader "Shader")
|
||||
(#eq? @_is_code "code")
|
||||
(#set! injection.language "glsl")
|
||||
)
|
||||
|
||||
((section
|
||||
(identifier) @_is_resource
|
||||
(property
|
||||
(path) @_is_code
|
||||
(string) @injection.content))
|
||||
(#eq? @_is_resource "resource")
|
||||
(#eq? @_is_code "code")
|
||||
(#set! injection.language "glsl")
|
||||
)
|
||||
|
||||
((section
|
||||
(identifier) @_id
|
||||
(property
|
||||
(path) @_is_expression
|
||||
(string) @injection.content))
|
||||
(#eq? @_id "sub_resource")
|
||||
(#eq? @_is_expression "expression")
|
||||
(#set! injection.language "glsl")
|
||||
)
|
||||
|
||||
((section
|
||||
(attribute
|
||||
(identifier) @_type
|
||||
(string) @_is_shader)
|
||||
(property
|
||||
(path) @_is_code
|
||||
(string) @injection.content))
|
||||
(#eq? @_type "type")
|
||||
(#match? @_is_shader "GDScript")
|
||||
(#eq? @_is_code "script/source")
|
||||
(#set! injection.language "gdscript")
|
||||
)
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user