Merge branch 'helix-editor:master' into command-expansion

pull/11164/head
Théo Daron 5 months ago
commit 0d97406257

71
Cargo.lock generated

@ -136,9 +136,9 @@ checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53"
[[package]]
name = "cc"
version = "1.0.100"
version = "1.0.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c891175c3fb232128f48de6590095e59198bbeb8620c310be349bfc3afd12c7b"
checksum = "066fce287b1d4eafef758e89e09d724a24808a9196fe9756b8ca90e86d0719a2"
[[package]]
name = "cfg-if"
@ -171,9 +171,9 @@ dependencies = [
[[package]]
name = "clipboard-win"
version = "5.3.1"
version = "5.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79f4473f5144e20d9aceaf2972478f06ddf687831eafeeb434fbaf0acc4144ad"
checksum = "15efe7a882b08f34e38556b14f2fb3daa98769d06c7f0c1b076dfd0d983bc892"
dependencies = [
"error-code",
]
@ -351,6 +351,15 @@ dependencies = [
"parking_lot_core",
]
[[package]]
name = "deranged"
version = "0.3.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4"
dependencies = [
"powerfmt",
]
[[package]]
name = "dunce"
version = "1.0.4"
@ -1601,12 +1610,12 @@ dependencies = [
[[package]]
name = "imara-diff"
version = "0.1.5"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e98c1d0ad70fc91b8b9654b1f33db55e59579d3b3de2bffdced0fdb810570cb8"
checksum = "af13c8ceb376860ff0c6a66d83a8cdd4ecd9e464da24621bbffcd02b49619434"
dependencies = [
"ahash",
"hashbrown 0.12.3",
"hashbrown 0.14.5",
]
[[package]]
@ -1711,9 +1720,9 @@ dependencies = [
[[package]]
name = "log"
version = "0.4.21"
version = "0.4.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
[[package]]
name = "lsp-types"
@ -1795,6 +1804,12 @@ dependencies = [
"unicode-segmentation",
]
[[package]]
name = "num-conv"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
[[package]]
name = "num-traits"
version = "0.2.15"
@ -1840,9 +1855,9 @@ checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
[[package]]
name = "open"
version = "5.1.4"
version = "5.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5ca541f22b1c46d4bb9801014f234758ab4297e7870b904b6a8415b980a7388"
checksum = "9d2c909a3fce3bd80efef4cd1c6c056bd9376a8fe06fcfdbebaf32cb485a7e37"
dependencies = [
"is-wsl",
"libc",
@ -1896,6 +1911,12 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "powerfmt"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
[[package]]
name = "proc-macro2"
version = "1.0.76"
@ -2098,18 +2119,18 @@ checksum = "1792db035ce95be60c3f8853017b3999209281c24e2ba5bc8e59bf97a0c590c1"
[[package]]
name = "serde"
version = "1.0.203"
version = "1.0.204"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094"
checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.203"
version = "1.0.204"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba"
checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222"
dependencies = [
"proc-macro2",
"quote",
@ -2118,9 +2139,9 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.117"
version = "1.0.120"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3"
checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5"
dependencies = [
"itoa",
"ryu",
@ -2358,13 +2379,16 @@ dependencies = [
[[package]]
name = "time"
version = "0.3.23"
version = "0.3.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59e399c068f43a5d116fedaf73b203fa4f9c519f17e2b34f63221d3792f81446"
checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885"
dependencies = [
"deranged",
"itoa",
"libc",
"num-conv",
"num_threads",
"powerfmt",
"serde",
"time-core",
"time-macros",
@ -2372,16 +2396,17 @@ dependencies = [
[[package]]
name = "time-core"
version = "0.1.1"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb"
checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
[[package]]
name = "time-macros"
version = "0.2.10"
version = "0.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96ba15a897f3c86766b757e5ac7221554c6750054d74d5b28844fce5fb36a6c4"
checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf"
dependencies = [
"num-conv",
"time-core",
]

@ -47,7 +47,7 @@ Note: Only certain languages have indentation definitions at the moment. Check
[Installation documentation](https://docs.helix-editor.com/install.html).
[![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.svg?exclude_unsupported=1)](https://repology.org/project/helix/versions)
# Contributing

@ -148,6 +148,12 @@ provided `.desktop` and icon files to their correct folders:
cp contrib/Helix.desktop ~/.local/share/applications
cp contrib/helix.png ~/.icons # or ~/.local/share/icons
```
It is recommended to convert the links in the `.desktop` file to absolute paths to avoid potential problems:
```sh
sed -i -e "s|Exec=hx %F|Exec=$(readlink -f ~/.cargo/bin/hx) %F|g" \
-e "s|Icon=helix|Icon=$(readlink -f ~/.icons/helix.png)|g" ~/.local/share/applications/Helix.desktop
```
To use another terminal than the system default, you can modify the `.desktop`
file. For example, to use `kitty`:

@ -1,15 +1,18 @@
#!/usr/bin/env fish
# Fish completion script for Helix editor
set -l langs (hx --health |tail -n '+7' |awk '{print $1}' |sed 's/\x1b\[[0-9;]*m//g')
complete -c hx -s h -l help -d "Prints help information"
complete -c hx -l tutor -d "Loads the tutorial"
complete -c hx -l health -x -a "$langs" -d "Checks for errors in editor setup"
complete -c hx -s g -l grammar -x -a "fetch build" -d "Fetches or builds tree-sitter grammars"
complete -c hx -l health -xa "(__hx_langs_ops)" -d "Checks for errors"
complete -c hx -s g -l grammar -x -a "fetch build" -d "Fetch or build tree-sitter grammars"
complete -c hx -s v -o vv -o vvv -d "Increases logging verbosity"
complete -c hx -s V -l version -d "Prints version information"
complete -c hx -l vsplit -d "Splits all given files vertically into different windows"
complete -c hx -l hsplit -d "Splits all given files horizontally into different windows"
complete -c hx -s c -l config -r -d "Specifies a file to use for completion"
complete -c hx -l log -r -d "Specifies a file to write log data into"
complete -c hx -l vsplit -d "Splits all given files vertically"
complete -c hx -l hsplit -d "Splits all given files horizontally"
complete -c hx -s c -l config -r -d "Specifies a file to use for config"
complete -c hx -l log -r -d "Specifies a file to use for logging"
complete -c hx -s w -l working-dir -d "Specify initial working directory" -xa "(__fish_complete_directories)"
function __hx_langs_ops
hx --health languages | tail -n '+2' | string replace -fr '^(\S+) .*' '$1'
end

@ -14,16 +14,18 @@ _hx() {
"--health[Checks for errors in editor setup]:language:->health" \
"-g[Fetches or builds tree-sitter grammars]:action:->grammar" \
"--grammar[Fetches or builds tree-sitter grammars]:action:->grammar" \
"--vsplit[Splits all given files vertically into different windows]" \
"--hsplit[Splits all given files horizontally into different windows]" \
"--vsplit[Splits all given files vertically]" \
"--hsplit[Splits all given files horizontally]" \
"-c[Specifies a file to use for configuration]" \
"--config[Specifies a file to use for configuration]" \
"--log[Specifies a file to write log data into]" \
"-w[Specify initial working directory]" \
"--working-dir[Specify initial working directory]" \
"--log[Specifies a file to use for logging]" \
"*:file:_files"
case "$state" in
health)
local languages=($(hx --health |tail -n '+7' |awk '{print $1}' |sed 's/\x1b\[[0-9;]*m//g'))
local languages=($(hx --health | tail -n '+11' | awk '{print $1}' | sed 's/\x1b\[[0-9;]*m//g;s/[✘✓]//g'))
_values 'language' $languages
;;
grammar)
@ -31,4 +33,3 @@ _hx() {
;;
esac
}

@ -40,7 +40,7 @@ serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
toml = "0.8"
imara-diff = "0.1.0"
imara-diff = "0.1.6"
encoding_rs = "0.8"

@ -175,7 +175,7 @@ impl Range {
/// function runs in O(N) (N is number of changes) and can therefore
/// cause performance problems if run for a large number of ranges as the
/// complexity is then O(MN) (for multicuror M=N usually). Instead use
/// [Selection::map] or [ChangeSet::update_positions] instead
/// [Selection::map] or [ChangeSet::update_positions].
pub fn map(mut self, changes: &ChangeSet) -> Self {
use std::cmp::Ordering;
if changes.is_empty() {
@ -541,6 +541,8 @@ impl Selection {
}
/// Normalizes a `Selection`.
///
/// Ranges are sorted by [Range::from], with overlapping ranges merged.
fn normalize(mut self) -> Self {
if self.len() < 2 {
return self;

@ -157,8 +157,8 @@ impl Client {
)
}
pub fn starting_request_args(&self) -> &Option<Value> {
&self.starting_request_args
pub fn starting_request_args(&self) -> Option<&Value> {
self.starting_request_args.as_ref()
}
pub async fn tcp_process(

@ -422,7 +422,7 @@ fn build_tree_sitter_library(
}
}
let recompile = needs_recompile(&library_path, &parser_path, &scanner_path)
let recompile = needs_recompile(&library_path, &parser_path, scanner_path.as_ref())
.context("Failed to compare source and binary timestamps")?;
if !recompile {
@ -568,7 +568,7 @@ fn build_tree_sitter_library(
fn needs_recompile(
lib_path: &Path,
parser_c_path: &Path,
scanner_path: &Option<PathBuf>,
scanner_path: Option<&PathBuf>,
) -> Result<bool> {
if !lib_path.exists() {
return Ok(true);

@ -123,7 +123,7 @@ impl Client {
{
client.add_workspace_folder(
root_uri,
&workspace_folders_caps.change_notifications,
workspace_folders_caps.change_notifications.as_ref(),
);
}
});
@ -136,7 +136,10 @@ impl Client {
.and_then(|cap| cap.workspace_folders.as_ref())
.filter(|cap| cap.supported.unwrap_or(false))
{
self.add_workspace_folder(root_uri, &workspace_folders_caps.change_notifications);
self.add_workspace_folder(
root_uri,
workspace_folders_caps.change_notifications.as_ref(),
);
true
} else {
// the server doesn't support multi workspaces, we need a new client
@ -147,7 +150,7 @@ impl Client {
fn add_workspace_folder(
&self,
root_uri: Option<lsp::Url>,
change_notifications: &Option<OneOf<bool, String>>,
change_notifications: Option<&OneOf<bool, String>>,
) {
// root_uri is None just means that there isn't really any LSP workspace
// associated with this file. For servers that support multiple workspaces
@ -162,7 +165,7 @@ impl Client {
self.workspace_folders
.lock()
.push(workspace_for_uri(root_uri.clone()));
if &Some(OneOf::Left(false)) == change_notifications {
if Some(&OneOf::Left(false)) == change_notifications {
// server specifically opted out of DidWorkspaceChange notifications
// let's assume the server will request the workspace folders itself
// and that we can therefore reuse the client (but are done now)
@ -616,6 +619,9 @@ impl Client {
prepare_support_default_behavior: None,
honors_change_annotations: Some(false),
}),
formatting: Some(lsp::DocumentFormattingClientCapabilities {
dynamic_registration: Some(false),
}),
code_action: Some(lsp::CodeActionClientCapabilities {
code_action_literal_support: Some(lsp::CodeActionLiteralSupport {
code_action_kind: lsp::CodeActionKindLiteralSupport {

@ -58,7 +58,7 @@ pulldown-cmark = { version = "0.11", default-features = false }
content_inspector = "0.2.4"
# opening URLs
open = "5.1.4"
open = "5.2.0"
url = "2.5.2"
# config

@ -1210,19 +1210,15 @@ fn goto_file_impl(cx: &mut Context, action: Action) {
let (view, doc) = current_ref!(cx.editor);
let text = doc.text();
let selections = doc.selection(view.id);
let primary = selections.primary();
let rel_path = doc
.relative_path()
.map(|path| path.parent().unwrap().to_path_buf())
.unwrap_or_default();
let mut paths: Vec<_> = selections
.iter()
.map(|r| text.slice(r.from()..r.to()).to_string())
.collect();
let primary = selections.primary();
// Checks whether there is only one selection with a width of 1
if selections.len() == 1 && primary.len() == 1 {
paths.clear();
let paths: Vec<_> = if selections.len() == 1 && primary.len() == 1 {
// Secial case: if there is only one one-width selection, try to detect the
// path under the cursor.
let is_valid_path_char = |c: &char| {
#[cfg(target_os = "windows")]
let valid_chars = &[
@ -1257,29 +1253,29 @@ fn goto_file_impl(cx: &mut Context, action: Action) {
.take_while(is_valid_path_char)
.count();
let path: Cow<str> = text
let path: String = text
.slice((start_pos - prefix_len)..(start_pos + postfix_len))
.into();
log::debug!("Goto file path: {}", path);
log::debug!("goto_file auto-detected path: {}", path);
match expand_tilde(PathBuf::from(path.as_ref())).to_str() {
Some(path) => paths.push(path.to_string()),
None => cx.editor.set_error("Couldn't get string out of path."),
vec![path]
} else {
// Otherwise use each selection, trimmed.
selections
.fragments(text.slice(..))
.map(|sel| sel.trim().to_string())
.filter(|sel| !sel.is_empty())
.collect()
};
}
for sel in paths {
let p = sel.trim();
if p.is_empty() {
continue;
}
if let Ok(url) = Url::parse(p) {
if let Ok(url) = Url::parse(&sel) {
open_url(cx, url, action);
continue;
}
let path = &rel_path.join(p);
let path = expand_tilde(Cow::from(PathBuf::from(sel)));
let path = &rel_path.join(path);
if path.is_dir() {
let picker = ui::file_picker(path.into(), &cx.editor.config());
cx.push_layer(Box::new(overlaid(picker)));
@ -5768,6 +5764,7 @@ fn shell(cx: &mut compositor::Context, cmd: &str, behavior: &ShellBehavior) {
let fragment = range.slice(text);
match shell_impl(shell, cmd, pipe.then(|| fragment.into())) {
Ok(result) => {
let result = Tendril::from(result.trim_end());
if !pipe {
shell_output = Some(result.clone());
}

@ -9,6 +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_lsp::LanguageServerId;
use helix_view::document::{read_to_string, DEFAULT_LANGUAGE_NAME};
use helix_view::editor::{CloseError, ConfigEvent};
use serde_json::Value;
@ -339,9 +340,12 @@ fn write_impl(
let path = path.map(AsRef::as_ref);
if config.insert_final_newline {
insert_final_newline(doc, view);
insert_final_newline(doc, view.id);
}
// Save an undo checkpoint for any outstanding changes.
doc.append_changes_to_history(view);
let fmt = if config.auto_format {
doc.auto_format().map(|fmt| {
let callback = make_format_callback(
@ -366,13 +370,12 @@ fn write_impl(
Ok(())
}
fn insert_final_newline(doc: &mut Document, view: &mut View) {
fn insert_final_newline(doc: &mut Document, view_id: ViewId) {
let text = doc.text();
if line_ending::get_line_ending(&text.slice(..)).is_none() {
let eof = Selection::point(text.len_chars());
let insert = Transaction::insert(text, &eof, doc.line_ending.as_str().into());
doc.apply(&insert, view.id);
doc.append_changes_to_history(view);
doc.apply(&insert, view_id);
}
}
@ -703,11 +706,15 @@ pub fn write_all_impl(
for (doc_id, target_view) in saves {
let doc = doc_mut!(cx.editor, &doc_id);
let view = view_mut!(cx.editor, target_view);
if config.insert_final_newline {
insert_final_newline(doc, view_mut!(cx.editor, target_view));
insert_final_newline(doc, target_view);
}
// Save an undo checkpoint for any outstanding changes.
doc.append_changes_to_history(view);
let fmt = if config.auto_format {
doc.auto_format().map(|fmt| {
let callback = make_format_callback(
@ -1370,37 +1377,51 @@ fn lsp_workspace_command(
if event != PromptEvent::Validate {
return Ok(());
}
struct LsIdCommand(LanguageServerId, helix_lsp::lsp::Command);
impl ui::menu::Item for LsIdCommand {
type Data = ();
fn format(&self, _data: &Self::Data) -> Row {
self.1.title.as_str().into()
}
}
let doc = doc!(cx.editor);
let Some((language_server_id, options)) = doc
let ls_id_commands = doc
.language_servers_with_feature(LanguageServerFeature::WorkspaceCommand)
.find_map(|ls| {
.flat_map(|ls| {
ls.capabilities()
.execute_command_provider
.as_ref()
.map(|options| (ls.id(), options))
})
else {
cx.editor
.set_status("No active language servers for this document support workspace commands");
return Ok(());
};
.iter()
.flat_map(|options| options.commands.iter())
.map(|command| (ls.id(), command))
});
if args.is_empty() {
let commands = options
.commands
.iter()
.map(|command| helix_lsp::lsp::Command {
let commands = ls_id_commands
.map(|(ls_id, command)| {
LsIdCommand(
ls_id,
helix_lsp::lsp::Command {
title: command.clone(),
command: command.clone(),
arguments: None,
},
)
})
.collect::<Vec<_>>();
let callback = async move {
let call: job::Callback = Callback::EditorCompositor(Box::new(
move |_editor: &mut Editor, compositor: &mut Compositor| {
let picker = ui::Picker::new(commands, (), move |cx, command, _action| {
execute_lsp_command(cx.editor, language_server_id, command.clone());
});
let picker = ui::Picker::new(
commands,
(),
move |cx, LsIdCommand(ls_id, command), _action| {
execute_lsp_command(cx.editor, *ls_id, command.clone());
},
);
compositor.push(Box::new(overlaid(picker)))
},
));
@ -1409,21 +1430,32 @@ fn lsp_workspace_command(
cx.jobs.callback(callback);
} else {
let command = args.join(" ");
if options.commands.iter().any(|c| c == &command) {
let matches: Vec<_> = ls_id_commands
.filter(|(_ls_id, c)| *c == &command)
.collect();
match matches.as_slice() {
[(ls_id, _command)] => {
execute_lsp_command(
cx.editor,
language_server_id,
*ls_id,
helix_lsp::lsp::Command {
title: command.clone(),
arguments: None,
command,
},
);
} else {
}
[] => {
cx.editor.set_status(format!(
"`{command}` is not supported for this language server"
"`{command}` is not supported for any language server"
));
return Ok(());
}
_ => {
cx.editor.set_status(format!(
"`{command}` supported by multiple language servers"
));
}
}
}
Ok(())

@ -364,14 +364,16 @@ pub mod completers {
}
pub fn lsp_workspace_command(editor: &Editor, input: &str) -> Vec<Completion> {
let Some(options) = doc!(editor)
let commands = doc!(editor)
.language_servers_with_feature(LanguageServerFeature::WorkspaceCommand)
.find_map(|ls| ls.capabilities().execute_command_provider.as_ref())
else {
return vec![];
};
.flat_map(|ls| {
ls.capabilities()
.execute_command_provider
.iter()
.flat_map(|options| options.commands.iter())
});
fuzzy_match(input, &options.commands, false)
fuzzy_match(input, commands, false)
.into_iter()
.map(|(name, _)| ((0..), name.to_owned().into()))
.collect()

@ -210,13 +210,10 @@ async fn test_multi_selection_shell_commands() -> anyhow::Result<()> {
"},
"|echo foo<ret>",
indoc! {"\
#[|foo\n]#
#(|foo\n)#
#(|foo\n)#
"},
#[|foo]#
#(|foo)#
#(|foo)#"
},
))
.await?;
@ -229,12 +226,9 @@ async fn test_multi_selection_shell_commands() -> anyhow::Result<()> {
"},
"!echo foo<ret>",
indoc! {"\
#[|foo\n]#
lorem
#(|foo\n)#
ipsum
#(|foo\n)#
dolor
#[|foo]#lorem
#(|foo)#ipsum
#(|foo)#dolor
"},
))
.await?;
@ -248,12 +242,9 @@ async fn test_multi_selection_shell_commands() -> anyhow::Result<()> {
"},
"<A-!>echo foo<ret>",
indoc! {"\
lorem#[|foo\n]#
ipsum#(|foo\n)#
dolor#(|foo\n)#
lorem#[|foo]#
ipsum#(|foo)#
dolor#(|foo)#
"},
))
.await?;

@ -20,7 +20,7 @@ parking_lot = "0.12"
arc-swap = { version = "1.7.1" }
gix = { version = "0.63.0", features = ["attributes", "status"], default-features = false, optional = true }
imara-diff = "0.1.5"
imara-diff = "0.1.6"
anyhow = "1"
log = "0.4"

@ -53,7 +53,7 @@ parking_lot = "0.12.3"
thiserror.workspace = true
[target.'cfg(windows)'.dependencies]
clipboard-win = { version = "5.3", features = ["std"] }
clipboard-win = { version = "5.4", features = ["std"] }
[target.'cfg(unix)'.dependencies]
libc = "0.2"

@ -1410,6 +1410,11 @@ impl Document {
}
fn undo_redo_impl(&mut self, view: &mut View, undo: bool) -> bool {
if undo {
self.append_changes_to_history(view);
} else if !self.changes.is_empty() {
return false;
}
let mut history = self.history.take();
let txn = if undo { history.undo() } else { history.redo() };
let success = if let Some(txn) = txn {
@ -1490,6 +1495,11 @@ impl Document {
}
fn earlier_later_impl(&mut self, view: &mut View, uk: UndoKind, earlier: bool) -> bool {
if earlier {
self.append_changes_to_history(view);
} else if !self.changes.is_empty() {
return false;
}
let txns = if earlier {
self.history.get_mut().earlier(uk)
} else {

@ -73,6 +73,7 @@ prisma-language-server = { command = "prisma-language-server", args = ["--stdio"
purescript-language-server = { command = "purescript-language-server", args = ["--stdio"] }
pylsp = { command = "pylsp" }
pyright = { command = "pyright-langserver", args = ["--stdio"], config = {} }
basedpyright = { command = "basedpyright-langserver", args = ["--stdio"], config = {} }
pylyzer = { command = "pylyzer", args = ["--server"] }
qmlls = { command = "qmlls" }
r = { command = "R", args = ["--no-echo", "-e", "languageserver::run()"] }
@ -296,7 +297,7 @@ source = { git = "https://github.com/FuelLabs/tree-sitter-sway", rev = "e491a005
name = "toml"
scope = "source.toml"
injection-regex = "toml"
file-types = ["toml", { glob = "poetry.lock" }, { glob = "Cargo.lock" }]
file-types = ["toml", { glob = "pdm.lock" }, { glob = "poetry.lock" }, { glob = "Cargo.lock" }, { glob = "uv.lock" }]
comment-token = "#"
language-servers = [ "taplo" ]
indent = { tab-width = 2, unit = " " }
@ -1269,7 +1270,7 @@ source = { git = "https://github.com/ikatyang/tree-sitter-yaml", rev = "0e36bed1
name = "haskell"
scope = "source.haskell"
injection-regex = "hs|haskell"
file-types = ["hs", "hs-boot"]
file-types = ["hs", "hs-boot", "hsc"]
roots = ["Setup.hs", "stack.yaml", "cabal.project"]
comment-token = "--"
block-comment-tokens = { start = "{-", end = "-}" }
@ -1693,7 +1694,7 @@ source = { git = "https://github.com/mtoohey31/tree-sitter-gitattributes", rev =
[[language]]
name = "git-ignore"
scope = "source.gitignore"
file-types = [{ glob = ".gitignore_global" }, { glob = ".ignore" }, { glob = "CODEOWNERS" }, { glob = ".config/helix/ignore" }, { glob = ".helix/ignore" }, { glob = ".*ignore" }]
file-types = [{ glob = ".gitignore_global" }, { glob = "git/ignore" }, { glob = ".ignore" }, { glob = "CODEOWNERS" }, { glob = ".config/helix/ignore" }, { glob = ".helix/ignore" }, { glob = ".*ignore" }]
injection-regex = "git-ignore"
comment-token = "#"
grammar = "gitignore"
@ -2054,7 +2055,7 @@ indent = { tab-width = 8, unit = "\t" }
[[grammar]]
name = "hare"
source = { git = "https://git.sr.ht/~ecmma/tree-sitter-hare", rev = "2495958aaf3f93581c87ec020164255e80655331" }
source = { git = "https://git.sr.ht/~ecs/tree-sitter-hare", rev = "07035a248943575444aa0b893ffe306e1444c0ab" }
[[language]]
name = "devicetree"
@ -2081,7 +2082,7 @@ language-servers = [ "cairo-language-server" ]
[[grammar]]
name = "cairo"
source = { git = "https://github.com/starkware-libs/tree-sitter-cairo", rev = "0596baab741ffacdc65c761d5d5ffbbeae97f033" }
source = { git = "https://github.com/starkware-libs/tree-sitter-cairo", rev = "e3a0212261c125cb38248458cd856c0ffee2b398" }
[[language]]
name = "cpon"
@ -2702,6 +2703,8 @@ file-types = [
"kube",
"network",
{ glob = ".editorconfig" },
{ glob = ".npmrc" },
{ glob = "npmrc" },
{ glob = "rclone.conf" },
"properties",
"cfg",
@ -3242,7 +3245,7 @@ auto-format = true
[[grammar]]
name = "todotxt"
source = { git = "https://github.com/arnarg/tree-sitter-todotxt", rev = "0207f6a4ab6aeafc4b091914d31d8235049a2578" }
source = { git = "https://github.com/arnarg/tree-sitter-todotxt", rev = "3937c5cd105ec4127448651a21aef45f52d19609" }
[[language]]
name = "strace"
@ -3513,7 +3516,7 @@ scope = "source.helm"
roots = ["Chart.yaml"]
comment-token = "#"
language-servers = ["helm_ls"]
file-types = [ { glob = "templates/*.yaml" }, { glob = "templates/_*.tpl"}, { glob = "templates/NOTES.txt" } ]
file-types = [ { glob = "templates/*.yaml" }, { glob = "templates/*.yml" }, { glob = "templates/_*.tpl"}, { glob = "templates/NOTES.txt" } ]
[[language]]
name = "glimmer"

@ -1,10 +1,15 @@
[
(string)
(raw_string)
(ansi_c_string)
(heredoc_body)
(heredoc_start)
] @string
[
(heredoc_start)
(heredoc_end)
] @label
(command_name) @function
(variable_name) @variable.other.member

@ -6,3 +6,6 @@
argument: (raw_string) @injection.content
(#match? @_command "^[gnm]?awk$")
(#set! injection.language "awk"))
((regex) @injection.content
(#set! injection.language "regex"))

@ -95,6 +95,12 @@
; -------
; Keywords
; -------
(for_expression
"for" @keyword.control.repeat)
"in" @keyword.control
[
"match"
"if"

@ -115,4 +115,10 @@
(#not-same-line? @expr-start @pattern-guard)
) @indent
(for_expression
"in" @in
.
(_) @indent
(#not-same-line? @in @indent)
(#set! "scope" "all")
)

@ -1,22 +1,5 @@
[
"f32"
"f64"
"i16"
"i32"
"i64"
"i8"
"int"
"rune"
"str"
"u16"
"u32"
"u64"
"u8"
"uint"
"uintptr"
"void"
] @type
(type) @type
(type "const" @type)
[
"else"
@ -36,28 +19,23 @@
"break"
] @keyword.control.repeat
[
"return"
"yield"
] @keyword.control.return
"return" @keyword.control.return
[
"abort"
"assert"
] @keyword.control.exception
[
"def"
"fn"
] @keyword.function
"fn" @keyword.function
[
"alloc"
"append"
"as"
"bool"
"char"
"case"
"const"
"def"
"defer"
"delete"
"enum"
@ -68,13 +46,14 @@
"match"
"nullable"
"offset"
"size"
"static"
"struct"
"type"
"union"
"yield"
] @keyword
"static" @keyword.storage.modifier
[
"."
"!"
@ -137,15 +116,17 @@
"null"
"true"
] @constant.builtin
(literal "void") @constant.builtin
(string_constant) @string
(string_literal) @string
(escape_sequence) @constant.character.escape
(rune_constant) @string
(integer_constant) @constant.numeric.integer
(floating_constant) @constant.numeric.float
(rune_literal) @string
(integer_literal) @constant.numeric.integer
(floating_literal) @constant.numeric.float
(call_expression
(postfix_expression) @function)
(size_expression "size" @function.builtin)
(function_declaration
name: (identifier) @function)
@ -158,4 +139,4 @@
(fndec_attrs) @special
(identifier) @variable
(struct_union_field (name)) @variable

@ -1,20 +1,19 @@
(unit) @local.scope
(sub_unit) @local.scope
(function_declaration) @local.scope
(compound_expression) @local.scope
(global_binding
(identifier) @local.definition)
(constant_binding
(identifier) @local.definition)
(type_bindings
(type_binding
(identifier) @local.definition)
(function_declaration
(prototype
(parameter_list
(parameters
(parameter
(name) @local.definition)))))
(identifier) @local.definition)
(function_declaration
(parameter (name) @local.definition))
(identifier) @local.reference

@ -24,6 +24,10 @@
"ui.cursor.match" = { fg = "light-yellow", underline = { color = "light-yellow", style = "line" } }
"ui.cursor.primary" = { modifiers = ["reversed", "slow_blink"] }
"ui.cursor.secondary" = { modifiers = ["reversed"] }
"ui.cursorline.primary" = { underline = { color = "light-gray", style = "line" } }
"ui.cursorline.secondary" = { underline = { color = "light-gray", style = "line" } }
"ui.cursorcolumn.primary" = { bg = "gray" }
"ui.cursorcolumn.secondary" = { bg = "gray" }
"ui.virtual.ruler" = { bg = "gray" }
"ui.virtual.whitespace" = "gray"
"ui.virtual.indent-guide" = "gray"

@ -77,7 +77,7 @@
"ui.selection" = { bg = "Gray 50" } # .primary
"ui.selection.primary" = { bg = "Blue 40" }
"ui.cursorline" = { bg = "Gray 20" }
"ui.cursorline" = { bg = "Gray 15" }
"ui.linenr" = "Gray 70"
"ui.linenr.selected" = "Gray 110"
@ -121,6 +121,7 @@
"Gray 40" = "#333333"
"Gray 30" = "#2d2d2d"
"Gray 20" = "#292929"
"Gray 15" = "#1F1F1F"
"Gray 10" = "#181818"
"Black" = "#000000"
"Blue 110" = "#6daaf7"

@ -6,6 +6,7 @@ inherits = "gruvbox"
"ui.cursor.primary" = { modifiers = ["reversed"] }
"ui.cursor.match" = { bg = "bg2" }
"ui.cursorline" = { bg = "bg1" }
[palette]
bg0 = "#fbf1c7" # main background

@ -0,0 +1,125 @@
# Kanagawa Dragon
# Author: EricHenry
# Adaptation of https://github.com/rebelot/kanagawa.nvim
# Original author: rebelot
# All credits to the original author, the palette is taken from the README
# because of some theming differences, it's not an exact copy of the original.
inherits = "kanagawa"
## User interface
"ui.selection" = { bg = "waveBlue2" }
"ui.selection.primary" = { bg = "waveBlue1" }
"ui.background" = { fg = "dragonWhite", bg = "dragonBlack3" }
"ui.gutter" = { fg = "dragonBlack6", bg = "dragonBlack4" }
"ui.linenr" = { fg = "dragonBlack6", bg = "dragonBlack4" }
"ui.linenr.selected" = { fg = "roninYellow", modifiers = ["bold"] }
"ui.virtual" = "dragonBlack4"
"ui.virtual.ruler" = { bg = "dragonBlack5" }
"ui.virtual.inlay-hint" = "dragonGray2"
"ui.virtual.inlay-hint.parameter" = { fg = "dragonYellow", modifiers = ["dim"] }
"ui.virtual.inlay-hint.type" = { fg = "dragonAqua", modifiers = ["dim"] }
"ui.virtual.jump-label" = { fg = "dragonRed", modifiers = ["bold"] }
"ui.statusline" = { fg = "oldWhite", bg = "dragonBlack0" }
"ui.bufferline" = { fg = "oldWhite", bg = "dragonBlack0" }
"ui.bufferline.active" = { fg = "oldWhite", bg = "dragonBlack0" }
"ui.bufferline.background" = { bg = "sumiInk0" }
"ui.popup" = { fg = "oldWhite", bg = "dragonBlack0" }
"ui.window" = { fg = "sumiInk0" }
"ui.help" = { fg = "fujiWhite", bg = "sumiInk0" }
"ui.text" = "dragonWhite"
"ui.text.focus" = { fg = "dragonWhite", bg = "waveBlue1", modifiers = ["bold"] }
"ui.cursor" = { fg = "waveBlue1", bg = "waveAqua2" }
"ui.cursor.primary" = { fg = "waveBlue1", bg = "fujiWhite" }
"ui.cursor.match" = { fg = "roninYellow", modifiers = ["bold"] }
"ui.highlight" = { fg = "fujiWhite", bg = "waveBlue2" }
"ui.cursorline.primary" = { bg = "dragonBlack5" }
"ui.cursorcolumn.primary" = { bg = "dragonBlack5" }
"diagnostic.info" = { underline = { color = "dragonBlue", style = "curl" } }
"diagnostic.hint" = { underline = { color = "waveAqua1", style = "curl" } }
"diagnostic.deprecated" = { fg= "katanaGray", modifiers = ["crossed_out"] }
## Syntax highlighting
"attribute" = "waveRed"
"type" = "dragonAqua"
"type.enum.variant" = "dragonOrange"
"constructor" = "dragonTeal"
"constant" = "dragonOrange"
"constant.numeric" = "dragonPink"
"constant.character.escape" = "dragonBlue2"
"string" = "dragonGreen2"
"string.regexp" = "dragonRed"
"string.special.url" = "dragonTeal"
"string.special.symbol" = "dragonTeal"
"comment" = "dragonAsh"
"variable" = "dragonWhite"
"variable.builtin" = "dragonRed"
"variable.parameter" = "dragonGray"
"variable.other.member" = "dragonYellow"
"label" = "dragonRed"
"punctuation" = "dragonWhite"
"keyword" = "dragonViolet"
"keyword.control.return" = "dragonRed"
"keyword.control.exception" = "dragonRed"
"keyword.directive" = "dragonRed"
"operator" = "dragonRed"
"function" = "dragonBlue2"
"function.builtin" = "dragonBlue2"
"function.macro" = "dragonRed"
"tag" = "dragonYellow"
"namespace" = "dragonWhite"
"special" = "dragonYellow"
## Markup modifiers
"markup.heading.marker" = "dragonViolet"
"markup.heading.1" = { fg = "dragonOrange", modifiers = ["bold"] }
"markup.heading.2" = { fg = "dragonYellow", modifiers = ["bold"] }
"markup.heading.3" = { fg = "dragonBlue2", modifiers = ["bold"] }
"markup.heading.4" = { fg = "dragonWhite", modifiers = ["bold"] }
"markup.heading.5" = { fg = "dragonRed", modifiers = ["bold"] }
"markup.heading.6" = { fg = "dragonPink", modifiers = ["bold"] }
"markup.list.numbered" = "dragonPink"
"markup.list.unnumbered" = "dragonRed"
"markup.bold" = { modifiers = ["bold"] }
"markup.italic" = { modifiers = ["italic"] }
"markup.strikethrough" = { modifiers = ["crossed_out"] }
"markup.link.text" = "dragonTeal"
"markup.link.url" = { fg = "dragonPink", underline.style = "line" }
"markup.link.label" = "dragonBlue2"
"markup.quote" = "springViolet1"
"markup.raw" = "dragonGreen2"
[palette]
dragonBlack0 = "#0d0c0c"
dragonBlack1 = "#12120f"
dragonBlack2 = "#1D1C19"
dragonBlack3 = "#181616"
dragonBlack4 = "#282727"
dragonBlack5 = "#393836"
dragonBlack6 = "#625e5a"
dragonWhite = "#c5c9c5"
dragonGreen = "#87a987"
dragonGreen2 = "#8a9a7b"
dragonPink = "#a292a3"
dragonOrange = "#b6927b"
dragonOrange2 = "#b98d7b"
dragonGray = "#a6a69c"
dragonGray2 = "#9e9b93"
dragonGray3 = "#7a8382"
dragonBlue2 = "#8ba4b0"
dragonViolet= "#8992a7"
dragonRed = "#c4746e"
dragonAqua = "#8ea4a2"
dragonAsh = "#737c73"
dragonTeal = "#949fb5"
dragonYellow = "#c4b28a"

@ -1,4 +1,5 @@
# Author : Eric Correia <correia.eh@gmail.com>
# Zed OneDark
# Author : EricHenry
"attribute" = { fg = "yellow" }
"comment" = { fg = "light-gray", modifiers = ["italic"] }

@ -1,4 +1,5 @@
# Author : Eric Correia <correia.eh@gmail.com>
# Zed OneLight
# Author : EricHenry
inherits = "zed_onedark"

Loading…
Cancel
Save