Merge branch 'helix-editor:master' into master

This commit is contained in:
Vadim 2024-04-19 01:55:13 +03:00 committed by GitHub
commit b792676400
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
32 changed files with 574 additions and 180 deletions

69
Cargo.lock generated
View File

@ -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",

View File

@ -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"

View File

@ -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` |

View File

@ -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 |

View File

@ -24,6 +24,8 @@ # Keymap
> 💡 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.

View File

@ -2765,10 +2765,10 @@ fn test_textobject_queries() {
)
};
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 @@ fn assert_pretty_print(
#[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 @@ fn test_pretty_print() {
" (macro_invocation\n",
" macro: (identifier)\n",
" (token_tree\n",
" (string_literal))))))",
" (string_literal\n",
" (string_content)))))))",
),
0,
source.len(),

View File

@ -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"),
];

View File

@ -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 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 @@ fn yank_diagnostic(
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>> =

View File

@ -5,7 +5,7 @@
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::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 @@ fn handle_event(
}
}
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(),
let signature_doc = if config.lsp.display_signature_help_docs {
s.documentation.map(|doc| match doc {
lsp::Documentation::String(s) => s,
lsp::Documentation::MarkupContent(markup) => markup.value,
})
} else {
None
};
Signature {
signature: s.label,
signature_doc,
active_param_range,
}
})
} 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))
}
}
};
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)

View File

@ -3,60 +3,95 @@
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 @@ fn render(&mut self, area: Rect, surface: &mut Buffer, cx: &mut Context) {
)]
});
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 @@ fn render(&mut self, area: Rect, surface: &mut Buffer, cx: &mut Context) {
}
}
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 @@ 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];
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 @@ 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 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 @@ fn required_size(&mut self, viewport: (u16, u16)) -> Option<(u16, u16)> {
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))
}
}

View File

@ -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(())
}

View File

@ -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"

View File

@ -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" }

View File

@ -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)
(import_command ["IMPORT" "AS"] @keyword.control.import)
(try_command ["TRY" "FINALLY" "END"] @keyword.control.exception)
(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

View File

@ -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

View File

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

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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" }

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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

View File

@ -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" }

View File

@ -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" }

View File

@ -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"}

View File

@ -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

View File

@ -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"

View File

@ -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"

View File

@ -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.
-->

View File

@ -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" }