mirror of https://github.com/helix-editor/helix
Compare commits
11 Commits
f65ea2f3ba
...
e5ff75ac97
Author | SHA1 | Date |
---|---|---|
|
e5ff75ac97 | |
|
395a71bf53 | |
|
1e4bf6704a | |
|
b01fbb4a22 | |
|
f75a26cb9b | |
|
21ae1c98fb | |
|
7b8a4b7a51 | |
|
715d4ae2d5 | |
|
22b184b570 | |
|
587ec24b04 | |
|
760b83dbf4 |
|
@ -112,8 +112,8 @@
|
||||||
| iex | ✓ | | | | |
|
| iex | ✓ | | | | |
|
||||||
| ini | ✓ | | | | |
|
| ini | ✓ | | | | |
|
||||||
| ink | ✓ | | | | |
|
| ink | ✓ | | | | |
|
||||||
| inko | ✓ | ✓ | ✓ | | |
|
| inko | ✓ | ✓ | ✓ | ✓ | |
|
||||||
| janet | ✓ | | | | |
|
| janet | ✓ | | ✓ | | |
|
||||||
| java | ✓ | ✓ | ✓ | | `jdtls` |
|
| java | ✓ | ✓ | ✓ | | `jdtls` |
|
||||||
| javascript | ✓ | ✓ | ✓ | ✓ | `typescript-language-server` |
|
| javascript | ✓ | ✓ | ✓ | ✓ | `typescript-language-server` |
|
||||||
| jinja | ✓ | | | | |
|
| jinja | ✓ | | | | |
|
||||||
|
|
|
@ -82,6 +82,8 @@
|
||||||
| `:pipe-to` | Pipe each selection to the shell command, ignoring output. |
|
| `:pipe-to` | Pipe each selection to the shell command, ignoring output. |
|
||||||
| `:run-shell-command`, `:sh`, `:!` | Run a shell command |
|
| `:run-shell-command`, `:sh`, `:!` | Run a shell command |
|
||||||
| `:reset-diff-change`, `:diffget`, `:diffg` | Reset the diff change at the cursor position. |
|
| `:reset-diff-change`, `:diffget`, `:diffg` | Reset the diff change at the cursor position. |
|
||||||
|
| `:show-selection-diff-popup`, `:diffshow` | Show a popup with the unsaved diff hunks intersecting the primary selection. |
|
||||||
|
| `:yank-selection-diff`, `:diffyank` | Yank the unsaved diff hunks intersecting the primary selection. |
|
||||||
| `:clear-register` | Clear given register. If no argument is provided, clear all registers. |
|
| `:clear-register` | Clear given register. If no argument is provided, clear all registers. |
|
||||||
| `:redraw` | Clear and re-render the whole UI |
|
| `:redraw` | Clear and re-render the whole UI |
|
||||||
| `:move`, `:mv` | Move the current buffer and its corresponding file to a different path |
|
| `:move`, `:mv` | Move the current buffer and its corresponding file to a different path |
|
||||||
|
|
|
@ -168,6 +168,21 @@ pub fn compare_ropes(before: &Rope, after: &Rope) -> Transaction {
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Compares `old` and `new` to generate a text diff
|
||||||
|
pub fn diff_ropes(before: RopeSlice, after: RopeSlice) -> String {
|
||||||
|
let before = before.to_string();
|
||||||
|
let after = after.to_string();
|
||||||
|
let input = InternedInput::new(before.as_str(), after.as_str());
|
||||||
|
let mut diff = Diff::compute(Algorithm::Histogram, &input);
|
||||||
|
diff.postprocess_lines(&input);
|
||||||
|
diff.unified_diff(
|
||||||
|
&imara_diff::BasicLineDiffPrinter(&input.interner),
|
||||||
|
imara_diff::UnifiedDiffConfig::default(),
|
||||||
|
&input,
|
||||||
|
)
|
||||||
|
.to_string()
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
|
@ -7,6 +7,7 @@ use crate::job::Job;
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use helix_core::command_line::{Args, Flag, Signature, Token, TokenKind};
|
use helix_core::command_line::{Args, Flag, Signature, Token, TokenKind};
|
||||||
|
use helix_core::diff::diff_ropes;
|
||||||
use helix_core::fuzzy::fuzzy_match;
|
use helix_core::fuzzy::fuzzy_match;
|
||||||
use helix_core::indent::MAX_INDENT;
|
use helix_core::indent::MAX_INDENT;
|
||||||
use helix_core::line_ending;
|
use helix_core::line_ending;
|
||||||
|
@ -2469,6 +2470,104 @@ fn reset_diff_change(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_diff_change_at_selection(editor: &mut Editor) -> anyhow::Result<String> {
|
||||||
|
let (view, doc) = current!(editor);
|
||||||
|
let Some(handle) = doc.diff_handle() else {
|
||||||
|
bail!("Diff is not available in the current buffer")
|
||||||
|
};
|
||||||
|
|
||||||
|
let diff = handle.load();
|
||||||
|
let doc_text = doc.text().slice(..);
|
||||||
|
let primary_selection = doc.selection(view.id).primary();
|
||||||
|
|
||||||
|
let Some((base_start, base_end, doc_start, doc_end)) = diff
|
||||||
|
.hunks_intersecting_line_ranges([primary_selection.line_range(doc_text)].into_iter())
|
||||||
|
.fold(None, |line_ranges, hunk| match line_ranges {
|
||||||
|
Some((base_start, base_end, doc_start, doc_end)) => Some((
|
||||||
|
hunk.before.start.min(base_start),
|
||||||
|
hunk.before.end.max(base_end),
|
||||||
|
hunk.after.start.min(doc_start),
|
||||||
|
hunk.after.end.max(doc_end),
|
||||||
|
)),
|
||||||
|
None => Some((
|
||||||
|
hunk.before.start,
|
||||||
|
hunk.before.end,
|
||||||
|
hunk.after.start,
|
||||||
|
hunk.after.end,
|
||||||
|
)),
|
||||||
|
})
|
||||||
|
else {
|
||||||
|
bail!("There are no changes in the primary selection");
|
||||||
|
};
|
||||||
|
|
||||||
|
let base = diff.diff_base();
|
||||||
|
let doc = diff.doc();
|
||||||
|
Ok(diff_ropes(
|
||||||
|
base.slice(
|
||||||
|
base.line_to_char(base_start as usize)..base.line_to_char((base_end as usize) + 1) - 1,
|
||||||
|
),
|
||||||
|
doc.slice(
|
||||||
|
doc.line_to_char(doc_start as usize)..doc.line_to_char((doc_end as usize) + 1) - 1,
|
||||||
|
),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn show_selection_diff_popup(
|
||||||
|
cx: &mut compositor::Context,
|
||||||
|
args: Args,
|
||||||
|
event: PromptEvent,
|
||||||
|
) -> anyhow::Result<()> {
|
||||||
|
if event != PromptEvent::Validate {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
ensure!(
|
||||||
|
args.is_empty(),
|
||||||
|
"show-selection-diff-popup takes no arguments"
|
||||||
|
);
|
||||||
|
|
||||||
|
let text = get_diff_change_at_selection(cx.editor)?;
|
||||||
|
|
||||||
|
let callback = async move {
|
||||||
|
let call: job::Callback = Callback::EditorCompositor(Box::new(
|
||||||
|
move |editor: &mut Editor, compositor: &mut Compositor| {
|
||||||
|
let contents =
|
||||||
|
ui::Markdown::new(format!("```diff\n{}```", text), editor.syn_loader.clone());
|
||||||
|
let popup = Popup::new("show-selection-diff-popup", contents).auto_close(true);
|
||||||
|
compositor.replace_or_push("show-selection-diff-popup", popup);
|
||||||
|
},
|
||||||
|
));
|
||||||
|
Ok(call)
|
||||||
|
};
|
||||||
|
cx.jobs.callback(callback);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn yank_selection_diff(
|
||||||
|
cx: &mut compositor::Context,
|
||||||
|
args: Args,
|
||||||
|
event: PromptEvent,
|
||||||
|
) -> anyhow::Result<()> {
|
||||||
|
if event != PromptEvent::Validate {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let reg = match args.first() {
|
||||||
|
Some(s) => {
|
||||||
|
ensure!(s.chars().count() == 1, format!("Invalid register {s}"));
|
||||||
|
s.chars().next().unwrap()
|
||||||
|
}
|
||||||
|
None => '+',
|
||||||
|
};
|
||||||
|
|
||||||
|
let text = get_diff_change_at_selection(cx.editor)?;
|
||||||
|
|
||||||
|
cx.editor.registers.write(reg, vec![text])?;
|
||||||
|
cx.editor.set_status(format!(
|
||||||
|
"Yanked diff changes in the primary selection to register {reg}",
|
||||||
|
));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn clear_register(
|
fn clear_register(
|
||||||
cx: &mut compositor::Context,
|
cx: &mut compositor::Context,
|
||||||
args: Args,
|
args: Args,
|
||||||
|
@ -3584,6 +3683,28 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[
|
||||||
..Signature::DEFAULT
|
..Signature::DEFAULT
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
TypableCommand {
|
||||||
|
name: "show-selection-diff-popup",
|
||||||
|
aliases: &["diffshow"],
|
||||||
|
doc: "Show a popup with the unsaved diff hunks intersecting the primary selection.",
|
||||||
|
fun: show_selection_diff_popup,
|
||||||
|
completer: CommandCompleter::all(completers::register),
|
||||||
|
signature: Signature {
|
||||||
|
positionals: (0, Some(0)),
|
||||||
|
..Signature::DEFAULT
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TypableCommand {
|
||||||
|
name: "yank-selection-diff",
|
||||||
|
aliases: &["diffyank"],
|
||||||
|
doc: "Yank the unsaved diff hunks intersecting the primary selection.",
|
||||||
|
fun: yank_selection_diff,
|
||||||
|
completer: CommandCompleter::all(completers::register),
|
||||||
|
signature: Signature {
|
||||||
|
positionals: (0, Some(1)),
|
||||||
|
..Signature::DEFAULT
|
||||||
|
},
|
||||||
|
},
|
||||||
TypableCommand {
|
TypableCommand {
|
||||||
name: "clear-register",
|
name: "clear-register",
|
||||||
aliases: &[],
|
aliases: &[],
|
||||||
|
|
|
@ -356,7 +356,7 @@ fn directory_content(path: &Path) -> Result<Vec<(PathBuf, bool)>, std::io::Error
|
||||||
.map(|entry| {
|
.map(|entry| {
|
||||||
(
|
(
|
||||||
entry.path(),
|
entry.path(),
|
||||||
entry.file_type().is_ok_and(|file_type| file_type.is_dir()),
|
std::fs::metadata(entry.path()).is_ok_and(|metadata| metadata.is_dir()),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
|
@ -65,6 +65,7 @@ julia = { command = "julia", timeout = 60, args = [ "--startup-file=no", "--hist
|
||||||
just-lsp = { command = "just-lsp" }
|
just-lsp = { command = "just-lsp" }
|
||||||
koka = { command = "koka", args = ["--language-server", "--lsstdio"] }
|
koka = { command = "koka", args = ["--language-server", "--lsstdio"] }
|
||||||
koto-ls = { command = "koto-ls" }
|
koto-ls = { command = "koto-ls" }
|
||||||
|
kotlin-lsp = { command = "kotlin-lsp", args = ["--stdio"] }
|
||||||
kotlin-language-server = { command = "kotlin-language-server" }
|
kotlin-language-server = { command = "kotlin-language-server" }
|
||||||
lean = { command = "lean", args = [ "--server", "--memory=1024" ] }
|
lean = { command = "lean", args = [ "--server", "--memory=1024" ] }
|
||||||
ltex-ls = { command = "ltex-ls" }
|
ltex-ls = { command = "ltex-ls" }
|
||||||
|
@ -1021,6 +1022,7 @@ shebangs = []
|
||||||
comment-token = "#"
|
comment-token = "#"
|
||||||
language-servers = [ "nil", "nixd" ]
|
language-servers = [ "nil", "nixd" ]
|
||||||
indent = { tab-width = 2, unit = " " }
|
indent = { tab-width = 2, unit = " " }
|
||||||
|
formatter = { command = "nixfmt" }
|
||||||
|
|
||||||
[[grammar]]
|
[[grammar]]
|
||||||
name = "nix"
|
name = "nix"
|
||||||
|
@ -3068,7 +3070,7 @@ formatter = { command = "inko", args = ["fmt", "-"] }
|
||||||
|
|
||||||
[[grammar]]
|
[[grammar]]
|
||||||
name = "inko"
|
name = "inko"
|
||||||
source = { git = "https://github.com/inko-lang/tree-sitter-inko", rev = "7860637ce1b43f5f79cfb7cc3311bf3234e9479f" }
|
source = { git = "https://github.com/inko-lang/tree-sitter-inko", rev = "f58a87ac4dc6a7955c64c9e4408fbd693e804686" }
|
||||||
|
|
||||||
[[language]]
|
[[language]]
|
||||||
name = "bicep"
|
name = "bicep"
|
||||||
|
@ -4242,10 +4244,11 @@ comment-token = "#"
|
||||||
block-comment-tokens = ["#-", "-#"]
|
block-comment-tokens = ["#-", "-#"]
|
||||||
indent = { tab-width = 2, unit = " " }
|
indent = { tab-width = 2, unit = " " }
|
||||||
language-servers = ["koto-ls"]
|
language-servers = ["koto-ls"]
|
||||||
|
formatter = {command = "koto", args = ["--format"]}
|
||||||
|
|
||||||
[[grammar]]
|
[[grammar]]
|
||||||
name = "koto"
|
name = "koto"
|
||||||
source = { git = "https://github.com/koto-lang/tree-sitter-koto", rev = "b420f7922d0d74905fd0d771e5b83be9ee8a8a9a" }
|
source = { git = "https://github.com/koto-lang/tree-sitter-koto", rev = "2ffc77c14f0ac1674384ff629bfc207b9c57ed89" }
|
||||||
|
|
||||||
[[language]]
|
[[language]]
|
||||||
name = "gpr"
|
name = "gpr"
|
||||||
|
|
|
@ -78,7 +78,7 @@
|
||||||
] @keyword.operator
|
] @keyword.operator
|
||||||
|
|
||||||
[
|
[
|
||||||
"class"
|
"type"
|
||||||
"trait"
|
"trait"
|
||||||
] @keyword.storage.type
|
] @keyword.storage.type
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
(class
|
||||||
|
name: _ @definition.struct)
|
||||||
|
|
||||||
|
(trait
|
||||||
|
name: _ @definition.interface)
|
||||||
|
|
||||||
|
(external_function
|
||||||
|
name: _ @definition.function)
|
||||||
|
|
||||||
|
(method
|
||||||
|
name: _ @definition.function)
|
||||||
|
|
||||||
|
(define_constant
|
||||||
|
name: _ @definition.constant)
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,28 @@
|
||||||
|
; aligns forms to the second position if there's two in a line:
|
||||||
|
; (-> 10
|
||||||
|
; (* 2)
|
||||||
|
; (print))
|
||||||
|
(par_tup_lit . (sym_lit) @first . (_) @anchor
|
||||||
|
(#set! "scope" "tail")
|
||||||
|
(#same-line? @first @anchor)
|
||||||
|
; anything that doesn't match should be indented normally
|
||||||
|
; from https://github.com/janet-lang/spork/blob/5601dc883535473bca28351cc6df04ed6c656c65/spork/fmt.janet#L87C12-L93C38
|
||||||
|
(#not-match? @first "^(fn|match|with|with-dyns|def|def-|var|var-|defn|defn-|varfn|defmacro|defmacro-|defer|edefer|loop|seq|tabseq|catseq|generate|coro|for|each|eachp|eachk|case|cond|do|defglobal|varglobal|if|when|when-let|when-with|while|with-syms|with-vars|if-let|if-not|if-with|let|short-fn|try|unless|default|forever|upscope|repeat|forv|compwhen|compif|ev/spawn|ev/do-thread|ev/spawn-thread|ev/with-deadline|label|prompt|forever)$")) @align
|
||||||
|
|
||||||
|
; everything else should be indented normally:
|
||||||
|
;
|
||||||
|
; (let [foo 10]
|
||||||
|
; (print foo))
|
||||||
|
;
|
||||||
|
; (foo
|
||||||
|
; bar)
|
||||||
|
(par_tup_lit . (sym_lit)) @indent
|
||||||
|
|
||||||
|
; for `{}` and `[]`:
|
||||||
|
; {:foo 10
|
||||||
|
; :bar 20}
|
||||||
|
(struct_lit . (_) @anchor) @align
|
||||||
|
|
||||||
|
; [foo
|
||||||
|
; bar]
|
||||||
|
(sqr_tup_lit . (_) @anchor) @align
|
|
@ -0,0 +1,2 @@
|
||||||
|
((comment) @injection.content
|
||||||
|
(#set! injection.language "comment"))
|
|
@ -5,11 +5,13 @@
|
||||||
"*"
|
"*"
|
||||||
"/"
|
"/"
|
||||||
"%"
|
"%"
|
||||||
|
"^"
|
||||||
"+="
|
"+="
|
||||||
"-="
|
"-="
|
||||||
"*="
|
"*="
|
||||||
"/="
|
"/="
|
||||||
"%="
|
"%="
|
||||||
|
"^="
|
||||||
"=="
|
"=="
|
||||||
"!="
|
"!="
|
||||||
"<"
|
"<"
|
||||||
|
@ -99,12 +101,18 @@
|
||||||
(export
|
(export
|
||||||
(identifier) @namespace)
|
(identifier) @namespace)
|
||||||
|
|
||||||
(call
|
(chain
|
||||||
function: (identifier) @function.method)
|
start: (identifier) @function)
|
||||||
|
|
||||||
(chain
|
(chain
|
||||||
lookup: (identifier) @variable.other.member)
|
lookup: (identifier) @variable.other.member)
|
||||||
|
|
||||||
|
(call
|
||||||
|
function: (identifier)) @function
|
||||||
|
|
||||||
|
(call_arg
|
||||||
|
(identifier) @variable.other.member)
|
||||||
|
|
||||||
[
|
[
|
||||||
(true)
|
(true)
|
||||||
(false)
|
(false)
|
||||||
|
@ -139,13 +147,10 @@
|
||||||
|
|
||||||
(self) @variable.builtin
|
(self) @variable.builtin
|
||||||
|
|
||||||
(variable
|
(type
|
||||||
type: (identifier) @type)
|
_ @type)
|
||||||
|
|
||||||
(arg
|
(arg
|
||||||
(_ (identifier) @variable.parameter))
|
(_ (identifier) @variable.parameter))
|
||||||
|
|
||||||
(ellipsis) @variable.parameter
|
(ellipsis) @variable.parameter
|
||||||
|
|
||||||
(function
|
|
||||||
output_type: (identifier) @type)
|
|
||||||
|
|
|
@ -11,10 +11,6 @@
|
||||||
(call_args
|
(call_args
|
||||||
((call_arg) @parameter.inside . ","? @parameter.around) @parameter.around)
|
((call_arg) @parameter.inside . ","? @parameter.around) @parameter.around)
|
||||||
|
|
||||||
(chain
|
|
||||||
call: (tuple
|
|
||||||
((element) @parameter.inside . ","? @parameter.around) @parameter.around))
|
|
||||||
|
|
||||||
(map
|
(map
|
||||||
((entry_inline) @entry.inside . ","? @entry.around) @entry.around)
|
((entry_inline) @entry.inside . ","? @entry.around) @entry.around)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue