Merge branch 'helix-editor:master' into scroll_preview_fixed

This commit is contained in:
Shaun_Sheep 2024-10-24 13:40:35 +02:00 committed by GitHub
commit f23721dbb3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
23 changed files with 437 additions and 147 deletions

View File

@ -14,7 +14,7 @@ jobs:
uses: actions/checkout@v4
- name: Install nix
uses: cachix/install-nix-action@v29
uses: cachix/install-nix-action@v30
- name: Authenticate with Cachix
uses: cachix/cachix-action@v15

47
Cargo.lock generated
View File

@ -68,9 +68,9 @@ dependencies = [
[[package]]
name = "anyhow"
version = "1.0.89"
version = "1.0.90"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6"
checksum = "37bf3594c4c988a53154954629820791dde498571819ae4ca50ca811e060cc95"
[[package]]
name = "arc-swap"
@ -136,9 +136,9 @@ checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53"
[[package]]
name = "cc"
version = "1.1.23"
version = "1.1.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3bbb537bb4a30b90362caddba8f360c0a56bc13d3a5570028e7197204cb54a17"
checksum = "c2e7962b54006dcfcc61cb72735f4d89bb97061dd6a7ed882ec6b8ee53714c6f"
dependencies = [
"shlex",
]
@ -355,9 +355,9 @@ checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6"
[[package]]
name = "fern"
version = "0.6.2"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9f0c14694cbd524c8720dd69b0e3179344f04ebb5f90f2e4a440c6ea3b2f1ee"
checksum = "69ff9c9d5fb3e6da8ac2f77ab76fe7e8087d512ce095200f8f29ac5b656cf6dc"
dependencies = [
"log",
]
@ -412,15 +412,15 @@ dependencies = [
[[package]]
name = "futures-core"
version = "0.3.30"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
[[package]]
name = "futures-executor"
version = "0.3.30"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d"
checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f"
dependencies = [
"futures-core",
"futures-task",
@ -429,15 +429,15 @@ dependencies = [
[[package]]
name = "futures-task"
version = "0.3.30"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988"
[[package]]
name = "futures-util"
version = "0.3.30"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
dependencies = [
"futures-core",
"futures-task",
@ -1609,9 +1609,9 @@ dependencies = [
[[package]]
name = "libc"
version = "0.2.159"
version = "0.2.161"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5"
checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1"
[[package]]
name = "libloading"
@ -1753,12 +1753,9 @@ dependencies = [
[[package]]
name = "once_cell"
version = "1.20.1"
version = "1.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "82881c4be219ab5faaf2ad5e5e5ecdff8c66bd7402ca3160975c93b24961afd1"
dependencies = [
"portable-atomic",
]
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
[[package]]
name = "open"
@ -1841,9 +1838,9 @@ checksum = "744a264d26b88a6a7e37cbad97953fa233b94d585236310bcbc88474b4092d79"
[[package]]
name = "pulldown-cmark"
version = "0.12.1"
version = "0.12.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "666f0f59e259aea2d72e6012290c09877a780935cc3c18b1ceded41f3890d59c"
checksum = "f86ba2052aebccc42cbbb3ed234b8b13ce76f75c3551a303cb2bcffcff12bb14"
dependencies = [
"bitflags",
"memchr",
@ -2029,9 +2026,9 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.128"
version = "1.0.132"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8"
checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03"
dependencies = [
"itoa",
"memchr",

View File

@ -47,7 +47,7 @@ # Installation
[Installation documentation](https://docs.helix-editor.com/install.html).
[![Packaging status](https://repology.org/badge/vertical-allrepos/helix.svg?exclude_unsupported=1)](https://repology.org/project/helix/versions)
[![Packaging status](https://repology.org/badge/vertical-allrepos/helix-editor.svg?exclude_unsupported=1)](https://repology.org/project/helix-editor/versions)
# Contributing

View File

@ -39,6 +39,7 @@
| dockerfile | ✓ | ✓ | | `docker-langserver` |
| dot | ✓ | | | `dot-language-server` |
| dtd | ✓ | | | |
| dune | ✓ | | | |
| earthfile | ✓ | ✓ | ✓ | `earthlyls` |
| edoc | ✓ | | | |
| eex | ✓ | | | |
@ -68,7 +69,7 @@
| gjs | ✓ | ✓ | ✓ | `typescript-language-server`, `vscode-eslint-language-server`, `ember-language-server` |
| gleam | ✓ | ✓ | | `gleam` |
| glimmer | ✓ | | | `ember-language-server` |
| glsl | ✓ | ✓ | ✓ | |
| glsl | ✓ | ✓ | ✓ | `glsl_analyzer` |
| gn | ✓ | | | |
| go | ✓ | ✓ | ✓ | `gopls`, `golangci-lint-langserver` |
| godot-resource | ✓ | ✓ | | |
@ -185,6 +186,7 @@
| smali | ✓ | | ✓ | |
| smithy | ✓ | | | `cs` |
| sml | ✓ | | | |
| snakemake | ✓ | | ✓ | `pylsp` |
| solidity | ✓ | ✓ | | `solc` |
| spicedb | ✓ | | | |
| sql | ✓ | ✓ | | |

View File

@ -17,7 +17,7 @@ ## Package managers
- [Chocolatey](#chocolatey)
- [MSYS2](#msys2)
[![Packaging status](https://repology.org/badge/vertical-allrepos/helix.svg)](https://repology.org/project/helix/versions)
[![Packaging status](https://repology.org/badge/vertical-allrepos/helix-editor.svg)](https://repology.org/project/helix-editor/versions)
## Linux

View File

@ -283,7 +283,6 @@ #### Interface
| `ui.debug.active` | Indicator for the line at which debugging execution is paused at, found in the gutter |
| `ui.gutter` | Gutter |
| `ui.gutter.selected` | Gutter for the line the cursor is on |
| `ui.highlight.frameline` | Line at which debugging execution is paused at |
| `ui.linenr` | Line numbers |
| `ui.linenr.selected` | Line number for the line the cursor is on |
| `ui.statusline` | Statusline |
@ -320,6 +319,7 @@ #### Interface
| `ui.selection` | For selections in the editing area |
| `ui.selection.primary` | |
| `ui.highlight` | Highlighted lines in the picker preview |
| `ui.highlight.frameline` | Line at which debugging execution is paused at |
| `ui.cursorline.primary` | The line of the primary cursor ([if cursorline is enabled][editor-section]) |
| `ui.cursorline.secondary` | The lines of any other cursors ([if cursorline is enabled][editor-section]) |
| `ui.cursorcolumn.primary` | The column of the primary cursor ([if cursorcolumn is enabled][editor-section]) |

View File

@ -1,17 +1,12 @@
{
"nodes": {
"crane": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1709610799,
"narHash": "sha256-5jfLQx0U9hXbi2skYMGodDJkIgffrjIOgMRjZqms2QE=",
"lastModified": 1727974419,
"narHash": "sha256-WD0//20h+2/yPGkO88d2nYbb23WMWYvnRyDQ9Dx4UHg=",
"owner": "ipetkov",
"repo": "crane",
"rev": "81c393c776d5379c030607866afef6406ca1be57",
"rev": "37e4f9f0976cb9281cd3f0c70081e5e0ecaee93f",
"type": "github"
},
"original": {
@ -25,11 +20,11 @@
"systems": "systems"
},
"locked": {
"lastModified": 1709126324,
"narHash": "sha256-q6EQdSeUZOG26WelxqkmR7kArjgWCdw5sfJVHPH/7j8=",
"lastModified": 1726560853,
"narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "d465f4819400de7c8d874d50b982301f28a84605",
"rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a",
"type": "github"
},
"original": {
@ -40,11 +35,11 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1709479366,
"narHash": "sha256-n6F0n8UV6lnTZbYPl1A9q1BS0p4hduAv1mGAP17CVd0=",
"lastModified": 1728018373,
"narHash": "sha256-NOiTvBbRLIOe5F6RbHaAh6++BNjsb149fGZd1T4+KBg=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "b8697e57f10292a6165a20f03d2f42920dfaf973",
"rev": "bc947f541ae55e999ffdb4013441347d83b00feb",
"type": "github"
},
"original": {
@ -64,19 +59,16 @@
},
"rust-overlay": {
"inputs": {
"flake-utils": [
"flake-utils"
],
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1709604635,
"narHash": "sha256-le4fwmWmjGRYWwkho0Gr7mnnZndOOe4XGbLw68OvF40=",
"lastModified": 1728268235,
"narHash": "sha256-lJMFnMO4maJuNO6PQ5fZesrTmglze3UFTTBuKGwR1Nw=",
"owner": "oxalica",
"repo": "rust-overlay",
"rev": "e86c0fb5d3a22a5f30d7f64ecad88643fe26449d",
"rev": "25685cc2c7054efc31351c172ae77b21814f2d42",
"type": "github"
},
"original": {

View File

@ -6,15 +6,9 @@
flake-utils.url = "github:numtide/flake-utils";
rust-overlay = {
url = "github:oxalica/rust-overlay";
inputs = {
nixpkgs.follows = "nixpkgs";
flake-utils.follows = "flake-utils";
};
};
crane = {
url = "github:ipetkov/crane";
inputs.nixpkgs.follows = "nixpkgs";
};
crane.url = "github:ipetkov/crane";
};
outputs = {
@ -114,7 +108,7 @@
if pkgs.stdenv.isLinux
then pkgs.stdenv
else pkgs.clangStdenv;
rustFlagsEnv = pkgs.lib.optionalString stdenv.isLinux "-C link-arg=-fuse-ld=lld -C target-cpu=native -Clink-arg=-Wl,--no-rosegment";
rustFlagsEnv = pkgs.lib.optionalString stdenv.isLinux "-C link-arg=-fuse-ld=lld -C target-cpu=native -Clink-arg=-Wl,--no-rosegment --cfg tokio_unstable";
rustToolchain = pkgs.pkgsBuildHost.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml;
craneLibMSRV = (crane.mkLib pkgs).overrideToolchain rustToolchain;
craneLibStable = (crane.mkLib pkgs).overrideToolchain pkgs.pkgsBuildHost.rust-bin.stable.latest.default;

View File

@ -9,6 +9,24 @@
use helix_stdx::rope::RopeSliceExt;
use std::borrow::Cow;
pub const DEFAULT_COMMENT_TOKEN: &str = "//";
/// Returns the longest matching comment token of the given line (if it exists).
pub fn get_comment_token<'a, S: AsRef<str>>(
text: RopeSlice,
tokens: &'a [S],
line_num: usize,
) -> Option<&'a str> {
let line = text.line(line_num);
let start = line.first_non_whitespace_char()?;
tokens
.iter()
.map(AsRef::as_ref)
.filter(|token| line.slice(start..).starts_with(token))
.max_by_key(|token| token.len())
}
/// Given text, a comment token, and a set of line indices, returns the following:
/// - Whether the given lines should be considered commented
/// - If any of the lines are uncommented, all lines are considered as such.
@ -28,21 +46,20 @@ fn find_line_comment(
let mut min = usize::MAX; // minimum col for first_non_whitespace_char
let mut margin = 1;
let token_len = token.chars().count();
for line in lines {
let line_slice = text.line(line);
if let Some(pos) = line_slice.first_non_whitespace_char() {
let len = line_slice.len_chars();
if pos < min {
min = pos;
}
min = std::cmp::min(min, pos);
// line can be shorter than pos + token len
let fragment = Cow::from(line_slice.slice(pos..std::cmp::min(pos + token.len(), len)));
if fragment != token {
// as soon as one of the non-blank lines doesn't have a comment, the whole block is
// considered uncommented.
if fragment != token {
commented = false;
}
@ -56,6 +73,7 @@ fn find_line_comment(
to_change.push(line);
}
}
(commented, to_change, min, margin)
}
@ -63,7 +81,7 @@ fn find_line_comment(
pub fn toggle_line_comments(doc: &Rope, selection: &Selection, token: Option<&str>) -> Transaction {
let text = doc.slice(..);
let token = token.unwrap_or("//");
let token = token.unwrap_or(DEFAULT_COMMENT_TOKEN);
let comment = Tendril::from(format!("{} ", token));
let mut lines: Vec<usize> = Vec::with_capacity(selection.len());
@ -317,56 +335,87 @@ pub fn split_lines_of_selection(text: RopeSlice, selection: &Selection) -> Selec
mod test {
use super::*;
mod find_line_comment {
use super::*;
#[test]
fn test_find_line_comment() {
fn not_commented() {
// four lines, two space indented, except for line 1 which is blank.
let mut doc = Rope::from(" 1\n\n 2\n 3");
// select whole document
let mut selection = Selection::single(0, doc.len_chars() - 1);
let doc = Rope::from(" 1\n\n 2\n 3");
let text = doc.slice(..);
let res = find_line_comment("//", text, 0..3);
// (commented = true, to_change = [line 0, line 2], min = col 2, margin = 0)
// (commented = false, to_change = [line 0, line 2], min = col 2, margin = 0)
assert_eq!(res, (false, vec![0, 2], 2, 0));
}
#[test]
fn is_commented() {
// three lines where the second line is empty.
let doc = Rope::from("// hello\n\n// there");
let res = find_line_comment("//", doc.slice(..), 0..3);
// (commented = true, to_change = [line 0, line 2], min = col 0, margin = 1)
assert_eq!(res, (true, vec![0, 2], 0, 1));
}
}
// TODO: account for uncommenting with uneven comment indentation
mod toggle_line_comment {
use super::*;
#[test]
fn comment() {
// four lines, two space indented, except for line 1 which is blank.
let mut doc = Rope::from(" 1\n\n 2\n 3");
// select whole document
let selection = Selection::single(0, doc.len_chars() - 1);
// comment
let transaction = toggle_line_comments(&doc, &selection, None);
transaction.apply(&mut doc);
selection = selection.map(transaction.changes());
assert_eq!(doc, " // 1\n\n // 2\n // 3");
}
// uncomment
let transaction = toggle_line_comments(&doc, &selection, None);
transaction.apply(&mut doc);
selection = selection.map(transaction.changes());
assert_eq!(doc, " 1\n\n 2\n 3");
assert!(selection.len() == 1); // to ignore the selection unused warning
// 0 margin comments
doc = Rope::from(" //1\n\n //2\n //3");
// reset the selection.
selection = Selection::single(0, doc.len_chars() - 1);
#[test]
fn uncomment() {
let mut doc = Rope::from(" // 1\n\n // 2\n // 3");
let mut selection = Selection::single(0, doc.len_chars() - 1);
let transaction = toggle_line_comments(&doc, &selection, None);
transaction.apply(&mut doc);
selection = selection.map(transaction.changes());
assert_eq!(doc, " 1\n\n 2\n 3");
assert!(selection.len() == 1); // to ignore the selection unused warning
}
// 0 margin comments, with no space
doc = Rope::from("//");
// reset the selection.
selection = Selection::single(0, doc.len_chars() - 1);
#[test]
fn uncomment_0_margin_comments() {
let mut doc = Rope::from(" //1\n\n //2\n //3");
let mut selection = Selection::single(0, doc.len_chars() - 1);
let transaction = toggle_line_comments(&doc, &selection, None);
transaction.apply(&mut doc);
selection = selection.map(transaction.changes());
assert_eq!(doc, " 1\n\n 2\n 3");
assert!(selection.len() == 1); // to ignore the selection unused warning
}
#[test]
fn uncomment_0_margin_comments_with_no_space() {
let mut doc = Rope::from("//");
let mut selection = Selection::single(0, doc.len_chars() - 1);
let transaction = toggle_line_comments(&doc, &selection, None);
transaction.apply(&mut doc);
selection = selection.map(transaction.changes());
assert_eq!(doc, "");
assert!(selection.len() == 1); // to ignore the selection unused warning
// TODO: account for uncommenting with uneven comment indentation
}
}
#[test]
@ -413,4 +462,32 @@ fn test_find_block_comments() {
transaction.apply(&mut doc);
assert_eq!(doc, "");
}
/// Test, if `get_comment_tokens` works, even if the content of the file includes chars, whose
/// byte size unequal the amount of chars
#[test]
fn test_get_comment_with_char_boundaries() {
let rope = Rope::from("··");
let tokens = ["//", "///"];
assert_eq!(
super::get_comment_token(rope.slice(..), tokens.as_slice(), 0),
None
);
}
/// Test for `get_comment_token`.
///
/// Assuming the comment tokens are stored as `["///", "//"]`, `get_comment_token` should still
/// return `///` instead of `//` if the user is in a doc-comment section.
#[test]
fn test_use_longest_comment() {
let text = Rope::from(" /// amogus");
let tokens = ["///", "//"];
assert_eq!(
super::get_comment_token(text.slice(..), tokens.as_slice(), 0),
Some("///")
);
}
}

View File

@ -24,4 +24,4 @@ tokio = { version = "1", features = ["rt", "rt-multi-thread", "io-util", "io-std
thiserror.workspace = true
[dev-dependencies]
fern = "0.6"
fern = "0.7"

View File

@ -23,7 +23,7 @@ once_cell = "1.20"
anyhow = "1"
log = "0.4"
futures-executor = "0.3.28"
futures-executor = "0.3.31"
[features]
integration_test = []

View File

@ -23,7 +23,7 @@ license = "MIT"
[dependencies]
bitflags = "2.6.0"
serde = { version = "1.0.209", features = ["derive"] }
serde_json = "1.0.127"
serde_json = "1.0.132"
serde_repr = "0.1"
url = {version = "2.0.0", features = ["serde"]}

View File

@ -45,7 +45,7 @@ arc-swap = { version = "1.7.1" }
termini = "1"
# Logging
fern = "0.6"
fern = "0.7"
chrono = { version = "0.4", default-features = false, features = ["clock"] }
log = "0.4"
@ -74,7 +74,7 @@ grep-searcher = "0.1.14"
[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.159"
libc = "0.2.161"
[target.'cfg(target_os = "macos")'.dependencies]
crossterm = { version = "0.28", features = ["event-stream", "use-dev-tty", "libc"] }

View File

@ -22,8 +22,8 @@
encoding, find_workspace,
graphemes::{self, next_grapheme_boundary, RevRopeGraphemes},
history::UndoKind,
increment, indent,
indent::IndentStyle,
increment,
indent::{self, IndentStyle},
line_ending::{get_line_ending_of_str, line_end_char_index},
match_brackets,
movement::{self, move_vertically_visual, Direction},
@ -3467,7 +3467,15 @@ fn open(cx: &mut Context, open: Open) {
)
};
let indent = indent::indent_for_newline(
let continue_comment_token = doc
.language_config()
.and_then(|config| config.comment_tokens.as_ref())
.and_then(|tokens| comment::get_comment_token(text, tokens, cursor_line));
let line = text.line(cursor_line);
let indent = match line.first_non_whitespace_char() {
Some(pos) if continue_comment_token.is_some() => line.slice(..pos).to_string(),
_ => indent::indent_for_newline(
doc.language_config(),
doc.syntax(),
&doc.config.load().indent_heuristic,
@ -3477,21 +3485,33 @@ fn open(cx: &mut Context, open: Open) {
line_num,
line_end_index,
cursor_line,
);
),
};
let indent_len = indent.len();
let mut text = String::with_capacity(1 + indent_len);
text.push_str(doc.line_ending.as_str());
text.push_str(&indent);
if let Some(token) = continue_comment_token {
text.push_str(token);
text.push(' ');
}
let text = text.repeat(count);
// calculate new selection ranges
let pos = offs + line_end_index + line_end_offset_width;
let comment_len = continue_comment_token
.map(|token| token.len() + 1) // `+ 1` for the extra space added
.unwrap_or_default();
for i in 0..count {
// pos -> beginning of reference line,
// + (i * (1+indent_len)) -> beginning of i'th line from pos
// + indent_len -> -> indent for i'th line
ranges.push(Range::point(pos + (i * (1 + indent_len)) + indent_len));
// + (i * (1+indent_len + comment_len)) -> beginning of i'th line from pos (possibly including comment token)
// + indent_len + comment_len -> -> indent for i'th line
ranges.push(Range::point(
pos + (i * (1 + indent_len + comment_len)) + indent_len + comment_len,
));
}
offs += text.chars().count();
@ -3929,6 +3949,11 @@ pub fn insert_newline(cx: &mut Context) {
let mut new_text = String::new();
let continue_comment_token = doc
.language_config()
.and_then(|config| config.comment_tokens.as_ref())
.and_then(|tokens| comment::get_comment_token(text, tokens, current_line));
// If the current line is all whitespace, insert a line ending at the beginning of
// the current line. This makes the current line empty and the new line contain the
// indentation of the old line.
@ -3938,7 +3963,11 @@ pub fn insert_newline(cx: &mut Context) {
(line_start, line_start, new_text.chars().count())
} else {
let indent = indent::indent_for_newline(
let line = text.line(current_line);
let indent = match line.first_non_whitespace_char() {
Some(pos) if continue_comment_token.is_some() => line.slice(..pos).to_string(),
_ => indent::indent_for_newline(
doc.language_config(),
doc.syntax(),
&doc.config.load().indent_heuristic,
@ -3948,7 +3977,8 @@ pub fn insert_newline(cx: &mut Context) {
current_line,
pos,
current_line,
);
),
};
// If we are between pairs (such as brackets), we want to
// insert an additional line which is indented one level
@ -3958,19 +3988,30 @@ pub fn insert_newline(cx: &mut Context) {
.and_then(|pairs| pairs.get(prev))
.map_or(false, |pair| pair.open == prev && pair.close == curr);
let local_offs = if on_auto_pair {
let local_offs = if let Some(token) = continue_comment_token {
new_text.push_str(doc.line_ending.as_str());
new_text.push_str(&indent);
new_text.push_str(token);
new_text.push(' ');
new_text.chars().count()
} else if on_auto_pair {
// line where the cursor will be
let inner_indent = indent.clone() + doc.indent_style.as_str();
new_text.reserve_exact(2 + indent.len() + inner_indent.len());
new_text.push_str(doc.line_ending.as_str());
new_text.push_str(&inner_indent);
// line where the matching pair will be
let local_offs = new_text.chars().count();
new_text.push_str(doc.line_ending.as_str());
new_text.push_str(&indent);
local_offs
} else {
new_text.reserve_exact(1 + indent.len());
new_text.push_str(doc.line_ending.as_str());
new_text.push_str(&indent);
new_text.chars().count()
};

View File

@ -96,7 +96,10 @@ fn handle_event(&mut self, event: &Event, _cx: &mut Context) -> EventResult {
fn render(&mut self, area: Rect, surface: &mut Buffer, cx: &mut Context) {
let margin = Margin::horizontal(1);
let signature = &self.signatures[self.active_signature];
let signature = self
.signatures
.get(self.active_signature)
.unwrap_or_else(|| &self.signatures[0]);
let active_param_span = signature.active_param_range.map(|(start, end)| {
vec![(
@ -108,9 +111,13 @@ fn render(&mut self, area: Rect, surface: &mut Buffer, cx: &mut Context) {
)]
});
let sig = &self.signatures[self.active_signature];
let signature = self
.signatures
.get(self.active_signature)
.unwrap_or_else(|| &self.signatures[0]);
let sig_text = crate::ui::markdown::highlighted_code_block(
sig.signature.as_str(),
signature.signature.as_str(),
&self.language,
Some(&cx.editor.theme),
Arc::clone(&self.config_loader),
@ -130,7 +137,7 @@ fn render(&mut self, area: Rect, surface: &mut Buffer, cx: &mut Context) {
let sig_text_para = Paragraph::new(&sig_text).wrap(Wrap { trim: false });
sig_text_para.render(sig_text_area, surface);
if sig.signature_doc.is_none() {
if signature.signature_doc.is_none() {
return;
}
@ -142,7 +149,7 @@ fn render(&mut self, area: Rect, surface: &mut Buffer, cx: &mut Context) {
}
}
let sig_doc = match &sig.signature_doc {
let sig_doc = match &signature.signature_doc {
None => return,
Some(doc) => Markdown::new(doc.clone(), Arc::clone(&self.config_loader)),
};
@ -160,12 +167,15 @@ fn required_size(&mut self, viewport: (u16, u16)) -> Option<(u16, u16)> {
const PADDING: u16 = 2;
const SEPARATOR_HEIGHT: u16 = 1;
let sig = &self.signatures[self.active_signature];
let signature = self
.signatures
.get(self.active_signature)
.unwrap_or_else(|| &self.signatures[0]);
let max_text_width = viewport.0.saturating_sub(PADDING).clamp(10, 120);
let signature_text = crate::ui::markdown::highlighted_code_block(
sig.signature.as_str(),
signature.signature.as_str(),
&self.language,
None,
Arc::clone(&self.config_loader),
@ -174,7 +184,7 @@ fn required_size(&mut self, viewport: (u16, u16)) -> Option<(u16, u16)> {
let (sig_width, sig_height) =
crate::ui::text::required_size(&signature_text, max_text_width);
let (width, height) = match sig.signature_doc {
let (width, height) = match signature.signature_doc {
Some(ref doc) => {
let doc_md = Markdown::new(doc.clone(), Arc::clone(&self.config_loader));
let doc_text = doc_md.parse(None);

View File

@ -41,6 +41,7 @@ forth-lsp = { command = "forth-lsp" }
fortls = { command = "fortls", args = ["--lowercase_intrinsics"] }
fsharp-ls = { command = "fsautocomplete", config = { AutomaticWorkspaceInit = true } }
gleam = { command = "gleam", args = ["lsp"] }
glsl_analyzer = { command = "glsl_analyzer" }
graphql-language-service = { command = "graphql-lsp", args = ["server", "-m", "stream"] }
haskell-language-server = { command = "haskell-language-server-wrapper", args = ["--lsp"] }
idris2-lsp = { command = "idris2-lsp" }
@ -1243,6 +1244,23 @@ indent = { tab-width = 2, unit = " " }
name = "ocaml-interface"
source = { git = "https://github.com/tree-sitter/tree-sitter-ocaml", rev = "9965d208337d88bbf1a38ad0b0fe49e5f5ec9677", subpath = "interface" }
[[language]]
name = "dune"
scope = "source.dune"
roots = ["dune-project"]
file-types = [{ glob = "dune-project" }, { glob = "dune" }]
comment-token = ";"
indent = { tab-width = 1, unit = " " }
grammar = "scheme"
auto-format = true
formatter = { command = "dune", args = ["format-dune-file"] }
[language.auto-pairs]
'(' = ')'
'{' = '}'
'[' = ']'
'"' = '"'
[[language]]
name = "lua"
injection-regex = "lua"
@ -1435,6 +1453,7 @@ file-types = ["glsl", "vert", "tesc", "tese", "geom", "frag", "comp" ]
comment-token = "//"
block-comment-tokens = { start = "/*", end = "*/" }
indent = { tab-width = 4, unit = " " }
language-servers = [ "glsl_analyzer" ]
injection-regex = "glsl"
[[grammar]]
@ -2465,6 +2484,12 @@ injection-regex = "sml"
file-types = ["sml"]
block-comment-tokens = { start = "(*", end = "*)" }
[language.auto-pairs]
'(' = ')'
'{' = '}'
'[' = ']'
'"' = '"'
[[grammar]]
name = "sml"
source = { git = "https://github.com/Giorbo/tree-sitter-sml", rev = "bd4055d5554614520d4a0706b34dc0c317c6b608" }
@ -3247,7 +3272,7 @@ text-width = 72
[[grammar]]
name = "jjdescription"
source = { git = "https://github.com/kareigu/tree-sitter-jjdescription", rev = "2ddec6cad07b366aee276a608e1daa2c29d3caf2" }
source = { git = "https://github.com/kareigu/tree-sitter-jjdescription", rev = "23dd3dd18ee29bdd761642511aa314215801afd8" }
[[language]]
name = "jq"
@ -3810,3 +3835,17 @@ language-servers = ["circom-lsp"]
[[grammar]]
name = "circom"
source = { git = "https://github.com/Decurity/tree-sitter-circom", rev = "02150524228b1e6afef96949f2d6b7cc0aaf999e" }
[[language]]
name = "snakemake"
scope = "source.snakemake"
roots = ["Snakefile", "config.yaml", "environment.yaml", "workflow/"]
file-types = ["smk", "Snakefile"]
comment-tokens = ["#", "##"]
indent = { tab-width = 2, unit = " " }
language-servers = ["pylsp" ]
[[grammar]]
name = "snakemake"
source = { git = "https://github.com/osthomas/tree-sitter-snakemake", rev = "e909815acdbe37e69440261ebb1091ed52e1dec6" }

View File

@ -0,0 +1 @@
; inherits: scheme

View File

@ -0,0 +1,20 @@
Copyright (c) 2016 Max Brunsfeld
Copyright (c) 2023 Oliver Thomas
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.

View File

@ -0,0 +1,8 @@
; inherits: python
[
(rule_definition)
(rule_inheritance)
(module_definition)
(checkpoint_definition)
] @fold

View File

@ -0,0 +1,76 @@
; inherits: python
; Compound directives
[
"rule"
"checkpoint"
"module"
] @keyword
; Top level directives (eg. configfile, include)
(module
(directive
name: _ @keyword))
; Subordinate directives (eg. input, output)
((_)
body: (_
(directive
name: _ @label)))
; rule/module/checkpoint names
(rule_definition
name: (identifier) @type)
(module_definition
name: (identifier) @type)
(checkpoint_definition
name: (identifier) @type)
; Rule imports
(rule_import
"use" @keyword.import
"rule" @keyword.import
"from" @keyword.import
"exclude"? @keyword.import
"as"? @keyword.import
"with"? @keyword.import)
; Rule inheritance
(rule_inheritance
"use" @keyword
"rule" @keyword
"with" @keyword)
; Wildcard names
(wildcard (identifier) @variable)
(wildcard (flag) @variable.parameter.builtin)
; builtin variables
((identifier) @variable.builtin
(#any-of? @variable.builtin "checkpoints" "config" "gather" "rules" "scatter" "workflow"))
; References to directive labels in wildcard interpolations
; the #any-of? queries are moved above the #has-ancestor? queries to
; short-circuit the potentially expensive tree traversal, if possible
; see:
; https://github.com/nvim-treesitter/nvim-treesitter/pull/4302#issuecomment-1685789790
; directive labels in wildcard context
((wildcard
(identifier) @label)
(#any-of? @label "input" "log" "output" "params" "resources" "threads" "wildcards"))
((wildcard
(attribute
object: (identifier) @label))
(#any-of? @label "input" "log" "output" "params" "resources" "threads" "wildcards"))
((wildcard
(subscript
value: (identifier) @label))
(#any-of? @label "input" "log" "output" "params" "resources" "threads" "wildcards"))
; directive labels in block context (eg. within 'run:')
((identifier) @label
(#any-of? @label "input" "log" "output" "params" "resources" "threads" "wildcards"))

View File

@ -0,0 +1,27 @@
; inherits: python
[
(rule_definition)
(checkpoint_definition)
(rule_inheritance)
(module_definition)
] @indent
[
(rule_definition)
(checkpoint_definition)
(rule_inheritance)
(module_definition)
] @extend
(directive) @indent
(directive) @extend
(rule_import
"with"
":") @indent
(rule_import
"with"
":") @extend

View File

@ -0,0 +1,5 @@
; inherits: python
(wildcard
(constraint) @injection.content
(#set! injection.language "regex"))

View File

@ -0,0 +1 @@
; inherits: python