Merge branch 'helix-editor:master' into master

pull/10391/head
Vadim 7 months ago committed by GitHub
commit b792676400
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

69
Cargo.lock generated

@ -538,9 +538,9 @@ checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e"
[[package]]
name = "gix"
version = "0.61.0"
version = "0.62.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4e0e59a44bf00de058ee98d6ecf3c9ed8f8842c1da642258ae4120d41ded8f7"
checksum = "5631c64fb4cd48eee767bf98a3cbc5c9318ef3bb71074d4c099a2371510282b6"
dependencies = [
"gix-actor",
"gix-attributes",
@ -663,9 +663,9 @@ dependencies = [
[[package]]
name = "gix-config"
version = "0.36.0"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62129c75e4b6229fe15fb9838cdc00c655e87105b651e4edd7c183fc5288b5d1"
checksum = "7580e05996e893347ad04e1eaceb92e1c0e6a3ffe517171af99bf6b6df0ca6e5"
dependencies = [
"bstr",
"gix-config-value",
@ -709,9 +709,9 @@ dependencies = [
[[package]]
name = "gix-diff"
version = "0.42.0"
version = "0.43.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78e605593c2ef74980a534ade0909c7dc57cca72baa30cbb67d2dda621f99ac4"
checksum = "a5fbc24115b957346cd23fb0f47d830eb799c46c89cdcf2f5acc9bf2938c2d01"
dependencies = [
"bstr",
"gix-command",
@ -729,9 +729,9 @@ dependencies = [
[[package]]
name = "gix-dir"
version = "0.3.0"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3413ccd29130900c17574678aee640e4847909acae9febf6424dc77b782c6d32"
checksum = "d6943a1f213ad7a060a0548ece229be53f3c2151534b126446ce3533eaf5f14c"
dependencies = [
"bstr",
"gix-discover",
@ -784,9 +784,9 @@ dependencies = [
[[package]]
name = "gix-filter"
version = "0.11.0"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd71bf3e64d8fb5d5635d4166ca5a36fe56b292ffff06eab1d93ea47fd5beb89"
checksum = "5c0d1f01af62bfd2fb3dd291acc2b29d4ab3e96ad52a679174626508ce98ef12"
dependencies = [
"bstr",
"encoding_rs",
@ -805,9 +805,9 @@ dependencies = [
[[package]]
name = "gix-fs"
version = "0.10.1"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "634b8a743b0aae03c1a74ee0ea24e8c5136895efac64ce52b3ea106e1c6f0613"
checksum = "e2184c40e7910529677831c8b481acf788ffd92427ed21fad65b6aa637e631b8"
dependencies = [
"gix-features",
"gix-utils",
@ -861,9 +861,9 @@ dependencies = [
[[package]]
name = "gix-index"
version = "0.31.1"
version = "0.32.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "549621f13d9ccf325a7de45506a3266af0d08f915181c5687abb5e8669bfd2e6"
checksum = "3383122cf18655ef4c097c0b935bba5eb56983947959aaf3b0ceb1949d4dd371"
dependencies = [
"bitflags 2.5.0",
"bstr",
@ -929,9 +929,9 @@ dependencies = [
[[package]]
name = "gix-odb"
version = "0.59.0"
version = "0.60.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81b55378c719693380f66d9dd21ce46721eed2981d8789fc698ec1ada6fa176e"
checksum = "e8bbb43d2fefdc4701ffdf9224844d05b136ae1b9a73c2f90710c8dd27a93503"
dependencies = [
"arc-swap",
"gix-date",
@ -949,9 +949,9 @@ dependencies = [
[[package]]
name = "gix-pack"
version = "0.49.0"
version = "0.50.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6391aeaa030ad64aba346a9f5c69bb1c4e5c6fb4411705b03b40b49d8614ec30"
checksum = "b58bad27c7677fa6b587aab3a1aca0b6c97373bd371a0a4290677c838c9bcaf1"
dependencies = [
"clru",
"gix-chunk",
@ -969,9 +969,9 @@ dependencies = [
[[package]]
name = "gix-packetline-blocking"
version = "0.17.3"
version = "0.17.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca8ef6dd3ea50e26f3bf572e90c034d033c804d340cd1eb386392f184a9ba2f7"
checksum = "c31d42378a3d284732e4d589979930d0d253360eccf7ec7a80332e5ccb77e14a"
dependencies = [
"bstr",
"faster-hex",
@ -994,9 +994,9 @@ dependencies = [
[[package]]
name = "gix-pathspec"
version = "0.7.2"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a96ed0e71ce9084a471fddfa74e842576a7cbf02fe8bd50388017ac461aed97"
checksum = "d479789f3abd10f68a709454ce04cd68b54092ee882c8622ae3aa1bb9bf8496c"
dependencies = [
"bitflags 2.5.0",
"bstr",
@ -1099,9 +1099,9 @@ dependencies = [
[[package]]
name = "gix-status"
version = "0.8.0"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca216db89947eca709f69ec5851aa76f9628e7c7aab7aa5a927d0c619d046bf2"
checksum = "50c413bfd2952e4ee92e48438dac3c696f3555e586a34d184a427f6bedd1e4f9"
dependencies = [
"bstr",
"filetime",
@ -1150,16 +1150,17 @@ dependencies = [
[[package]]
name = "gix-trace"
version = "0.1.8"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b838b2db8f62c9447d483a4c28d251b67fee32741a82cb4d35e9eb4e9fdc5ab"
checksum = "f924267408915fddcd558e3f37295cc7d6a3e50f8bd8b606cee0808c3915157e"
[[package]]
name = "gix-traverse"
version = "0.38.0"
version = "0.39.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95aef84bc777025403a09788b1e4815c06a19332e9e5d87a955e1ed7da9bf0cf"
checksum = "f4029ec209b0cc480d209da3837a42c63801dd8548f09c1f4502c60accb62aeb"
dependencies = [
"bitflags 2.5.0",
"gix-commitgraph",
"gix-date",
"gix-hash",
@ -1172,9 +1173,9 @@ dependencies = [
[[package]]
name = "gix-url"
version = "0.27.2"
version = "0.27.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f0b24f3ecc79a5a53539de9c2e99425d0ef23feacdcf3faac983aa9a2f26849"
checksum = "0db829ebdca6180fbe32be7aed393591df6db4a72dbbc0b8369162390954d1cf"
dependencies = [
"bstr",
"gix-features",
@ -1186,9 +1187,9 @@ dependencies = [
[[package]]
name = "gix-utils"
version = "0.1.11"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0066432d4c277f9877f091279a597ea5331f68ca410efc874f0bdfb1cd348f92"
checksum = "35192df7fd0fa112263bad8021e2df7167df4cc2a6e6d15892e1e55621d3d4dc"
dependencies = [
"bstr",
"fastrand",
@ -1207,9 +1208,9 @@ dependencies = [
[[package]]
name = "gix-worktree"
version = "0.32.0"
version = "0.33.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe78e03af9eec168eb187e05463a981c57f0a915f64b1788685a776bd2ef969c"
checksum = "359a87dfef695b5f91abb9a424c947edca82768f34acfc269659f66174a510b4"
dependencies = [
"bstr",
"gix-attributes",

@ -29,6 +29,7 @@
"namespace" = "magenta"
"ui.help" = { fg = "white", bg = "black" }
"ui.virtual.jump-label" = { fg = "blue", modifiers = ["bold", "underlined"] }
"ui.virtual.ruler" = { bg = "black" }
"markup.heading" = "blue"
"markup.list" = "red"

@ -122,6 +122,7 @@
| mermaid | ✓ | | | |
| meson | ✓ | | ✓ | |
| mint | | | | `mint` |
| move | ✓ | | | |
| msbuild | ✓ | | ✓ | |
| nasm | ✓ | ✓ | | |
| nickel | ✓ | | ✓ | `nls` |
@ -197,7 +198,7 @@
| tsx | ✓ | ✓ | ✓ | `typescript-language-server` |
| twig | ✓ | | | |
| typescript | ✓ | ✓ | ✓ | `typescript-language-server` |
| typst | ✓ | | | `typst-lsp` |
| typst | ✓ | | | `tinymist`, `typst-lsp` |
| ungrammar | ✓ | | | |
| unison | ✓ | | ✓ | |
| uxntal | ✓ | | | |
@ -215,6 +216,7 @@
| wren | ✓ | ✓ | ✓ | |
| xit | ✓ | | | |
| xml | ✓ | | ✓ | |
| xtc | ✓ | | | |
| yaml | ✓ | | ✓ | `yaml-language-server`, `ansible-language-server` |
| yuck | ✓ | | | |
| zig | ✓ | ✓ | ✓ | `zls` |

@ -87,3 +87,4 @@
| `:redraw` | Clear and re-render the whole UI |
| `:move` | Move the current buffer and its corresponding file to a different path |
| `:yank-diagnostic` | Yank diagnostic(s) under primary cursor to register, or clipboard by default |
| `:read`, `:r` | Load a file into buffer |

@ -24,6 +24,8 @@
> 💡 Mappings marked (**TS**) require a tree-sitter grammar for the file type.
> ⚠️ Some terminals' default key mappings conflict with Helix's. If any of the mappings described on this page do not work as expected, check your terminal's mappings to ensure they do not conflict. See the (wiki)[https://github.com/helix-editor/helix/wiki/Terminal-Support] for known conflicts.
## Normal mode
Normal mode is the default mode when you launch helix. You can return to it from other modes by pressing the `Escape` key.

@ -2765,10 +2765,10 @@ mod test {
)
};
test("quantified_nodes", 1..36);
test("quantified_nodes", 1..37);
// NOTE: Enable after implementing proper node group capturing
// test("quantified_nodes_grouped", 1..36);
// test("multiple_nodes_grouped", 1..36);
// test("quantified_nodes_grouped", 1..37);
// test("multiple_nodes_grouped", 1..37);
}
#[test]
@ -2939,7 +2939,7 @@ mod test {
#[test]
fn test_pretty_print() {
let source = r#"/// Hello"#;
let source = r#"// Hello"#;
assert_pretty_print("rust", source, "(line_comment)", 0, source.len());
// A large tree should be indented with fields:
@ -2958,7 +2958,8 @@ mod test {
" (macro_invocation\n",
" macro: (identifier)\n",
" (token_tree\n",
" (string_literal))))))",
" (string_literal\n",
" (string_content)))))))",
),
0,
source.len(),

@ -799,28 +799,29 @@ fn goto_line_start(cx: &mut Context) {
}
fn goto_next_buffer(cx: &mut Context) {
goto_buffer(cx.editor, Direction::Forward);
goto_buffer(cx.editor, Direction::Forward, cx.count());
}
fn goto_previous_buffer(cx: &mut Context) {
goto_buffer(cx.editor, Direction::Backward);
goto_buffer(cx.editor, Direction::Backward, cx.count());
}
fn goto_buffer(editor: &mut Editor, direction: Direction) {
fn goto_buffer(editor: &mut Editor, direction: Direction, count: usize) {
let current = view!(editor).doc;
let id = match direction {
Direction::Forward => {
let iter = editor.documents.keys();
let mut iter = iter.skip_while(|id| *id != &current);
iter.next(); // skip current item
iter.next().or_else(|| editor.documents.keys().next())
// skip 'count' times past current buffer
iter.cycle().skip_while(|id| *id != &current).nth(count)
}
Direction::Backward => {
let iter = editor.documents.keys();
let mut iter = iter.rev().skip_while(|id| *id != &current);
iter.next(); // skip current item
iter.next().or_else(|| editor.documents.keys().next_back())
// skip 'count' times past current buffer
iter.rev()
.cycle()
.skip_while(|id| *id != &current)
.nth(count)
}
}
.unwrap();
@ -5435,6 +5436,7 @@ fn select_textobject(cx: &mut Context, objtype: textobject::TextObject) {
("T", "Test (tree-sitter)"),
("e", "Data structure entry (tree-sitter)"),
("m", "Closest surrounding pair"),
("g", "Change"),
(" ", "... or any character acting as a pair"),
];

@ -1,4 +1,5 @@
use std::fmt::Write;
use std::io::BufReader;
use std::ops::Deref;
use crate::job::Job;
@ -8,7 +9,7 @@ use super::*;
use helix_core::fuzzy::fuzzy_match;
use helix_core::indent::MAX_INDENT;
use helix_core::{line_ending, shellwords::Shellwords};
use helix_view::document::DEFAULT_LANGUAGE_NAME;
use helix_view::document::{read_to_string, DEFAULT_LANGUAGE_NAME};
use helix_view::editor::{CloseError, ConfigEvent};
use serde_json::Value;
use ui::completers::{self, Completer};
@ -309,7 +310,7 @@ fn buffer_next(
return Ok(());
}
goto_buffer(cx.editor, Direction::Forward);
goto_buffer(cx.editor, Direction::Forward, 1);
Ok(())
}
@ -322,7 +323,7 @@ fn buffer_previous(
return Ok(());
}
goto_buffer(cx.editor, Direction::Backward);
goto_buffer(cx.editor, Direction::Backward, 1);
Ok(())
}
@ -2454,6 +2455,39 @@ fn yank_diagnostic(
Ok(())
}
fn read(cx: &mut compositor::Context, args: &[Cow<str>], event: PromptEvent) -> anyhow::Result<()> {
if event != PromptEvent::Validate {
return Ok(());
}
let scrolloff = cx.editor.config().scrolloff;
let (view, doc) = current!(cx.editor);
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 path = PathBuf::from(filename.to_string());
ensure!(
path.exists() && path.is_file(),
"path is not a file: {:?}",
path
);
let file = std::fs::File::open(path).map_err(|err| anyhow!("error opening file: {}", err))?;
let mut reader = BufReader::new(file);
let (contents, _, _) = read_to_string(&mut reader, Some(doc.encoding()))
.map_err(|err| anyhow!("error reading file: {}", err))?;
let contents = Tendril::from(contents);
let selection = doc.selection(view.id);
let transaction = Transaction::insert(doc.text(), selection, contents);
doc.apply(&transaction, view.id);
doc.append_changes_to_history(view);
view.ensure_cursor_in_view(doc, scrolloff);
Ok(())
}
pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[
TypableCommand {
name: "quit",
@ -3068,6 +3102,13 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[
fun: yank_diagnostic,
signature: CommandSignature::all(completers::register),
},
TypableCommand {
name: "read",
aliases: &["r"],
doc: "Load a file into buffer",
fun: read,
signature: CommandSignature::positional(&[completers::filename]),
},
];
pub static TYPABLE_COMMAND_MAP: Lazy<HashMap<&'static str, &'static TypableCommand>> =

@ -5,7 +5,7 @@ use helix_core::syntax::LanguageServerFeature;
use helix_event::{
cancelable_future, cancelation, register_hook, send_blocking, CancelRx, CancelTx,
};
use helix_lsp::lsp;
use helix_lsp::lsp::{self, SignatureInformation};
use helix_stdx::rope::RopeSliceExt;
use helix_view::document::Mode;
use helix_view::events::{DocumentDidChange, SelectionDidChange};
@ -18,7 +18,7 @@ use crate::commands::Open;
use crate::compositor::Compositor;
use crate::events::{OnModeSwitch, PostInsertChar};
use crate::handlers::Handlers;
use crate::ui::lsp::SignatureHelp;
use crate::ui::lsp::{Signature, SignatureHelp};
use crate::ui::Popup;
use crate::{job, ui};
@ -82,6 +82,7 @@ impl helix_event::AsyncHook for SignatureHelpHandler {
}
}
self.state = if open { State::Open } else { State::Closed };
return timeout;
}
}
@ -138,6 +139,31 @@ pub fn request_signature_help(
});
}
fn active_param_range(
signature: &SignatureInformation,
response_active_parameter: Option<u32>,
) -> Option<(usize, usize)> {
let param_idx = signature
.active_parameter
.or(response_active_parameter)
.unwrap_or(0) as usize;
let param = signature.parameters.as_ref()?.get(param_idx)?;
match &param.label {
lsp::ParameterLabel::Simple(string) => {
let start = signature.label.find(string.as_str())?;
Some((start, start + string.len()))
}
lsp::ParameterLabel::LabelOffsets([start, end]) => {
// LS sends offsets based on utf-16 based string representation
// but highlighting in helix is done using byte offset.
use helix_core::str_utils::char_to_byte_idx;
let from = char_to_byte_idx(&signature.label, *start as usize);
let to = char_to_byte_idx(&signature.label, *end as usize);
Some((from, to))
}
}
}
pub fn show_signature_help(
editor: &mut Editor,
compositor: &mut Compositor,
@ -184,54 +210,50 @@ pub fn show_signature_help(
let doc = doc!(editor);
let language = doc.language_name().unwrap_or("");
let signature = match response
if response.signatures.is_empty() {
return;
}
let signatures: Vec<Signature> = response
.signatures
.get(response.active_signature.unwrap_or(0) as usize)
{
Some(s) => s,
None => return,
};
let mut contents = SignatureHelp::new(
signature.label.clone(),
language.to_string(),
Arc::clone(&editor.syn_loader),
);
.into_iter()
.map(|s| {
let active_param_range = active_param_range(&s, response.active_parameter);
let signature_doc = if config.lsp.display_signature_help_docs {
signature.documentation.as_ref().map(|doc| match doc {
lsp::Documentation::String(s) => s.clone(),
lsp::Documentation::MarkupContent(markup) => markup.value.clone(),
s.documentation.map(|doc| match doc {
lsp::Documentation::String(s) => s,
lsp::Documentation::MarkupContent(markup) => markup.value,
})
} else {
None
};
contents.set_signature_doc(signature_doc);
let active_param_range = || -> Option<(usize, usize)> {
let param_idx = signature
.active_parameter
.or(response.active_parameter)
.unwrap_or(0) as usize;
let param = signature.parameters.as_ref()?.get(param_idx)?;
match &param.label {
lsp::ParameterLabel::Simple(string) => {
let start = signature.label.find(string.as_str())?;
Some((start, start + string.len()))
}
lsp::ParameterLabel::LabelOffsets([start, end]) => {
// LS sends offsets based on utf-16 based string representation
// but highlighting in helix is done using byte offset.
use helix_core::str_utils::char_to_byte_idx;
let from = char_to_byte_idx(&signature.label, *start as usize);
let to = char_to_byte_idx(&signature.label, *end as usize);
Some((from, to))
Signature {
signature: s.label,
signature_doc,
active_param_range,
}
}
};
contents.set_active_param_range(active_param_range());
})
.collect();
let old_popup = compositor.find_id::<Popup<SignatureHelp>>(SignatureHelp::ID);
let mut active_signature = old_popup
.as_ref()
.map(|popup| popup.contents().active_signature())
.unwrap_or_else(|| response.active_signature.unwrap_or_default() as usize);
if active_signature >= signatures.len() {
active_signature = signatures.len() - 1;
}
let contents = SignatureHelp::new(
language.to_string(),
Arc::clone(&editor.syn_loader),
active_signature,
signatures,
);
let mut popup = Popup::new(SignatureHelp::ID, contents)
.position(old_popup.and_then(|p| p.get_position()))
.position_bias(Open::Above)

@ -3,60 +3,95 @@ use std::sync::Arc;
use arc_swap::ArcSwap;
use helix_core::syntax;
use helix_view::graphics::{Margin, Rect, Style};
use helix_view::input::Event;
use tui::buffer::Buffer;
use tui::layout::Alignment;
use tui::text::Text;
use tui::widgets::{BorderType, Paragraph, Widget, Wrap};
use crate::compositor::{Component, Compositor, Context};
use crate::compositor::{Component, Compositor, Context, EventResult};
use crate::alt;
use crate::ui::Markdown;
use super::Popup;
pub struct SignatureHelp {
signature: String,
signature_doc: Option<String>,
pub struct Signature {
pub signature: String,
pub signature_doc: Option<String>,
/// Part of signature text
active_param_range: Option<(usize, usize)>,
pub active_param_range: Option<(usize, usize)>,
}
pub struct SignatureHelp {
language: String,
config_loader: Arc<ArcSwap<syntax::Loader>>,
active_signature: usize,
signatures: Vec<Signature>,
}
impl SignatureHelp {
pub const ID: &'static str = "signature-help";
pub fn new(
signature: String,
language: String,
config_loader: Arc<ArcSwap<syntax::Loader>>,
active_signature: usize,
signatures: Vec<Signature>,
) -> Self {
Self {
signature,
signature_doc: None,
active_param_range: None,
language,
config_loader,
active_signature,
signatures,
}
}
pub fn set_signature_doc(&mut self, signature_doc: Option<String>) {
self.signature_doc = signature_doc;
}
pub fn set_active_param_range(&mut self, offset: Option<(usize, usize)>) {
self.active_param_range = offset;
pub fn active_signature(&self) -> usize {
self.active_signature
}
pub fn visible_popup(compositor: &mut Compositor) -> Option<&mut Popup<Self>> {
compositor.find_id::<Popup<Self>>(Self::ID)
}
fn signature_index(&self) -> String {
format!("({}/{})", self.active_signature + 1, self.signatures.len())
}
}
impl Component for SignatureHelp {
fn handle_event(&mut self, event: &Event, _cx: &mut Context) -> EventResult {
let Event::Key(event) = event else {
return EventResult::Ignored(None);
};
if self.signatures.len() <= 1 {
return EventResult::Ignored(None);
}
match event {
alt!('p') => {
self.active_signature = self
.active_signature
.checked_sub(1)
.unwrap_or(self.signatures.len() - 1);
EventResult::Consumed(None)
}
alt!('n') => {
self.active_signature = (self.active_signature + 1) % self.signatures.len();
EventResult::Consumed(None)
}
_ => EventResult::Ignored(None),
}
}
fn render(&mut self, area: Rect, surface: &mut Buffer, cx: &mut Context) {
let margin = Margin::horizontal(1);
let active_param_span = self.active_param_range.map(|(start, end)| {
let signature = &self.signatures[self.active_signature];
let active_param_span = signature.active_param_range.map(|(start, end)| {
vec![(
cx.editor
.theme
@ -66,21 +101,29 @@ impl Component for SignatureHelp {
)]
});
let sig = &self.signatures[self.active_signature];
let sig_text = crate::ui::markdown::highlighted_code_block(
&self.signature,
sig.signature.as_str(),
&self.language,
Some(&cx.editor.theme),
Arc::clone(&self.config_loader),
active_param_span,
);
if self.signatures.len() > 1 {
let signature_index = self.signature_index();
let text = Text::from(signature_index);
let paragraph = Paragraph::new(&text).alignment(Alignment::Right);
paragraph.render(area.clip_top(1).with_height(1).clip_right(1), surface);
}
let (_, sig_text_height) = crate::ui::text::required_size(&sig_text, area.width);
let sig_text_area = area.clip_top(1).with_height(sig_text_height);
let sig_text_area = sig_text_area.inner(&margin).intersection(surface.area);
let sig_text_para = Paragraph::new(&sig_text).wrap(Wrap { trim: false });
sig_text_para.render(sig_text_area, surface);
if self.signature_doc.is_none() {
if sig.signature_doc.is_none() {
return;
}
@ -92,7 +135,7 @@ impl Component for SignatureHelp {
}
}
let sig_doc = match &self.signature_doc {
let sig_doc = match &sig.signature_doc {
None => return,
Some(doc) => Markdown::new(doc.clone(), Arc::clone(&self.config_loader)),
};
@ -110,13 +153,15 @@ impl Component for SignatureHelp {
const PADDING: u16 = 2;
const SEPARATOR_HEIGHT: u16 = 1;
let sig = &self.signatures[self.active_signature];
if PADDING >= viewport.1 || PADDING >= viewport.0 {
return None;
}
let max_text_width = (viewport.0 - PADDING).min(120);
let signature_text = crate::ui::markdown::highlighted_code_block(
&self.signature,
sig.signature.as_str(),
&self.language,
None,
Arc::clone(&self.config_loader),
@ -125,7 +170,7 @@ impl Component for SignatureHelp {
let (sig_width, sig_height) =
crate::ui::text::required_size(&signature_text, max_text_width);
let (width, height) = match self.signature_doc {
let (width, height) = match sig.signature_doc {
Some(ref doc) => {
let doc_md = Markdown::new(doc.clone(), Arc::clone(&self.config_loader));
let doc_text = doc_md.parse(None);
@ -139,6 +184,12 @@ impl Component for SignatureHelp {
None => (sig_width, sig_height),
};
Some((width + PADDING, height + PADDING))
let sig_index_width = if self.signatures.len() > 1 {
self.signature_index().len() + 1
} else {
0
};
Some((width + PADDING + sig_index_width as u16, height + PADDING))
}
}

@ -640,3 +640,27 @@ async fn test_join_selections_space() -> anyhow::Result<()> {
Ok(())
}
#[tokio::test(flavor = "multi_thread")]
async fn test_read_file() -> anyhow::Result<()> {
let mut file = tempfile::NamedTempFile::new()?;
let contents_to_read = "some contents";
let output_file = helpers::temp_file_with_contents(contents_to_read)?;
test_key_sequence(
&mut helpers::AppBuilder::new()
.with_file(file.path(), None)
.build()?,
Some(&format!(":r {:?}<ret><esc>:w<ret>", output_file.path())),
Some(&|app| {
assert!(!app.editor.is_err(), "error: {:?}", app.editor.get_status());
}),
false,
)
.await?;
let expected_contents = LineFeedHandling::Native.apply(contents_to_read);
helpers::assert_file_has_content(&mut file, &expected_contents)?;
Ok(())
}

@ -19,7 +19,7 @@ tokio = { version = "1", features = ["rt", "rt-multi-thread", "time", "sync", "p
parking_lot = "0.12"
arc-swap = { version = "1.7.1" }
gix = { version = "0.61.0", features = ["attributes", "status"], default-features = false, optional = true }
gix = { version = "0.62.0", features = ["attributes", "status"], default-features = false, optional = true }
imara-diff = "0.1.5"
anyhow = "1"

@ -102,6 +102,7 @@ yaml-language-server = { command = "yaml-language-server", args = ["--stdio"] }
zls = { command = "zls" }
blueprint-compiler = { command = "blueprint-compiler", args = ["lsp"] }
typst-lsp = { command = "typst-lsp" }
tinymist = { command = "tinymist" }
pkgbuild-language-server = { command = "pkgbuild-language-server" }
helm_ls = { command = "helm_ls", args = ["serve"] }
ember-language-server = { command = "ember-language-server", args = ["--stdio"] }
@ -201,6 +202,7 @@ scope = "source.rust"
injection-regex = "rust"
file-types = ["rs"]
roots = ["Cargo.toml", "Cargo.lock"]
shebangs = ["rust-script", "cargo"]
auto-format = true
comment-tokens = ["//", "///", "//!"]
block-comment-tokens = [
@ -250,7 +252,7 @@ args = { attachCommands = [ "platform select remote-gdb-server", "platform conne
[[grammar]]
name = "rust"
source = { git = "https://github.com/tree-sitter/tree-sitter-rust", rev = "0431a2c60828731f27491ee9fdefe25e250ce9c9" }
source = { git = "https://github.com/tree-sitter/tree-sitter-rust", rev = "473634230435c18033384bebaa6d6a17c2523281" }
[[language]]
name = "sway"
@ -2052,6 +2054,29 @@ block-comment-tokens = { start = "/*", end = "*/" }
indent = { tab-width = 4, unit = "\t" }
formatter = { command = "odinfmt", args = [ "-stdin", "true" ] }
[language.debugger]
name = "lldb-dap"
transport = "stdio"
command = "lldb-dap"
[[language.debugger.templates]]
name = "binary"
request = "launch"
completion = [ { name = "binary", completion = "filename" } ]
args = { console = "internalConsole", program = "{0}" }
[[language.debugger.templates]]
name = "attach"
request = "attach"
completion = [ "pid" ]
args = { console = "internalConsole", pid = "{0}" }
[[language.debugger.templates]]
name = "gdbserver attach"
request = "attach"
completion = [ { name = "lldb connect url", default = "connect://localhost:3333" }, { name = "file", completion = "filename" }, "pid" ]
args = { console = "internalConsole", attachCommands = [ "platform select remote-gdb-server", "platform connect {0}", "file {1}", "attach {2}" ] }
[[grammar]]
name = "odin"
source = { git = "https://github.com/ap29600/tree-sitter-odin", rev = "b219207e49ffca2952529d33e94ed63b1b75c4f1" }
@ -3071,7 +3096,7 @@ scope = "source.typst"
injection-regex = "typst"
file-types = ["typst", "typ"]
comment-token = "//"
language-servers = ["typst-lsp"]
language-servers = ["tinymist", "typst-lsp"]
indent = { tab-width = 2, unit = " " }
[language.auto-pairs]
@ -3083,7 +3108,7 @@ indent = { tab-width = 2, unit = " " }
[[grammar]]
name = "typst"
source = { git = "https://github.com/uben0/tree-sitter-typst", rev = "ecf8596336857adfcd5f7cbb3b2aa11a67badc37" }
source = { git = "https://github.com/uben0/tree-sitter-typst", rev = "13863ddcbaa7b68ee6221cea2e3143415e64aea4" }
[[language]]
name = "nunjucks"
@ -3366,7 +3391,7 @@ source = { git = "https://github.com/mtoohey31/tree-sitter-ld", rev = "0e9695ae0
name = "hyprlang"
scope = "source.hyprlang"
roots = ["hyprland.conf"]
file-types = [ { glob = "hyprland.conf"} ]
file-types = [ { glob = "hyprland.conf" }, { glob = "hyprpaper.conf" }, { glob = "hypridle.conf" }, { glob = "hyprlock.conf" } ]
comment-token = "#"
grammar = "hyprlang"
@ -3478,7 +3503,7 @@ language-servers = ["earthlyls"]
[[grammar]]
name = "earthfile"
source = { git = "https://github.com/glehmann/tree-sitter-earthfile", rev = "2a6ab191f5f962562e495a818aa4e7f45f8a556a" }
source = { git = "https://github.com/glehmann/tree-sitter-earthfile", rev = "a079e6c472eeedd6b9a1e03ca0b6c82cd6a112a4" }
[[language]]
name = "adl"
@ -3508,3 +3533,28 @@ comment-token = "#"
[[grammar]]
name = "ldif"
source = { git = "https://github.com/kepet19/tree-sitter-ldif", rev = "0a917207f65ba3e3acfa9cda16142ee39c4c1aaa" }
[[language]]
name = "xtc"
scope = "source.xtc"
# Accept Xena Traffic Configuration, Xena Port Configuration and Xena OpenAutomation
file-types = [ "xtc", "xpc", "xoa" ]
comment-token = ";"
[[grammar]]
name = "xtc"
source = { git = "https://github.com/Alexis-Lapierre/tree-sitter-xtc", rev = "7bc11b736250c45e25cfb0215db2f8393779957e" }
[[language]]
name = "move"
scope = "source.move"
injection-regex = "move"
roots = ["Move.toml"]
file-types = ["move"]
comment-token = "//"
indent = { tab-width = 4, unit = " " }
language-servers = []
[[grammar]]
name = "move"
source = { git = "https://github.com/tzakian/tree-sitter-move", rev = "8bc0d1692caa8763fef54d48068238d9bf3c0264" }

@ -1,42 +1,48 @@
(string_array "," @punctuation.delimiter)
(string_array ["[" "]"] @punctuation.bracket)
(arg_command "ARG" @keyword)
(build_command "BUILD" @keyword)
(cache_command "CACHE" @keyword)
(cmd_command "CMD" @keyword)
(copy_command "COPY" @keyword)
(do_command "DO" @keyword)
(entrypoint_command "ENTRYPOINT" @keyword)
(env_command "ENV" @keyword)
(expose_command "EXPOSE" @keyword)
(from_command "FROM" @keyword)
(from_dockerfile_command "FROM DOCKERFILE" @keyword)
(function_command "FUNCTION" @keyword)
(git_clone_command "GIT CLONE" @keyword)
(host_command "HOST" @keyword)
(import_command "IMPORT" @keyword)
(label_command "LABEL" @keyword)
(let_command "LET" @keyword)
(project_command "PROJECT" @keyword)
(run_command "RUN" @keyword)
(save_artifact_command ["SAVE ARTIFACT" "AS LOCAL"] @keyword)
(save_image_command "SAVE IMAGE" @keyword)
(set_command "SET" @keyword)
(user_command "USER" @keyword)
(version_command "VERSION" @keyword)
(volume_command "VOLUME" @keyword)
(with_docker_command "WITH DOCKER" @keyword)
(workdir_command "WORKDIR" @keyword)
[
"ARG"
"AS LOCAL"
"BUILD"
"CACHE"
"CMD"
"COPY"
"DO"
"ENTRYPOINT"
"ENV"
"EXPOSE"
"FROM DOCKERFILE"
"FROM"
"FUNCTION"
"GIT CLONE"
"HOST"
"IMPORT"
"LABEL"
"LET"
"PROJECT"
"RUN"
"SAVE ARTIFACT"
"SAVE IMAGE"
"SET"
"USER"
"VERSION"
"VOLUME"
"WORKDIR"
] @keyword
(for_command ["FOR" "IN" "END"] @keyword.control.repeat)
(if_command ["IF" "END"] @keyword.control.conditional)
(elif_block ["ELSE IF"] @keyword.control.conditional)
(else_block ["ELSE"] @keyword.control.conditional)
(import_command ["IMPORT" "AS"] @keyword.control.import)
(try_command ["TRY" "FINALLY" "END"] @keyword.control.exception)
(wait_command ["WAIT" "END"] @keyword.control)
(wait_command ["WAIT" "END"] @keyword.control)
(with_docker_command ["WITH DOCKER" "END"] @keyword.control)
[
(comment)
@ -65,10 +71,4 @@
(build_arg) @variable
(options (_) @variable.parameter)
(options (_ "=" @operator))
(build_arg "=" @operator)
(arg_command "=" @operator)
(env_command "=" @operator)
(label "=" @operator)
(set_command "=" @operator)
(let_command "=" @operator)
"=" @operator

@ -0,0 +1,157 @@
(ability) @keyword
; ---
; Primitives
; ---
(address_literal) @constant
(bool_literal) @constant.builtin.boolean
(num_literal) @constant.numeric
[
(hex_string_literal)
(byte_string_literal)
] @string
; TODO: vector_literal
[
(line_comment)
(block_comment)
] @comment
(annotation) @function.macro
(borrow_expression "&" @keyword.storage.modifier.ref)
(borrow_expression "&mut" @keyword.storage.modifier.mut)
(constant_identifier) @constant
((identifier) @constant
(#match? @constant "^[A-Z][A-Z\\d_]*$"))
(function_identifier) @function
(struct_identifier) @type
(pack_expression
access: (module_access
member: (identifier) @type))
(apply_type
(module_access
member: (identifier) @type))
(field_identifier) @variable.other.member
; -------
; Functions
; -------
(call_expression
access: (module_access
member: (identifier) @function))
(macro_call_expression
access: (macro_module_access
access: (module_access
member: [(identifier) @function.macro])
"!" @function.macro))
; -------
; Paths
; -------
(module_identifier) @namespace
; -------
; Operators
; -------
[
"*"
"="
"!"
] @operator
(binary_operator) @operator
; ---
; Punctuation
; ---
[
"::"
"."
";"
","
] @punctuation.delimiter
[
"("
")"
"["
"]"
"{"
"}"
] @punctuation.bracket
[
"abort"
; "acquires"
"as"
"break"
"const"
"continue"
"copy"
"else"
"false"
"friend"
"fun"
"has"
"if"
; "invariant"
"let"
"loop"
"module"
"move"
"native"
"public"
"return"
; "script"
"spec"
"struct"
"true"
"use"
"while"
"entry"
; "aborts_if"
; "aborts_with"
"address"
"apply"
"assume"
; "axiom"
; "choose"
"decreases"
; "emits"
"ensures"
"except"
; "forall"
"global"
"include"
"internal"
"local"
; "min"
; "modifies"
"mut"
"phantom"
"post"
"pragma"
; "requires"
; "Self"
"schema"
"succeeds_if"
"to"
; "update"
"where"
"with"
] @keyword
(primitive_type) @type.buildin
(identifier) @variable

@ -51,7 +51,7 @@
(lifetime
"'" @label
(identifier) @label)
(loop_label
(label
"'" @label
(identifier) @label)

@ -1,6 +1,11 @@
; Special identifiers
;--------------------
(tag_name) @tag
(attribute_name) @variable.other.member
(erroneous_end_tag_name) @error
(comment) @comment
; TODO:
((element (start_tag (tag_name) @_tag) (text) @markup.heading)
(#match? @_tag "^(h[0-9]|title)$"))
@ -28,11 +33,6 @@
(quoted_attribute_value (attribute_value) @markup.link.url))
(#match? @_attr "^(href|src)$"))
(tag_name) @tag
(attribute_name) @variable.other.member
(erroneous_end_tag_name) @error
(comment) @comment
[
(attribute_value)
(quoted_attribute_value)

@ -21,6 +21,7 @@
; OPERATOR
(in ["in" "not"] @keyword.operator)
(context "context" @keyword.control)
(and "and" @keyword.operator)
(or "or" @keyword.operator)
(not "not" @keyword.operator)
@ -45,12 +46,9 @@
(string) @string
(content ["[" "]"] @operator)
(bool) @constant.builtin.boolean
(builtin) @constant.builtin
(none) @constant.builtin
(auto) @constant.builtin
(ident) @variable
(call
item: (builtin) @function.builtin)
; MARKUP
(item "-" @markup.list)

@ -0,0 +1,27 @@
(parameter) @keyword
(change_port) @function.special
(template) @variable
[
(hex_argument)
(ipv4_argument)
] @attribute
(numeric_argument) @constant.numeric
(index) @tag
(string_literal_argument) @string
(string_argument) @constant.character
(comment) @comment
(port_comment) @label
[
("[")
("]")
] @punctuation.bracket

@ -3,6 +3,7 @@
"ui.background" = { bg = "base00" }
"ui.virtual.whitespace" = "base03"
"ui.virtual.jump-label" = { fg = "blue", modifiers = ["bold", "underlined"] }
"ui.virtual.ruler" = { bg = "base01" }
"ui.menu" = { fg = "base05", bg = "base01" }
"ui.menu.selected" = { fg = "base01", bg = "base04" }
"ui.linenr" = { fg = "base03", bg = "base01" }

@ -14,6 +14,7 @@
"ui.cursor.primary" = { fg = "base05", modifiers = ["reversed"] }
"ui.virtual.whitespace" = "base03"
"ui.virtual.jump-label" = { fg = "blue", modifiers = ["bold", "underlined"] }
"ui.virtual.ruler" = { bg = "base01" }
"ui.text" = "base05"
"operator" = "base05"
"ui.text.focus" = "base05"

@ -15,6 +15,7 @@
"ui.cursor.primary" = { fg = "light-gray", modifiers = ["reversed"] }
"ui.virtual.whitespace" = "light-gray"
"ui.virtual.jump-label" = { fg = "blue", modifiers = ["bold", "underlined"] }
"ui.virtual.ruler" = { bg = "black" }
"variable" = "light-red"
"constant.numeric" = "yellow"
"constant" = "yellow"

@ -4,15 +4,19 @@ constant = "purple"
"constant.numeric" = "orange"
"constant.builtin" = "orange"
variable = "red"
attribute = "brown"
comment = "light-gray"
special = "purple"
"punctuation" = "red"
"punctuation.bracket" = "purple"
"punctuation.delimiter" = "white"
keyword = "purple"
function = "blue"
label = "orange"
type = "orange"
constructor = "orange"
namespace = "orange"
tag = "red"
# User Interface
"ui.background" = { bg = "bg", fg = "gray" }
@ -29,6 +33,7 @@ namespace = "orange"
"ui.selection" = { bg = "selection" }
"ui.virtual.indent-guide" = { fg = "gray" }
"ui.virtual.whitespace" = { fg = "light-gray" }
"ui.virtual.ruler" = { bg ="dark-bg" }
"ui.statusline" = { bg = "dark-bg", fg = "light-gray" }
"ui.popup" = { bg = "dark-bg", fg = "orange" }
"ui.help" = { bg = "dark-bg", fg = "orange" }
@ -79,6 +84,7 @@ pink = "#EE64AE"
selection = "#353747"
green = "#27D796"
orange = "#FAB795"
brown = "#F09383"
purple = "#B877DB"
red = "#E95678"
blue = "#25B2BC"

@ -8,7 +8,7 @@
## User interface
"ui.selection" = { bg = "waveBlue2" }
"ui.selection.primary" = { bg = "sumiInk5" }
"ui.selection.primary" = { bg = "waveBlue2" }
"ui.background" = { fg = "fujiWhite", bg = "sumiInk1" }
"ui.linenr" = { fg = "sumiInk4" }
@ -123,7 +123,6 @@ sumiInk1 = "#1F1F28" # default background
sumiInk2 = "#2A2A37" # lighter background, e.g. colorcolumns, folds
sumiInk3 = "#363646" # lighter background, e.g. cursorline
sumiInk4 = "#54546D" # darker foreground, e.g. linenumbers, fold column
sumiInk5 = "#363646" # current selection
waveBlue1 = "#223249" # popup background, visual selection background
waveBlue2 = "#2D4F67" # popup selection background, search background
winterGreen = "#2B3328" # diff add background

@ -79,6 +79,7 @@
"ui.text.focus" = { fg = "fg" }
"ui.virtual" = { fg = "gray02" }
"ui.virtual.ruler" = { bg ="gray02" }
"ui.virtual.indent-guide" = { fg = "gray02" }
"ui.virtual.inlay-hint" = { fg = "gray04" }

@ -58,6 +58,7 @@ string = { fg = "brightMint" }
"ui.text.inactive" = "darkerGray"
"ui.virtual" = { fg = "darkerGray.b0" }
"ui.virtual.indent-guide" = "#303442"
"ui.virtual.ruler" = { bg ="selection" }
"ui.selection" = { bg = "focus" }
"ui.selection.primary" = { bg = "selection" }

@ -90,7 +90,7 @@
"ui.selection.primary" = { bg = "base015" }
"ui.virtual.indent-guide" = { fg = "base02" }
"ui.virtual.ruler" = { fg = "red" }
"ui.virtual.ruler" = { bg = "base02" }
# normal模式的光标
"ui.cursor" = {fg = "base02", bg = "cyan"}

@ -91,9 +91,6 @@
# 影响 picker列表选中, 快捷键帮助窗口文本
# Affects picker list selection, shortcut key help window text
"ui.text.focus" = { fg = "blue", modifiers = ["bold"]}
# file picker中 预览的当前选中项
# In file picker, the currently selected item of the preview
"ui.highlight" = { fg = "red", modifiers = ["bold", "italic", "underlined"] }
# 主光标/selection
# main cursor/selection
@ -107,7 +104,7 @@
"ui.selection.primary" = { bg = "base015" }
"ui.virtual.indent-guide" = { fg = "base02" }
"ui.virtual.ruler" = { fg = "red" }
"ui.virtual.ruler" = { bg = "base02" }
# normal模式的光标
# normal mode cursor

@ -67,6 +67,7 @@
"ui.statusline.select" = { bg = "blue", fg = "bg2" }
"ui.virtual.wrap" = { fg = "grey0" }
"ui.virtual.inlay-hint" = { fg = "grey1" }
"ui.virtual.ruler" = { bg = "bg2"}
"hint" = "blue"
"info" = "aqua"

@ -1,7 +1,10 @@
"ui.background" = { bg = "black" }
"ui.bufferline" = { bg = "black" }
"ui.bufferline.active" = { fg = "light-magenta", bg = "dark-magenta" }
"ui.cursor" = { fg = "green", modifiers = ["reversed"] }
"ui.cursor.match" = { fg = "light-cyan", bg = "dark-cyan" }
"ui.cursor.primary" = { fg = "light-green", modifiers = ["reversed"] }
"ui.cursorline.primary" = { bg = "gray" }
"ui.menu" = { bg = "dark-white" }
"ui.menu.selected" = { fg = "yellow" }
"ui.popup" = { bg = "dark-white" }
@ -15,6 +18,7 @@
"ui.text.focus" = { fg = "yellow" }
"ui.virtual.wrap" = { fg = "dark-blue" }
"ui.virtual.indent-guide" = { fg = "dark-blue" }
"ui.virtual.ruler" = { bg = "dark-white" }
"ui.window" = { bg = "dark-white" }
"diagnostic.error" = { bg = "dark-red" }
@ -50,6 +54,7 @@
black = "#000000"
red = "#ed5f74"
green = "#1ea672"
gray = "#111111"
yellow = "#d97917"
blue = "#688ef1"
magenta = "#c96ed0"

@ -539,7 +539,7 @@
will now affect both cursors.
3. Use Insert mode to correct the lines. The two cursors will
fix both lines simultaneously.
4. Type , to remove the second cursor.
4. Type , to remove the first cursor.
--> Fix th two nes at same ime.
-->

@ -40,7 +40,7 @@ label = "honey"
"diff.minus" = "#f22c86"
"diff.delta" = "#6f44f0"
# TODO: diferentiate doc comment
# TODO: differentiate doc comment
# concat (ERROR) @error.syntax and "MISSING ;" selectors for errors
"ui.background" = { bg = "midnight" }
@ -56,6 +56,7 @@ label = "honey"
"ui.text.focus" = { fg = "white" }
"ui.text.inactive" = "sirocco"
"ui.virtual" = { fg = "comet" }
"ui.virtual.ruler" = { bg = "revolver" }
"ui.virtual.jump-label" = { fg = "apricot", modifiers = ["bold"] }
"ui.virtual.indent-guide" = { fg = "comet" }

Loading…
Cancel
Save