mirror of
https://github.com/helix-editor/helix.git
synced 2024-11-22 09:26:19 +04:00
Merge branch 'helix-editor:master' into scroll_preview_fixed
This commit is contained in:
commit
f23721dbb3
2
.github/workflows/cachix.yml
vendored
2
.github/workflows/cachix.yml
vendored
@ -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
47
Cargo.lock
generated
@ -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",
|
||||
|
@ -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
|
||||
|
||||
|
@ -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 | ✓ | ✓ | | |
|
||||
|
@ -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
|
||||
|
||||
|
@ -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]) |
|
||||
|
32
flake.lock
32
flake.lock
@ -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": {
|
||||
|
10
flake.nix
10
flake.nix
@ -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;
|
||||
|
@ -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("///")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -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"
|
||||
|
@ -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 = []
|
||||
|
@ -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"]}
|
||||
|
||||
|
@ -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"] }
|
||||
|
@ -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()
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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" }
|
||||
|
1
runtime/queries/dune/highlights.scm
Normal file
1
runtime/queries/dune/highlights.scm
Normal file
@ -0,0 +1 @@
|
||||
; inherits: scheme
|
20
runtime/queries/snakemake/LICENSE
Executable file
20
runtime/queries/snakemake/LICENSE
Executable 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.
|
8
runtime/queries/snakemake/folds.scm
Executable file
8
runtime/queries/snakemake/folds.scm
Executable file
@ -0,0 +1,8 @@
|
||||
; inherits: python
|
||||
|
||||
[
|
||||
(rule_definition)
|
||||
(rule_inheritance)
|
||||
(module_definition)
|
||||
(checkpoint_definition)
|
||||
] @fold
|
76
runtime/queries/snakemake/highlights.scm
Executable file
76
runtime/queries/snakemake/highlights.scm
Executable 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"))
|
27
runtime/queries/snakemake/indents.scm
Executable file
27
runtime/queries/snakemake/indents.scm
Executable 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
|
5
runtime/queries/snakemake/injections.scm
Executable file
5
runtime/queries/snakemake/injections.scm
Executable file
@ -0,0 +1,5 @@
|
||||
; inherits: python
|
||||
|
||||
(wildcard
|
||||
(constraint) @injection.content
|
||||
(#set! injection.language "regex"))
|
1
runtime/queries/snakemake/locals.scm
Executable file
1
runtime/queries/snakemake/locals.scm
Executable file
@ -0,0 +1 @@
|
||||
; inherits: python
|
Loading…
Reference in New Issue
Block a user