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 {
title: command.clone(),
command: command.clone(),
arguments: None,
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) {
execute_lsp_command(
cx.editor,
language_server_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"
));
return Ok(());
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,
*ls_id,
helix_lsp::lsp::Command {
title: command.clone(),
arguments: None,
command,
},
);
}
[] => {
cx.editor.set_status(format!(
"`{command}` is not supported for any language server"
));
}
_ => {
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![];
};
fuzzy_match(input, &options.commands, false)
.flat_map(|ls| {
ls.capabilities()
.execute_command_provider
.iter()
.flat_map(|options| options.commands.iter())
});
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

@ -5,4 +5,7 @@
name: (command_name (word) @_command)
argument: (raw_string) @injection.content
(#match? @_command "^[gnm]?awk$")
(#set! injection.language "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
(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"

@ -145,7 +145,7 @@
You can also type wq or write-quit to save and exit.
Note: You can optionally enter a filepath after the w / write
Note: You can optionally enter a file path after the w / write
command in order to save to that path.
Note: If there are any unsaved changes to a file, a plus [+]
will appear next to the file name in the status bar.
@ -1124,14 +1124,14 @@ letters! that is not good grammar. you can fix this.
= 11.1 COMMENTING A LINE =
=================================================================
Press Ctrl-c to comment the line under your cursor.
To uncomment the line, press Ctrl-c again.
Press Ctrl-c to comment the line under your cursor.
To uncomment the line, press Ctrl-c again.
1. Move your cursor to the line marked '-->' below.
2. Now comment the line marked with '-->'.
3. Now try uncommenting the line.
1. Move your cursor to the line marked '-->' below.
2. Now comment the line marked with '-->'.
3. Now try uncommenting the line.
--> Comment me please
--> Comment me please
@ -1146,23 +1146,23 @@ To uncomment the line, press Ctrl-c again.
= 11.2 COMMENTING MULTIPLE LINES =
=================================================================
Using the selections and multi-cursor functionality, you can
comment multiple lines as long as it is under the selection or
cursors.
Using the selections and multi-cursor functionality, you can
comment multiple lines as long as it is under the selection or
cursors.
1. Move your cursor to the line marked with '-->' below.
2. Now try to select or add more cursors the other lines marked
with '-->'.
3. Comment those lines.
1. Move your cursor to the line marked with '-->' below.
2. Now try to select or add more cursors the other lines marked
with '-->'.
3. Comment those lines.
--> How many are you going to comment?
--> Is this enough for a comment?
--> What are you doing?!
--> Stop commenting me!
--> AAAAaargh!!!
--> How many are you going to comment?
--> Is this enough for a comment?
--> What are you doing?!
--> Stop commenting me!
--> AAAAaargh!!!
Note: If there are already commented lines under selections or
multiple cursors, they won't be uncommented but commented again.
Note: If there are already commented lines under selections or
multiple cursors, they won't be uncommented but commented again.
=================================================================
= CHAPTER 11 RECAP =
@ -1190,20 +1190,20 @@ multiple cursors, they won't be uncommented but commented again.
= 12.1 USING MATCH MODE JUMP =
=================================================================
To switch to match mode from normal mode, type m. This feature
is particularly useful for handling bracket pairs and their
contents.
To switch to match mode from normal mode, type m. This feature
is particularly useful for handling bracket pairs and their
contents.
There are several actions that can be performed in match mode,
as indicated by the help pop-up. To jump to a matching bracket pair,
simply press mm. For example on the lines below (starting with
-->), move the cursor in normal mode to (, and then press mm to jump
to the matching ). You can do the same on the line below: for example
move to ], and press mm to jump to [ .
There are several actions that can be performed in match mode,
as indicated by the help pop-up. To jump to a matching bracket pair,
simply press mm. For example on the lines below (starting with
-->), move the cursor in normal mode to (, and then press mm to jump
to the matching ). You can do the same on the line below: for example
move to ], and press mm to jump to [ .
--> you can (jump between matching parenthesis)
--> or between matching [ square brackets ]
--> now { you know the drill: this works with brackets too }
--> you can (jump between matching parenthesis)
--> or between matching [ square brackets ]
--> now { you know the drill: this works with brackets too }
@ -1212,41 +1212,41 @@ move to ], and press mm to jump to [ .
= 12.2 USING MATCH MODE SELECT INSIDE =
=================================================================
Match mode also lets you select the "inside" content between a
pair of brackets or other delimiters. In the lines below:
Match mode also lets you select the "inside" content between a
pair of brackets or other delimiters. In the lines below:
- move to the --> line, put your cursor in normal mode at any
location between the parenthesis, for example at 'x', and press
mi( or mi) to select the whole content inside the parenthesis
(parenthesis excluded). As usual, you can then do anything you want
with the selection (for example, press c to change it)
- move to the --> line, put your cursor in normal mode at any
location between the parenthesis, for example at 'x', and press
mi( or mi) to select the whole content inside the parenthesis
(parenthesis excluded). As usual, you can then do anything you want
with the selection (for example, press c to change it)
--> outside and (inside x parenthesis) - and outside again
--> outside and (inside x parenthesis) - and outside again
Test below that you can do the same with [], or {}, or with
nested combinations of these (this will act on the immediately
surrounding matching pair). This also works with "" and similar
Test below that you can do the same with [], or {}, or with
nested combinations of these (this will act on the immediately
surrounding matching pair). This also works with "" and similar
--> test [ with square brackets ] !
--> try ( with nested [ pairs of ( parenthesis) and "brackets" ])
--> test [ with square brackets ] !
--> try ( with nested [ pairs of ( parenthesis) and "brackets" ])
=================================================================
= 12.3 USING MATCH MODE SELECT AROUND =
=================================================================
You can also select the "around" content, i.e. both the inside
content and the delimiters themselves, by using the ma select.
For example, move to the line under, move your cursor in normal
mode to any position between the (), and select the content of
the (), including the surrounding (), by typing ma( or ma). As
usual, you can do anything you want with the selection, for
example delete it all with ma(d .
You can also select the "around" content, i.e. both the inside
content and the delimiters themselves, by using the ma select.
For example, move to the line under, move your cursor in normal
mode to any position between the (), and select the content of
the (), including the surrounding (), by typing ma( or ma). As
usual, you can do anything you want with the selection, for
example delete it all with ma(d .
--> you ( select x around ) to include delimiters in the select
--> you ( select x around ) to include delimiters in the select
This naturally works with other delimiters too:
This naturally works with other delimiters too:
--> try [ with 'square' brackets ] too!
--> try [ with 'square' brackets ] too!
@ -1256,21 +1256,21 @@ This naturally works with other delimiters too:
= 12.4 USING MATCH MODE SURROUND =
=================================================================
The match mode can also be used to add surrounding around the
current selection. For example, move to the line below, then:
* i) select the "select all of this" line segment (for example,
move in normal mode the cursor to the start of select, then enter
selection mode with v , then select the 4 next words with 4e ),
* ii) press ms( or ms) to surround the selection with a pair of
parenthesis.
The match mode can also be used to add surrounding around the
current selection. For example, move to the line below, then:
* i) select the "select all of this" line segment (for example,
move in normal mode the cursor to the start of select, then enter
selection mode with v , then select the 4 next words with 4e ),
* ii) press ms( or ms) to surround the selection with a pair of
parenthesis.
--> so, select all of this, and surround it with ()
--> so, select all of this, and surround it with ()
You can do the same with other delimiters: for example, ms' on
WORD below to surround it with a pair of ''. You can try also
with adding a surrounding pair of "", or {}, or [].
You can do the same with other delimiters: for example, ms' on
WORD below to surround it with a pair of ''. You can try also
with adding a surrounding pair of "", or {}, or [].
--> surround this WORD !
--> surround this WORD !
@ -1278,64 +1278,64 @@ with adding a surrounding pair of "", or {}, or [].
= 12.5 USING MATCH MODE DELETE SURROUND =
=================================================================
You can delete surrounding pair of delimiters with the md
command. On the line below, move the cursor anywhere
within the pair of (), for example to the 'x', then from there,
in normal mode, press md( or md) to delete the surrounding
pair of parenthesis.
You can delete surrounding pair of delimiters with the md
command. On the line below, move the cursor anywhere
within the pair of (), for example to the 'x', then from there,
in normal mode, press md( or md) to delete the surrounding
pair of parenthesis.
--> delete (the x pair of parenthesis) from within!
--> delete (the x pair of parenthesis) from within!
You can naturally delete other kinds of surroundings:
You can naturally delete other kinds of surroundings:
--> delete (nested [delimiters]): "this" will delete the nearest
matching surrounding pair.
--> delete "layers "of" quote marks" too: this will delete the
nearest previous and following quote marks
--> delete (nested [delimiters]): "this" will delete the nearest
matching surrounding pair.
--> delete "layers "of" quote marks" too: this will delete the
nearest previous and following quote marks
Trying to delete unexisting surrounding delimiters print an error
at the bottom bar and does nothing.
Trying to delete unexisting surrounding delimiters print an error
at the bottom bar and does nothing.
=================================================================
= 12.6 USING MATCH MODE REPLACE SURROUND =
=================================================================
You can replace surrounding pairs of delimiters with the mr
command. On the line below, move the cursor to
anywhere within the pair of (), for example on the 'x', then in
normal mode, press mr([ to replace the pair of () with a pair
of [].
You can replace surrounding pairs of delimiters with the mr
command. On the line below, move the cursor to
anywhere within the pair of (), for example on the 'x', then in
normal mode, press mr([ to replace the pair of () with a pair
of [].
--> replace the (pair from x within), with something else
--> replace the (pair from x within), with something else
This command will act on the closest enclosing pair, so you
can try replacing different surrounding in the following:
This command will act on the closest enclosing pair, so you
can try replacing different surrounding in the following:
--> some (nested surroundings [can be replaced])
--> this "works with 'other surroundings' too"
--> some (nested surroundings [can be replaced])
--> this "works with 'other surroundings' too"
You can try to replace a non existing pair: this will show
an error warning at the bottom bar and do nothing.
You can try to replace a non existing pair: this will show
an error warning at the bottom bar and do nothing.
=================================================================
= CHAPTER 12 RECAP =
=================================================================
You can enter the match mode with the m key; this will show the
actions available in a popup. This will allow you to:
* jump to matching pair of delimiters with mm (you must have a
delimiter belonging to a pair under your cursor)
* select inside a pair of delimiters surrounding your cursor
(i.e. select the content but not the delimiters) with mi(
and similar
* select around a pair of delimiters surrounding your cursor
(i.e. select the content and the delimiters) with ma( and
similar
* delete surrounding delimiters with md( and similar
* add surrounding delimiters around the selection with ms(
* replace a pair of delimiters surrounding your selection with
mr([ to replace for example surrounding () with []
You can enter the match mode with the m key; this will show the
actions available in a popup. This will allow you to:
* jump to matching pair of delimiters with mm (you must have a
delimiter belonging to a pair under your cursor)
* select inside a pair of delimiters surrounding your cursor
(i.e. select the content but not the delimiters) with mi(
and similar
* select around a pair of delimiters surrounding your cursor
(i.e. select the content and the delimiters) with ma( and
similar
* delete surrounding delimiters with md( and similar
* add surrounding delimiters around the selection with ms(
* replace a pair of delimiters surrounding your selection with
mr([ to replace for example surrounding () with []
@ -1344,20 +1344,20 @@ actions available in a popup. This will allow you to:
= CHAPTER 13.1 CREATE NEW SPLIT =
=================================================================
In Normal mode, press Ctrl-w to open the Window menu, which displays
a list of available commands.
In Normal mode, press Ctrl-w to open the Window menu, which displays
a list of available commands.
To open a new empty buffer in a vertical split on the right half
of your current window, use Ctrl-w nv (i.e., press Ctrl
and w simultaneously, then press n, followed by v). Your current
window will now split in 2 vertically. A new empty buffer split
will appear on the right half and your cursor will jump to the
new vertical split.
To open a new empty buffer in a vertical split on the right half
of your current window, use Ctrl-w nv (i.e., press Ctrl
and w simultaneously, then press n, followed by v). Your current
window will now split in 2 vertically. A new empty buffer split
will appear on the right half and your cursor will jump to the
new vertical split.
To create a new empty buffer in a horizontal split, press
Ctrl-w ns. This action divides your current window into two
horizontally, creates a new buffer, and moves your cursor to the
new horizontal split.
To create a new empty buffer in a horizontal split, press
Ctrl-w ns. This action divides your current window into two
horizontally, creates a new buffer, and moves your cursor to the
new horizontal split.
@ -1366,33 +1366,33 @@ new horizontal split.
= CHAPTER 13.2 MOVE BETWEEN SPLITS =
=================================================================
Use Ctrl-w k to move to the split above your current split. Use
Ctrl-w j to move to the split below. Use Ctrl-w h to move to
the split on the left and Ctrl-w l to move to the split on the
right. To navigate to the next split (in the order they were
opened), press Ctrl-w w.
Use Ctrl-w k to move to the split above your current split. Use
Ctrl-w j to move to the split below. Use Ctrl-w h to move to
the split on the left and Ctrl-w l to move to the split on the
right. To navigate to the next split (in the order they were
opened), press Ctrl-w w.
You can now do whatever you want in your new buffers and splits.
Once you are done with using your new buffer split,
you can close it with Ctrl-w q . Move to the bottom right split
with Ctrl-w l then Ctrl-w j, then press Ctrl-w q to close this
specific split.
You can now do whatever you want in your new buffers and splits.
Once you are done with using your new buffer split,
you can close it with Ctrl-w q . Move to the bottom right split
with Ctrl-w l then Ctrl-w j, then press Ctrl-w q to close this
specific split.
You can also close all splits except the current one with Ctrl-w o .
Open a third vertical split with Ctrl-w nv , then move to the
leftmost split with Ctrl-w h twice, then from inside the split on
the left press Ctrl-w o to close all except this split.
You can also close all splits except the current one with Ctrl-w o .
Open a third vertical split with Ctrl-w nv , then move to the
leftmost split with Ctrl-w h twice, then from inside the split on
the left press Ctrl-w o to close all except this split.
=================================================================
= CHAPTER 13.3 SPLIT CURRENT BUFFER =
=================================================================
Use Ctrl-w s to split the view of the current buffer horizontally
and Ctrl-w v to split it vertically with the buffer opened in both
splits.
Use Ctrl-w s to split the view of the current buffer horizontally
and Ctrl-w v to split it vertically with the buffer opened in both
splits.
Close extra splits with Ctrl-w o to return to a single window view.
Close extra splits with Ctrl-w o to return to a single window view.
@ -1410,41 +1410,41 @@ Close extra splits with Ctrl-w o to return to a single window view.
= CHAPTER 13.4 USE COMMANDS TO SPLIT =
=================================================================
The :vsplit (or :vs for short) and :hsplit (or :hs) commands can
also be used to split a specific buffer vertically or horizontally.
For example, enter the command:
The :vsplit (or :vs for short) and :hsplit (or :hs) commands can
also be used to split a specific buffer vertically or horizontally.
For example, enter the command:
:vs something
:vs something
to open a new vertical split named "something" to the right. Here,
"something" is not an existing file, so a new buffer with this name
will open; however, you can replace "something" with any file name
to open it in a new buffer. Similarly, you can enter the command:
to open a new vertical split named "something" to the right. Here,
"something" is not an existing file, so a new buffer with this name
will open; however, you can replace "something" with any file name
to open it in a new buffer. Similarly, you can enter the command:
:hs some_more
:hs some_more
to open a new buffer named "some_more" in the lower half.
"some_more" could be any file or path to open this specific file
or path instead of a new empty buffer.
to open a new buffer named "some_more" in the lower half.
"some_more" could be any file or path to open this specific file
or path instead of a new empty buffer.
=================================================================
= CHAPTER 13.5 SWAPPING SPLITS =
=================================================================
Open a split on the left with :vs hello1 and then a split below
with :hs hello2.
Open a split on the left with :vs hello1 and then a split below
with :hs hello2.
From hello2, press Ctrl-w K to swap it with the split above. Now
hello2 is at the top while hello1 is at the bottom.
From hello2, press Ctrl-w K to swap it with the split above. Now
hello2 is at the top while hello1 is at the bottom.
Still from hello2, press Ctrl-w H to swap with the split on the
left: now hello2 is on the left and the tutor is on the top
right. After Ctrl-w you can use HJKL to split with the buffer
on the left / below / above / on the right.
Still from hello2, press Ctrl-w H to swap with the split on the
left: now hello2 is on the left and the tutor is on the top
right. After Ctrl-w you can use HJKL to split with the buffer
on the left / below / above / on the right.
Move back to the tutor split, and press Ctrl-w o to only keep
this split.
Move back to the tutor split, and press Ctrl-w o to only keep
this split.
@ -1454,21 +1454,21 @@ this split.
= CHAPTER 13.6 TRANSPOSE SPLITS =
=================================================================
Open a split on the left with :vs hello1 and then a split below
with :vs hello2.
Open a split on the left with :vs hello1 and then a split below
with :vs hello2.
Move to the tutor split, then press Ctrl-w t to transpose the
vertical split opened from this window: now, hello1 and
hello2 are below, rather than to the right of, the tutor. Press
Ctrl-w t again to transpose back.
Move to the tutor split, then press Ctrl-w t to transpose the
vertical split opened from this window: now, hello1 and
hello2 are below, rather than to the right of, the tutor. Press
Ctrl-w t again to transpose back.
Move to the hello1 split, then press Ctrl-w t to transpose the
horizontal split that was opened from this window: now hello2
is on the right, rather than below, hello1. Press Ctrl-w t to
transpose back.
Move to the hello1 split, then press Ctrl-w t to transpose the
horizontal split that was opened from this window: now hello2
is on the right, rather than below, hello1. Press Ctrl-w t to
transpose back.
Move back to the tutor split and press Ctrl-w o to close all but
the tutor window.
Move back to the tutor split and press Ctrl-w o to close all but
the tutor window.
@ -1476,21 +1476,21 @@ the tutor window.
= CHAPTER 13.7 OPEN SPLIT FROM FILEPICKER =
=================================================================
Splits can also be opened directly from the file picker. Press
space f to open the file picker. From there, you can type in text
to perform file lookup with fuzzy matching, and use the arrows
up and down to move the selected file (indicated by the > symbol).
If you want to exit the file picker, press Escape.
Splits can also be opened directly from the file picker. Press
space f to open the file picker. From there, you can type in text
to perform file lookup with fuzzy matching, and use the arrows
up and down to move the selected file (indicated by the > symbol).
If you want to exit the file picker, press Escape.
Select any file you like in the file picker. You could open it in
the current view by pressing enter (do not do this at present).
But you can also open it in a new split. Press Ctrl-v to open
the selected file in a new vertical split. Press space f again,
select any file you want, and press Ctrl-s to open it in a
horizontal split.
Select any file you like in the file picker. You could open it in
the current view by pressing enter (do not do this at present).
But you can also open it in a new split. Press Ctrl-v to open
the selected file in a new vertical split. Press space f again,
select any file you want, and press Ctrl-s to open it in a
horizontal split.
Move back to the tutor split, and press Ctrl-w o to close all
splits except this one.
Move back to the tutor split, and press Ctrl-w o to close all
splits except this one.
@ -1498,18 +1498,18 @@ splits except this one.
= CHAPTER 13 RECAP =
=================================================================
Splits can be used to display either the same buffer several times
or several buffers. To access the main windows and splits commands,
press Ctrl-w . You can move between splits with Ctrl-w hjkl ,
you can close a split with Ctrl-w q , and you can close all but
the present split with Ctrl-w o .
Splits can be used to display either the same buffer several times
or several buffers. To access the main windows and splits commands,
press Ctrl-w . You can move between splits with Ctrl-w hjkl ,
you can close a split with Ctrl-w q , and you can close all but
the present split with Ctrl-w o .
Splits can also be opened by using the :vs FILENAME and
:hs FILENAME commands.
Splits can also be opened by using the :vs FILENAME and
:hs FILENAME commands.
Splits can also be used directly from the file pickers, by using
Ctrl-v to open the file selected in a new vertical split, and
Ctrl-s in a horizontal split.
Splits can also be used directly from the file pickers, by using
Ctrl-v to open the file selected in a new vertical split, and
Ctrl-s in a horizontal split.

Loading…
Cancel
Save