mirror of https://github.com/helix-editor/helix
Add live preview to theme picker (#1798)
* Add theme picker with live preview * Add live theme preview to :theme command * cargo fmt * Fix clippy warnings * Remove picker variant * Remove unused import * Cleanup * Change current_theme to last_theme * Fix accidental comment flash deletion * Typo * Remove theme cache * Add some comments * Refactor some theme handling TIL flatmap on Option is called and_then * Remove unnecessary renames * Constrain last_theme theme preview lifecycle * Switch to bitflag implementation * Better handling of last_theme * Sort theme names * Better memory juggling * Missed a branch * Remove name from theme, switch bitand to & * cargo fmt * Update helix-view/src/editor.rs * Switch boolean to enum * Remove bitflag impl * cargo fmt * Remove un-needed type arg * cargo fmtpull/2982/head
parent
85411bed83
commit
b26e7e2e8f
|
@ -108,13 +108,7 @@ impl Application {
|
||||||
.ok()
|
.ok()
|
||||||
.filter(|theme| (true_color || theme.is_16_color()))
|
.filter(|theme| (true_color || theme.is_16_color()))
|
||||||
})
|
})
|
||||||
.unwrap_or_else(|| {
|
.unwrap_or_else(|| theme_loader.default_theme(true_color));
|
||||||
if true_color {
|
|
||||||
theme_loader.default()
|
|
||||||
} else {
|
|
||||||
theme_loader.base16_default()
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let syn_loader_conf = user_syntax_loader().unwrap_or_else(|err| {
|
let syn_loader_conf = user_syntax_loader().unwrap_or_else(|err| {
|
||||||
eprintln!("Bad language config: {}", err);
|
eprintln!("Bad language config: {}", err);
|
||||||
|
@ -373,13 +367,7 @@ impl Application {
|
||||||
})
|
})
|
||||||
.ok()
|
.ok()
|
||||||
.filter(|theme| (true_color || theme.is_16_color()))
|
.filter(|theme| (true_color || theme.is_16_color()))
|
||||||
.unwrap_or_else(|| {
|
.unwrap_or_else(|| self.theme_loader.default_theme(true_color)),
|
||||||
if true_color {
|
|
||||||
self.theme_loader.default()
|
|
||||||
} else {
|
|
||||||
self.theme_loader.base16_default()
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,11 +15,11 @@ pub struct TypableCommand {
|
||||||
pub completer: Option<Completer>,
|
pub completer: Option<Completer>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn quit(
|
fn quit(cx: &mut compositor::Context, args: &[Cow<str>], event: PromptEvent) -> anyhow::Result<()> {
|
||||||
cx: &mut compositor::Context,
|
if event != PromptEvent::Validate {
|
||||||
args: &[Cow<str>],
|
return Ok(());
|
||||||
_event: PromptEvent,
|
}
|
||||||
) -> anyhow::Result<()> {
|
|
||||||
ensure!(args.is_empty(), ":quit takes no arguments");
|
ensure!(args.is_empty(), ":quit takes no arguments");
|
||||||
|
|
||||||
// last view and we have unsaved changes
|
// last view and we have unsaved changes
|
||||||
|
@ -35,8 +35,12 @@ fn quit(
|
||||||
fn force_quit(
|
fn force_quit(
|
||||||
cx: &mut compositor::Context,
|
cx: &mut compositor::Context,
|
||||||
args: &[Cow<str>],
|
args: &[Cow<str>],
|
||||||
_event: PromptEvent,
|
event: PromptEvent,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
if event != PromptEvent::Validate {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
ensure!(args.is_empty(), ":quit! takes no arguments");
|
ensure!(args.is_empty(), ":quit! takes no arguments");
|
||||||
|
|
||||||
cx.editor.close(view!(cx.editor).id);
|
cx.editor.close(view!(cx.editor).id);
|
||||||
|
@ -44,11 +48,11 @@ fn force_quit(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn open(
|
fn open(cx: &mut compositor::Context, args: &[Cow<str>], event: PromptEvent) -> anyhow::Result<()> {
|
||||||
cx: &mut compositor::Context,
|
if event != PromptEvent::Validate {
|
||||||
args: &[Cow<str>],
|
return Ok(());
|
||||||
_event: PromptEvent,
|
}
|
||||||
) -> anyhow::Result<()> {
|
|
||||||
ensure!(!args.is_empty(), "wrong argument count");
|
ensure!(!args.is_empty(), "wrong argument count");
|
||||||
for arg in args {
|
for arg in args {
|
||||||
let (path, pos) = args::parse_file(arg);
|
let (path, pos) = args::parse_file(arg);
|
||||||
|
@ -114,8 +118,12 @@ fn buffer_gather_paths_impl(editor: &mut Editor, args: &[Cow<str>]) -> Vec<Docum
|
||||||
fn buffer_close(
|
fn buffer_close(
|
||||||
cx: &mut compositor::Context,
|
cx: &mut compositor::Context,
|
||||||
args: &[Cow<str>],
|
args: &[Cow<str>],
|
||||||
_event: PromptEvent,
|
event: PromptEvent,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
if event != PromptEvent::Validate {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
let document_ids = buffer_gather_paths_impl(cx.editor, args);
|
let document_ids = buffer_gather_paths_impl(cx.editor, args);
|
||||||
buffer_close_by_ids_impl(cx.editor, &document_ids, false)
|
buffer_close_by_ids_impl(cx.editor, &document_ids, false)
|
||||||
}
|
}
|
||||||
|
@ -123,8 +131,12 @@ fn buffer_close(
|
||||||
fn force_buffer_close(
|
fn force_buffer_close(
|
||||||
cx: &mut compositor::Context,
|
cx: &mut compositor::Context,
|
||||||
args: &[Cow<str>],
|
args: &[Cow<str>],
|
||||||
_event: PromptEvent,
|
event: PromptEvent,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
if event != PromptEvent::Validate {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
let document_ids = buffer_gather_paths_impl(cx.editor, args);
|
let document_ids = buffer_gather_paths_impl(cx.editor, args);
|
||||||
buffer_close_by_ids_impl(cx.editor, &document_ids, true)
|
buffer_close_by_ids_impl(cx.editor, &document_ids, true)
|
||||||
}
|
}
|
||||||
|
@ -141,8 +153,12 @@ fn buffer_gather_others_impl(editor: &mut Editor) -> Vec<DocumentId> {
|
||||||
fn buffer_close_others(
|
fn buffer_close_others(
|
||||||
cx: &mut compositor::Context,
|
cx: &mut compositor::Context,
|
||||||
_args: &[Cow<str>],
|
_args: &[Cow<str>],
|
||||||
_event: PromptEvent,
|
event: PromptEvent,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
if event != PromptEvent::Validate {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
let document_ids = buffer_gather_others_impl(cx.editor);
|
let document_ids = buffer_gather_others_impl(cx.editor);
|
||||||
buffer_close_by_ids_impl(cx.editor, &document_ids, false)
|
buffer_close_by_ids_impl(cx.editor, &document_ids, false)
|
||||||
}
|
}
|
||||||
|
@ -150,8 +166,12 @@ fn buffer_close_others(
|
||||||
fn force_buffer_close_others(
|
fn force_buffer_close_others(
|
||||||
cx: &mut compositor::Context,
|
cx: &mut compositor::Context,
|
||||||
_args: &[Cow<str>],
|
_args: &[Cow<str>],
|
||||||
_event: PromptEvent,
|
event: PromptEvent,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
if event != PromptEvent::Validate {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
let document_ids = buffer_gather_others_impl(cx.editor);
|
let document_ids = buffer_gather_others_impl(cx.editor);
|
||||||
buffer_close_by_ids_impl(cx.editor, &document_ids, true)
|
buffer_close_by_ids_impl(cx.editor, &document_ids, true)
|
||||||
}
|
}
|
||||||
|
@ -163,8 +183,12 @@ fn buffer_gather_all_impl(editor: &mut Editor) -> Vec<DocumentId> {
|
||||||
fn buffer_close_all(
|
fn buffer_close_all(
|
||||||
cx: &mut compositor::Context,
|
cx: &mut compositor::Context,
|
||||||
_args: &[Cow<str>],
|
_args: &[Cow<str>],
|
||||||
_event: PromptEvent,
|
event: PromptEvent,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
if event != PromptEvent::Validate {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
let document_ids = buffer_gather_all_impl(cx.editor);
|
let document_ids = buffer_gather_all_impl(cx.editor);
|
||||||
buffer_close_by_ids_impl(cx.editor, &document_ids, false)
|
buffer_close_by_ids_impl(cx.editor, &document_ids, false)
|
||||||
}
|
}
|
||||||
|
@ -172,8 +196,12 @@ fn buffer_close_all(
|
||||||
fn force_buffer_close_all(
|
fn force_buffer_close_all(
|
||||||
cx: &mut compositor::Context,
|
cx: &mut compositor::Context,
|
||||||
_args: &[Cow<str>],
|
_args: &[Cow<str>],
|
||||||
_event: PromptEvent,
|
event: PromptEvent,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
if event != PromptEvent::Validate {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
let document_ids = buffer_gather_all_impl(cx.editor);
|
let document_ids = buffer_gather_all_impl(cx.editor);
|
||||||
buffer_close_by_ids_impl(cx.editor, &document_ids, true)
|
buffer_close_by_ids_impl(cx.editor, &document_ids, true)
|
||||||
}
|
}
|
||||||
|
@ -181,8 +209,12 @@ fn force_buffer_close_all(
|
||||||
fn buffer_next(
|
fn buffer_next(
|
||||||
cx: &mut compositor::Context,
|
cx: &mut compositor::Context,
|
||||||
_args: &[Cow<str>],
|
_args: &[Cow<str>],
|
||||||
_event: PromptEvent,
|
event: PromptEvent,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
if event != PromptEvent::Validate {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
goto_buffer(cx.editor, Direction::Forward);
|
goto_buffer(cx.editor, Direction::Forward);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -190,8 +222,12 @@ fn buffer_next(
|
||||||
fn buffer_previous(
|
fn buffer_previous(
|
||||||
cx: &mut compositor::Context,
|
cx: &mut compositor::Context,
|
||||||
_args: &[Cow<str>],
|
_args: &[Cow<str>],
|
||||||
_event: PromptEvent,
|
event: PromptEvent,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
if event != PromptEvent::Validate {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
goto_buffer(cx.editor, Direction::Backward);
|
goto_buffer(cx.editor, Direction::Backward);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -242,24 +278,36 @@ fn write_impl(
|
||||||
fn write(
|
fn write(
|
||||||
cx: &mut compositor::Context,
|
cx: &mut compositor::Context,
|
||||||
args: &[Cow<str>],
|
args: &[Cow<str>],
|
||||||
_event: PromptEvent,
|
event: PromptEvent,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
if event != PromptEvent::Validate {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
write_impl(cx, args.first(), false)
|
write_impl(cx, args.first(), false)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn force_write(
|
fn force_write(
|
||||||
cx: &mut compositor::Context,
|
cx: &mut compositor::Context,
|
||||||
args: &[Cow<str>],
|
args: &[Cow<str>],
|
||||||
_event: PromptEvent,
|
event: PromptEvent,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
if event != PromptEvent::Validate {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
write_impl(cx, args.first(), true)
|
write_impl(cx, args.first(), true)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_file(
|
fn new_file(
|
||||||
cx: &mut compositor::Context,
|
cx: &mut compositor::Context,
|
||||||
_args: &[Cow<str>],
|
_args: &[Cow<str>],
|
||||||
_event: PromptEvent,
|
event: PromptEvent,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
if event != PromptEvent::Validate {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
cx.editor.new_file(Action::Replace);
|
cx.editor.new_file(Action::Replace);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -268,8 +316,12 @@ fn new_file(
|
||||||
fn format(
|
fn format(
|
||||||
cx: &mut compositor::Context,
|
cx: &mut compositor::Context,
|
||||||
_args: &[Cow<str>],
|
_args: &[Cow<str>],
|
||||||
_event: PromptEvent,
|
event: PromptEvent,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
if event != PromptEvent::Validate {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
let doc = doc!(cx.editor);
|
let doc = doc!(cx.editor);
|
||||||
if let Some(format) = doc.format() {
|
if let Some(format) = doc.format() {
|
||||||
let callback =
|
let callback =
|
||||||
|
@ -282,8 +334,12 @@ fn format(
|
||||||
fn set_indent_style(
|
fn set_indent_style(
|
||||||
cx: &mut compositor::Context,
|
cx: &mut compositor::Context,
|
||||||
args: &[Cow<str>],
|
args: &[Cow<str>],
|
||||||
_event: PromptEvent,
|
event: PromptEvent,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
if event != PromptEvent::Validate {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
use IndentStyle::*;
|
use IndentStyle::*;
|
||||||
|
|
||||||
// If no argument, report current indent style.
|
// If no argument, report current indent style.
|
||||||
|
@ -321,8 +377,12 @@ fn set_indent_style(
|
||||||
fn set_line_ending(
|
fn set_line_ending(
|
||||||
cx: &mut compositor::Context,
|
cx: &mut compositor::Context,
|
||||||
args: &[Cow<str>],
|
args: &[Cow<str>],
|
||||||
_event: PromptEvent,
|
event: PromptEvent,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
if event != PromptEvent::Validate {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
use LineEnding::*;
|
use LineEnding::*;
|
||||||
|
|
||||||
// If no argument, report current line ending setting.
|
// If no argument, report current line ending setting.
|
||||||
|
@ -391,8 +451,12 @@ fn set_line_ending(
|
||||||
fn earlier(
|
fn earlier(
|
||||||
cx: &mut compositor::Context,
|
cx: &mut compositor::Context,
|
||||||
args: &[Cow<str>],
|
args: &[Cow<str>],
|
||||||
_event: PromptEvent,
|
event: PromptEvent,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
if event != PromptEvent::Validate {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
let uk = args.join(" ").parse::<UndoKind>().map_err(|s| anyhow!(s))?;
|
let uk = args.join(" ").parse::<UndoKind>().map_err(|s| anyhow!(s))?;
|
||||||
|
|
||||||
let (view, doc) = current!(cx.editor);
|
let (view, doc) = current!(cx.editor);
|
||||||
|
@ -407,8 +471,12 @@ fn earlier(
|
||||||
fn later(
|
fn later(
|
||||||
cx: &mut compositor::Context,
|
cx: &mut compositor::Context,
|
||||||
args: &[Cow<str>],
|
args: &[Cow<str>],
|
||||||
_event: PromptEvent,
|
event: PromptEvent,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
if event != PromptEvent::Validate {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
let uk = args.join(" ").parse::<UndoKind>().map_err(|s| anyhow!(s))?;
|
let uk = args.join(" ").parse::<UndoKind>().map_err(|s| anyhow!(s))?;
|
||||||
let (view, doc) = current!(cx.editor);
|
let (view, doc) = current!(cx.editor);
|
||||||
let success = doc.later(view.id, uk);
|
let success = doc.later(view.id, uk);
|
||||||
|
@ -424,6 +492,10 @@ fn write_quit(
|
||||||
args: &[Cow<str>],
|
args: &[Cow<str>],
|
||||||
event: PromptEvent,
|
event: PromptEvent,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
if event != PromptEvent::Validate {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
write_impl(cx, args.first(), false)?;
|
write_impl(cx, args.first(), false)?;
|
||||||
helix_lsp::block_on(cx.jobs.finish())?;
|
helix_lsp::block_on(cx.jobs.finish())?;
|
||||||
quit(cx, &[], event)
|
quit(cx, &[], event)
|
||||||
|
@ -434,6 +506,10 @@ fn force_write_quit(
|
||||||
args: &[Cow<str>],
|
args: &[Cow<str>],
|
||||||
event: PromptEvent,
|
event: PromptEvent,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
if event != PromptEvent::Validate {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
write_impl(cx, args.first(), true)?;
|
write_impl(cx, args.first(), true)?;
|
||||||
force_quit(cx, &[], event)
|
force_quit(cx, &[], event)
|
||||||
}
|
}
|
||||||
|
@ -463,10 +539,14 @@ pub(super) fn buffers_remaining_impl(editor: &mut Editor) -> anyhow::Result<()>
|
||||||
fn write_all_impl(
|
fn write_all_impl(
|
||||||
cx: &mut compositor::Context,
|
cx: &mut compositor::Context,
|
||||||
_args: &[Cow<str>],
|
_args: &[Cow<str>],
|
||||||
_event: PromptEvent,
|
event: PromptEvent,
|
||||||
quit: bool,
|
quit: bool,
|
||||||
force: bool,
|
force: bool,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
if event != PromptEvent::Validate {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
let mut errors = String::new();
|
let mut errors = String::new();
|
||||||
let auto_format = cx.editor.config().auto_format;
|
let auto_format = cx.editor.config().auto_format;
|
||||||
let jobs = &mut cx.jobs;
|
let jobs = &mut cx.jobs;
|
||||||
|
@ -520,6 +600,10 @@ fn write_all(
|
||||||
args: &[Cow<str>],
|
args: &[Cow<str>],
|
||||||
event: PromptEvent,
|
event: PromptEvent,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
if event != PromptEvent::Validate {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
write_all_impl(cx, args, event, false, false)
|
write_all_impl(cx, args, event, false, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -528,6 +612,10 @@ fn write_all_quit(
|
||||||
args: &[Cow<str>],
|
args: &[Cow<str>],
|
||||||
event: PromptEvent,
|
event: PromptEvent,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
if event != PromptEvent::Validate {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
write_all_impl(cx, args, event, true, false)
|
write_all_impl(cx, args, event, true, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -536,6 +624,10 @@ fn force_write_all_quit(
|
||||||
args: &[Cow<str>],
|
args: &[Cow<str>],
|
||||||
event: PromptEvent,
|
event: PromptEvent,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
if event != PromptEvent::Validate {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
write_all_impl(cx, args, event, true, true)
|
write_all_impl(cx, args, event, true, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -556,24 +648,36 @@ fn quit_all_impl(editor: &mut Editor, force: bool) -> anyhow::Result<()> {
|
||||||
fn quit_all(
|
fn quit_all(
|
||||||
cx: &mut compositor::Context,
|
cx: &mut compositor::Context,
|
||||||
_args: &[Cow<str>],
|
_args: &[Cow<str>],
|
||||||
_event: PromptEvent,
|
event: PromptEvent,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
if event != PromptEvent::Validate {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
quit_all_impl(cx.editor, false)
|
quit_all_impl(cx.editor, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn force_quit_all(
|
fn force_quit_all(
|
||||||
cx: &mut compositor::Context,
|
cx: &mut compositor::Context,
|
||||||
_args: &[Cow<str>],
|
_args: &[Cow<str>],
|
||||||
_event: PromptEvent,
|
event: PromptEvent,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
if event != PromptEvent::Validate {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
quit_all_impl(cx.editor, true)
|
quit_all_impl(cx.editor, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cquit(
|
fn cquit(
|
||||||
cx: &mut compositor::Context,
|
cx: &mut compositor::Context,
|
||||||
args: &[Cow<str>],
|
args: &[Cow<str>],
|
||||||
_event: PromptEvent,
|
event: PromptEvent,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
if event != PromptEvent::Validate {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
let exit_code = args
|
let exit_code = args
|
||||||
.first()
|
.first()
|
||||||
.and_then(|code| code.parse::<i32>().ok())
|
.and_then(|code| code.parse::<i32>().ok())
|
||||||
|
@ -586,8 +690,12 @@ fn cquit(
|
||||||
fn force_cquit(
|
fn force_cquit(
|
||||||
cx: &mut compositor::Context,
|
cx: &mut compositor::Context,
|
||||||
args: &[Cow<str>],
|
args: &[Cow<str>],
|
||||||
_event: PromptEvent,
|
event: PromptEvent,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
if event != PromptEvent::Validate {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
let exit_code = args
|
let exit_code = args
|
||||||
.first()
|
.first()
|
||||||
.and_then(|code| code.parse::<i32>().ok())
|
.and_then(|code| code.parse::<i32>().ok())
|
||||||
|
@ -600,35 +708,61 @@ fn force_cquit(
|
||||||
fn theme(
|
fn theme(
|
||||||
cx: &mut compositor::Context,
|
cx: &mut compositor::Context,
|
||||||
args: &[Cow<str>],
|
args: &[Cow<str>],
|
||||||
_event: PromptEvent,
|
event: PromptEvent,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
let theme = args.first().context("Theme not provided")?;
|
let true_color = cx.editor.config.load().true_color || crate::true_color();
|
||||||
|
match event {
|
||||||
|
PromptEvent::Abort => {
|
||||||
|
cx.editor.unset_theme_preview();
|
||||||
|
}
|
||||||
|
PromptEvent::Update => {
|
||||||
|
if let Some(theme_name) = args.first() {
|
||||||
|
if let Ok(theme) = cx.editor.theme_loader.load(theme_name) {
|
||||||
|
if !(true_color || theme.is_16_color()) {
|
||||||
|
bail!("Unsupported theme: theme requires true color support");
|
||||||
|
}
|
||||||
|
cx.editor.set_theme_preview(theme);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
PromptEvent::Validate => {
|
||||||
|
let theme_name = args.first().with_context(|| "Theme name not provided")?;
|
||||||
let theme = cx
|
let theme = cx
|
||||||
.editor
|
.editor
|
||||||
.theme_loader
|
.theme_loader
|
||||||
.load(theme)
|
.load(theme_name)
|
||||||
.with_context(|| format!("Failed setting theme {}", theme))?;
|
.with_context(|| "Theme does not exist")?;
|
||||||
let true_color = cx.editor.config().true_color || crate::true_color();
|
|
||||||
if !(true_color || theme.is_16_color()) {
|
if !(true_color || theme.is_16_color()) {
|
||||||
bail!("Unsupported theme: theme requires true color support");
|
bail!("Unsupported theme: theme requires true color support");
|
||||||
}
|
}
|
||||||
cx.editor.set_theme(theme);
|
cx.editor.set_theme(theme);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn yank_main_selection_to_clipboard(
|
fn yank_main_selection_to_clipboard(
|
||||||
cx: &mut compositor::Context,
|
cx: &mut compositor::Context,
|
||||||
_args: &[Cow<str>],
|
_args: &[Cow<str>],
|
||||||
_event: PromptEvent,
|
event: PromptEvent,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
if event != PromptEvent::Validate {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
yank_main_selection_to_clipboard_impl(cx.editor, ClipboardType::Clipboard)
|
yank_main_selection_to_clipboard_impl(cx.editor, ClipboardType::Clipboard)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn yank_joined_to_clipboard(
|
fn yank_joined_to_clipboard(
|
||||||
cx: &mut compositor::Context,
|
cx: &mut compositor::Context,
|
||||||
args: &[Cow<str>],
|
args: &[Cow<str>],
|
||||||
_event: PromptEvent,
|
event: PromptEvent,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
if event != PromptEvent::Validate {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
let doc = doc!(cx.editor);
|
let doc = doc!(cx.editor);
|
||||||
let default_sep = Cow::Borrowed(doc.line_ending.as_str());
|
let default_sep = Cow::Borrowed(doc.line_ending.as_str());
|
||||||
let separator = args.first().unwrap_or(&default_sep);
|
let separator = args.first().unwrap_or(&default_sep);
|
||||||
|
@ -638,16 +772,24 @@ fn yank_joined_to_clipboard(
|
||||||
fn yank_main_selection_to_primary_clipboard(
|
fn yank_main_selection_to_primary_clipboard(
|
||||||
cx: &mut compositor::Context,
|
cx: &mut compositor::Context,
|
||||||
_args: &[Cow<str>],
|
_args: &[Cow<str>],
|
||||||
_event: PromptEvent,
|
event: PromptEvent,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
if event != PromptEvent::Validate {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
yank_main_selection_to_clipboard_impl(cx.editor, ClipboardType::Selection)
|
yank_main_selection_to_clipboard_impl(cx.editor, ClipboardType::Selection)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn yank_joined_to_primary_clipboard(
|
fn yank_joined_to_primary_clipboard(
|
||||||
cx: &mut compositor::Context,
|
cx: &mut compositor::Context,
|
||||||
args: &[Cow<str>],
|
args: &[Cow<str>],
|
||||||
_event: PromptEvent,
|
event: PromptEvent,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
if event != PromptEvent::Validate {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
let doc = doc!(cx.editor);
|
let doc = doc!(cx.editor);
|
||||||
let default_sep = Cow::Borrowed(doc.line_ending.as_str());
|
let default_sep = Cow::Borrowed(doc.line_ending.as_str());
|
||||||
let separator = args.first().unwrap_or(&default_sep);
|
let separator = args.first().unwrap_or(&default_sep);
|
||||||
|
@ -657,32 +799,48 @@ fn yank_joined_to_primary_clipboard(
|
||||||
fn paste_clipboard_after(
|
fn paste_clipboard_after(
|
||||||
cx: &mut compositor::Context,
|
cx: &mut compositor::Context,
|
||||||
_args: &[Cow<str>],
|
_args: &[Cow<str>],
|
||||||
_event: PromptEvent,
|
event: PromptEvent,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
if event != PromptEvent::Validate {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
paste_clipboard_impl(cx.editor, Paste::After, ClipboardType::Clipboard, 1)
|
paste_clipboard_impl(cx.editor, Paste::After, ClipboardType::Clipboard, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paste_clipboard_before(
|
fn paste_clipboard_before(
|
||||||
cx: &mut compositor::Context,
|
cx: &mut compositor::Context,
|
||||||
_args: &[Cow<str>],
|
_args: &[Cow<str>],
|
||||||
_event: PromptEvent,
|
event: PromptEvent,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
if event != PromptEvent::Validate {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
paste_clipboard_impl(cx.editor, Paste::Before, ClipboardType::Clipboard, 1)
|
paste_clipboard_impl(cx.editor, Paste::Before, ClipboardType::Clipboard, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paste_primary_clipboard_after(
|
fn paste_primary_clipboard_after(
|
||||||
cx: &mut compositor::Context,
|
cx: &mut compositor::Context,
|
||||||
_args: &[Cow<str>],
|
_args: &[Cow<str>],
|
||||||
_event: PromptEvent,
|
event: PromptEvent,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
if event != PromptEvent::Validate {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
paste_clipboard_impl(cx.editor, Paste::After, ClipboardType::Selection, 1)
|
paste_clipboard_impl(cx.editor, Paste::After, ClipboardType::Selection, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paste_primary_clipboard_before(
|
fn paste_primary_clipboard_before(
|
||||||
cx: &mut compositor::Context,
|
cx: &mut compositor::Context,
|
||||||
_args: &[Cow<str>],
|
_args: &[Cow<str>],
|
||||||
_event: PromptEvent,
|
event: PromptEvent,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
if event != PromptEvent::Validate {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
paste_clipboard_impl(cx.editor, Paste::Before, ClipboardType::Selection, 1)
|
paste_clipboard_impl(cx.editor, Paste::Before, ClipboardType::Selection, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -710,24 +868,36 @@ fn replace_selections_with_clipboard_impl(
|
||||||
fn replace_selections_with_clipboard(
|
fn replace_selections_with_clipboard(
|
||||||
cx: &mut compositor::Context,
|
cx: &mut compositor::Context,
|
||||||
_args: &[Cow<str>],
|
_args: &[Cow<str>],
|
||||||
_event: PromptEvent,
|
event: PromptEvent,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
if event != PromptEvent::Validate {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
replace_selections_with_clipboard_impl(cx, ClipboardType::Clipboard)
|
replace_selections_with_clipboard_impl(cx, ClipboardType::Clipboard)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn replace_selections_with_primary_clipboard(
|
fn replace_selections_with_primary_clipboard(
|
||||||
cx: &mut compositor::Context,
|
cx: &mut compositor::Context,
|
||||||
_args: &[Cow<str>],
|
_args: &[Cow<str>],
|
||||||
_event: PromptEvent,
|
event: PromptEvent,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
if event != PromptEvent::Validate {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
replace_selections_with_clipboard_impl(cx, ClipboardType::Selection)
|
replace_selections_with_clipboard_impl(cx, ClipboardType::Selection)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn show_clipboard_provider(
|
fn show_clipboard_provider(
|
||||||
cx: &mut compositor::Context,
|
cx: &mut compositor::Context,
|
||||||
_args: &[Cow<str>],
|
_args: &[Cow<str>],
|
||||||
_event: PromptEvent,
|
event: PromptEvent,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
if event != PromptEvent::Validate {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
cx.editor
|
cx.editor
|
||||||
.set_status(cx.editor.clipboard_provider.name().to_string());
|
.set_status(cx.editor.clipboard_provider.name().to_string());
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -736,8 +906,12 @@ fn show_clipboard_provider(
|
||||||
fn change_current_directory(
|
fn change_current_directory(
|
||||||
cx: &mut compositor::Context,
|
cx: &mut compositor::Context,
|
||||||
args: &[Cow<str>],
|
args: &[Cow<str>],
|
||||||
_event: PromptEvent,
|
event: PromptEvent,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
if event != PromptEvent::Validate {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
let dir = helix_core::path::expand_tilde(
|
let dir = helix_core::path::expand_tilde(
|
||||||
args.first()
|
args.first()
|
||||||
.context("target directory not provided")?
|
.context("target directory not provided")?
|
||||||
|
@ -760,8 +934,12 @@ fn change_current_directory(
|
||||||
fn show_current_directory(
|
fn show_current_directory(
|
||||||
cx: &mut compositor::Context,
|
cx: &mut compositor::Context,
|
||||||
_args: &[Cow<str>],
|
_args: &[Cow<str>],
|
||||||
_event: PromptEvent,
|
event: PromptEvent,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
if event != PromptEvent::Validate {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
let cwd = std::env::current_dir().context("Couldn't get the new working directory")?;
|
let cwd = std::env::current_dir().context("Couldn't get the new working directory")?;
|
||||||
cx.editor
|
cx.editor
|
||||||
.set_status(format!("Current working directory is {}", cwd.display()));
|
.set_status(format!("Current working directory is {}", cwd.display()));
|
||||||
|
@ -772,8 +950,12 @@ fn show_current_directory(
|
||||||
fn set_encoding(
|
fn set_encoding(
|
||||||
cx: &mut compositor::Context,
|
cx: &mut compositor::Context,
|
||||||
args: &[Cow<str>],
|
args: &[Cow<str>],
|
||||||
_event: PromptEvent,
|
event: PromptEvent,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
if event != PromptEvent::Validate {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
let doc = doc_mut!(cx.editor);
|
let doc = doc_mut!(cx.editor);
|
||||||
if let Some(label) = args.first() {
|
if let Some(label) = args.first() {
|
||||||
doc.set_encoding(label)
|
doc.set_encoding(label)
|
||||||
|
@ -788,8 +970,12 @@ fn set_encoding(
|
||||||
fn reload(
|
fn reload(
|
||||||
cx: &mut compositor::Context,
|
cx: &mut compositor::Context,
|
||||||
_args: &[Cow<str>],
|
_args: &[Cow<str>],
|
||||||
_event: PromptEvent,
|
event: PromptEvent,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
if event != PromptEvent::Validate {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
let scrolloff = cx.editor.config().scrolloff;
|
let scrolloff = cx.editor.config().scrolloff;
|
||||||
let (view, doc) = current!(cx.editor);
|
let (view, doc) = current!(cx.editor);
|
||||||
doc.reload(view.id).map(|_| {
|
doc.reload(view.id).map(|_| {
|
||||||
|
@ -800,8 +986,12 @@ fn reload(
|
||||||
fn tree_sitter_scopes(
|
fn tree_sitter_scopes(
|
||||||
cx: &mut compositor::Context,
|
cx: &mut compositor::Context,
|
||||||
_args: &[Cow<str>],
|
_args: &[Cow<str>],
|
||||||
_event: PromptEvent,
|
event: PromptEvent,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
if event != PromptEvent::Validate {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
let (view, doc) = current!(cx.editor);
|
let (view, doc) = current!(cx.editor);
|
||||||
let text = doc.text().slice(..);
|
let text = doc.text().slice(..);
|
||||||
|
|
||||||
|
@ -814,8 +1004,12 @@ fn tree_sitter_scopes(
|
||||||
fn vsplit(
|
fn vsplit(
|
||||||
cx: &mut compositor::Context,
|
cx: &mut compositor::Context,
|
||||||
args: &[Cow<str>],
|
args: &[Cow<str>],
|
||||||
_event: PromptEvent,
|
event: PromptEvent,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
if event != PromptEvent::Validate {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
let id = view!(cx.editor).doc;
|
let id = view!(cx.editor).doc;
|
||||||
|
|
||||||
if args.is_empty() {
|
if args.is_empty() {
|
||||||
|
@ -833,8 +1027,12 @@ fn vsplit(
|
||||||
fn hsplit(
|
fn hsplit(
|
||||||
cx: &mut compositor::Context,
|
cx: &mut compositor::Context,
|
||||||
args: &[Cow<str>],
|
args: &[Cow<str>],
|
||||||
_event: PromptEvent,
|
event: PromptEvent,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
if event != PromptEvent::Validate {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
let id = view!(cx.editor).doc;
|
let id = view!(cx.editor).doc;
|
||||||
|
|
||||||
if args.is_empty() {
|
if args.is_empty() {
|
||||||
|
@ -852,8 +1050,12 @@ fn hsplit(
|
||||||
fn vsplit_new(
|
fn vsplit_new(
|
||||||
cx: &mut compositor::Context,
|
cx: &mut compositor::Context,
|
||||||
_args: &[Cow<str>],
|
_args: &[Cow<str>],
|
||||||
_event: PromptEvent,
|
event: PromptEvent,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
if event != PromptEvent::Validate {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
cx.editor.new_file(Action::VerticalSplit);
|
cx.editor.new_file(Action::VerticalSplit);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -862,8 +1064,12 @@ fn vsplit_new(
|
||||||
fn hsplit_new(
|
fn hsplit_new(
|
||||||
cx: &mut compositor::Context,
|
cx: &mut compositor::Context,
|
||||||
_args: &[Cow<str>],
|
_args: &[Cow<str>],
|
||||||
_event: PromptEvent,
|
event: PromptEvent,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
if event != PromptEvent::Validate {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
cx.editor.new_file(Action::HorizontalSplit);
|
cx.editor.new_file(Action::HorizontalSplit);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -872,8 +1078,12 @@ fn hsplit_new(
|
||||||
fn debug_eval(
|
fn debug_eval(
|
||||||
cx: &mut compositor::Context,
|
cx: &mut compositor::Context,
|
||||||
args: &[Cow<str>],
|
args: &[Cow<str>],
|
||||||
_event: PromptEvent,
|
event: PromptEvent,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
if event != PromptEvent::Validate {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(debugger) = cx.editor.debugger.as_mut() {
|
if let Some(debugger) = cx.editor.debugger.as_mut() {
|
||||||
let (frame, thread_id) = match (debugger.active_frame, debugger.thread_id) {
|
let (frame, thread_id) = match (debugger.active_frame, debugger.thread_id) {
|
||||||
(Some(frame), Some(thread_id)) => (frame, thread_id),
|
(Some(frame), Some(thread_id)) => (frame, thread_id),
|
||||||
|
@ -894,8 +1104,12 @@ fn debug_eval(
|
||||||
fn debug_start(
|
fn debug_start(
|
||||||
cx: &mut compositor::Context,
|
cx: &mut compositor::Context,
|
||||||
args: &[Cow<str>],
|
args: &[Cow<str>],
|
||||||
_event: PromptEvent,
|
event: PromptEvent,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
if event != PromptEvent::Validate {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
let mut args = args.to_owned();
|
let mut args = args.to_owned();
|
||||||
let name = match args.len() {
|
let name = match args.len() {
|
||||||
0 => None,
|
0 => None,
|
||||||
|
@ -907,8 +1121,12 @@ fn debug_start(
|
||||||
fn debug_remote(
|
fn debug_remote(
|
||||||
cx: &mut compositor::Context,
|
cx: &mut compositor::Context,
|
||||||
args: &[Cow<str>],
|
args: &[Cow<str>],
|
||||||
_event: PromptEvent,
|
event: PromptEvent,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
if event != PromptEvent::Validate {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
let mut args = args.to_owned();
|
let mut args = args.to_owned();
|
||||||
let address = match args.len() {
|
let address = match args.len() {
|
||||||
0 => None,
|
0 => None,
|
||||||
|
@ -924,8 +1142,12 @@ fn debug_remote(
|
||||||
fn tutor(
|
fn tutor(
|
||||||
cx: &mut compositor::Context,
|
cx: &mut compositor::Context,
|
||||||
_args: &[Cow<str>],
|
_args: &[Cow<str>],
|
||||||
_event: PromptEvent,
|
event: PromptEvent,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
if event != PromptEvent::Validate {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
let path = helix_loader::runtime_dir().join("tutor.txt");
|
let path = helix_loader::runtime_dir().join("tutor.txt");
|
||||||
cx.editor.open(&path, Action::Replace)?;
|
cx.editor.open(&path, Action::Replace)?;
|
||||||
// Unset path to prevent accidentally saving to the original tutor file.
|
// Unset path to prevent accidentally saving to the original tutor file.
|
||||||
|
@ -936,8 +1158,12 @@ fn tutor(
|
||||||
pub(super) fn goto_line_number(
|
pub(super) fn goto_line_number(
|
||||||
cx: &mut compositor::Context,
|
cx: &mut compositor::Context,
|
||||||
args: &[Cow<str>],
|
args: &[Cow<str>],
|
||||||
_event: PromptEvent,
|
event: PromptEvent,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
if event != PromptEvent::Validate {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
ensure!(!args.is_empty(), "Line number required");
|
ensure!(!args.is_empty(), "Line number required");
|
||||||
|
|
||||||
let line = args[0].parse::<usize>()?;
|
let line = args[0].parse::<usize>()?;
|
||||||
|
@ -954,8 +1180,12 @@ pub(super) fn goto_line_number(
|
||||||
fn get_option(
|
fn get_option(
|
||||||
cx: &mut compositor::Context,
|
cx: &mut compositor::Context,
|
||||||
args: &[Cow<str>],
|
args: &[Cow<str>],
|
||||||
_event: PromptEvent,
|
event: PromptEvent,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
if event != PromptEvent::Validate {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
if args.len() != 1 {
|
if args.len() != 1 {
|
||||||
anyhow::bail!("Bad arguments. Usage: `:get key`");
|
anyhow::bail!("Bad arguments. Usage: `:get key`");
|
||||||
}
|
}
|
||||||
|
@ -976,8 +1206,12 @@ fn get_option(
|
||||||
fn set_option(
|
fn set_option(
|
||||||
cx: &mut compositor::Context,
|
cx: &mut compositor::Context,
|
||||||
args: &[Cow<str>],
|
args: &[Cow<str>],
|
||||||
_event: PromptEvent,
|
event: PromptEvent,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
if event != PromptEvent::Validate {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
if args.len() != 2 {
|
if args.len() != 2 {
|
||||||
anyhow::bail!("Bad arguments. Usage: `:set key field`");
|
anyhow::bail!("Bad arguments. Usage: `:set key field`");
|
||||||
}
|
}
|
||||||
|
@ -1009,8 +1243,12 @@ fn set_option(
|
||||||
fn language(
|
fn language(
|
||||||
cx: &mut compositor::Context,
|
cx: &mut compositor::Context,
|
||||||
args: &[Cow<str>],
|
args: &[Cow<str>],
|
||||||
_event: PromptEvent,
|
event: PromptEvent,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
if event != PromptEvent::Validate {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
if args.len() != 1 {
|
if args.len() != 1 {
|
||||||
anyhow::bail!("Bad arguments. Usage: `:set-language language`");
|
anyhow::bail!("Bad arguments. Usage: `:set-language language`");
|
||||||
}
|
}
|
||||||
|
@ -1023,19 +1261,23 @@ fn language(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sort(
|
fn sort(cx: &mut compositor::Context, args: &[Cow<str>], event: PromptEvent) -> anyhow::Result<()> {
|
||||||
cx: &mut compositor::Context,
|
if event != PromptEvent::Validate {
|
||||||
args: &[Cow<str>],
|
return Ok(());
|
||||||
_event: PromptEvent,
|
}
|
||||||
) -> anyhow::Result<()> {
|
|
||||||
sort_impl(cx, args, false)
|
sort_impl(cx, args, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sort_reverse(
|
fn sort_reverse(
|
||||||
cx: &mut compositor::Context,
|
cx: &mut compositor::Context,
|
||||||
args: &[Cow<str>],
|
args: &[Cow<str>],
|
||||||
_event: PromptEvent,
|
event: PromptEvent,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
if event != PromptEvent::Validate {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
sort_impl(cx, args, true)
|
sort_impl(cx, args, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1076,8 +1318,12 @@ fn sort_impl(
|
||||||
fn reflow(
|
fn reflow(
|
||||||
cx: &mut compositor::Context,
|
cx: &mut compositor::Context,
|
||||||
args: &[Cow<str>],
|
args: &[Cow<str>],
|
||||||
_event: PromptEvent,
|
event: PromptEvent,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
if event != PromptEvent::Validate {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
let (view, doc) = current!(cx.editor);
|
let (view, doc) = current!(cx.editor);
|
||||||
|
|
||||||
const DEFAULT_MAX_LEN: usize = 79;
|
const DEFAULT_MAX_LEN: usize = 79;
|
||||||
|
@ -1115,8 +1361,12 @@ fn reflow(
|
||||||
fn tree_sitter_subtree(
|
fn tree_sitter_subtree(
|
||||||
cx: &mut compositor::Context,
|
cx: &mut compositor::Context,
|
||||||
_args: &[Cow<str>],
|
_args: &[Cow<str>],
|
||||||
_event: PromptEvent,
|
event: PromptEvent,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
if event != PromptEvent::Validate {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
let (view, doc) = current!(cx.editor);
|
let (view, doc) = current!(cx.editor);
|
||||||
|
|
||||||
if let Some(syntax) = doc.syntax() {
|
if let Some(syntax) = doc.syntax() {
|
||||||
|
@ -1151,8 +1401,12 @@ fn tree_sitter_subtree(
|
||||||
fn open_config(
|
fn open_config(
|
||||||
cx: &mut compositor::Context,
|
cx: &mut compositor::Context,
|
||||||
_args: &[Cow<str>],
|
_args: &[Cow<str>],
|
||||||
_event: PromptEvent,
|
event: PromptEvent,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
if event != PromptEvent::Validate {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
cx.editor
|
cx.editor
|
||||||
.open(&helix_loader::config_file(), Action::Replace)?;
|
.open(&helix_loader::config_file(), Action::Replace)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -1161,8 +1415,12 @@ fn open_config(
|
||||||
fn open_log(
|
fn open_log(
|
||||||
cx: &mut compositor::Context,
|
cx: &mut compositor::Context,
|
||||||
_args: &[Cow<str>],
|
_args: &[Cow<str>],
|
||||||
_event: PromptEvent,
|
event: PromptEvent,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
if event != PromptEvent::Validate {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
cx.editor.open(&helix_loader::log_file(), Action::Replace)?;
|
cx.editor.open(&helix_loader::log_file(), Action::Replace)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -1170,8 +1428,12 @@ fn open_log(
|
||||||
fn refresh_config(
|
fn refresh_config(
|
||||||
cx: &mut compositor::Context,
|
cx: &mut compositor::Context,
|
||||||
_args: &[Cow<str>],
|
_args: &[Cow<str>],
|
||||||
_event: PromptEvent,
|
event: PromptEvent,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
if event != PromptEvent::Validate {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
cx.editor.config_events.0.send(ConfigEvent::Refresh)?;
|
cx.editor.config_events.0.send(ConfigEvent::Refresh)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -1179,8 +1441,12 @@ fn refresh_config(
|
||||||
fn append_output(
|
fn append_output(
|
||||||
cx: &mut compositor::Context,
|
cx: &mut compositor::Context,
|
||||||
args: &[Cow<str>],
|
args: &[Cow<str>],
|
||||||
_event: PromptEvent,
|
event: PromptEvent,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
if event != PromptEvent::Validate {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
ensure!(!args.is_empty(), "Shell command required");
|
ensure!(!args.is_empty(), "Shell command required");
|
||||||
shell(cx, &args.join(" "), &ShellBehavior::Append);
|
shell(cx, &args.join(" "), &ShellBehavior::Append);
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -1189,18 +1455,22 @@ fn append_output(
|
||||||
fn insert_output(
|
fn insert_output(
|
||||||
cx: &mut compositor::Context,
|
cx: &mut compositor::Context,
|
||||||
args: &[Cow<str>],
|
args: &[Cow<str>],
|
||||||
_event: PromptEvent,
|
event: PromptEvent,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
if event != PromptEvent::Validate {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
ensure!(!args.is_empty(), "Shell command required");
|
ensure!(!args.is_empty(), "Shell command required");
|
||||||
shell(cx, &args.join(" "), &ShellBehavior::Insert);
|
shell(cx, &args.join(" "), &ShellBehavior::Insert);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pipe(
|
fn pipe(cx: &mut compositor::Context, args: &[Cow<str>], event: PromptEvent) -> anyhow::Result<()> {
|
||||||
cx: &mut compositor::Context,
|
if event != PromptEvent::Validate {
|
||||||
args: &[Cow<str>],
|
return Ok(());
|
||||||
_event: PromptEvent,
|
}
|
||||||
) -> anyhow::Result<()> {
|
|
||||||
ensure!(!args.is_empty(), "Shell command required");
|
ensure!(!args.is_empty(), "Shell command required");
|
||||||
shell(cx, &args.join(" "), &ShellBehavior::Replace);
|
shell(cx, &args.join(" "), &ShellBehavior::Replace);
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -1209,8 +1479,12 @@ fn pipe(
|
||||||
fn run_shell_command(
|
fn run_shell_command(
|
||||||
cx: &mut compositor::Context,
|
cx: &mut compositor::Context,
|
||||||
args: &[Cow<str>],
|
args: &[Cow<str>],
|
||||||
_event: PromptEvent,
|
event: PromptEvent,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
if event != PromptEvent::Validate {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
let shell = &cx.editor.config().shell;
|
let shell = &cx.editor.config().shell;
|
||||||
let (output, success) = shell_impl(shell, &args.join(" "), None)?;
|
let (output, success) = shell_impl(shell, &args.join(" "), None)?;
|
||||||
if success {
|
if success {
|
||||||
|
@ -1787,10 +2061,6 @@ pub fn command_mode(cx: &mut Context) {
|
||||||
}
|
}
|
||||||
}, // completion
|
}, // completion
|
||||||
move |cx: &mut compositor::Context, input: &str, event: PromptEvent| {
|
move |cx: &mut compositor::Context, input: &str, event: PromptEvent| {
|
||||||
if event != PromptEvent::Validate {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let parts = input.split_whitespace().collect::<Vec<&str>>();
|
let parts = input.split_whitespace().collect::<Vec<&str>>();
|
||||||
if parts.is_empty() {
|
if parts.is_empty() {
|
||||||
return;
|
return;
|
||||||
|
@ -1811,10 +2081,10 @@ pub fn command_mode(cx: &mut Context) {
|
||||||
if let Err(e) = (cmd.fun)(cx, &args[1..], event) {
|
if let Err(e) = (cmd.fun)(cx, &args[1..], event) {
|
||||||
cx.editor.set_error(format!("{}", e));
|
cx.editor.set_error(format!("{}", e));
|
||||||
}
|
}
|
||||||
} else {
|
} else if event == PromptEvent::Validate {
|
||||||
cx.editor
|
cx.editor
|
||||||
.set_error(format!("no such command: '{}'", parts[0]));
|
.set_error(format!("no such command: '{}'", parts[0]));
|
||||||
};
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
prompt.doc_fn = Box::new(|input: &str| {
|
prompt.doc_fn = Box::new(|input: &str| {
|
||||||
|
|
|
@ -237,6 +237,7 @@ pub mod completers {
|
||||||
));
|
));
|
||||||
names.push("default".into());
|
names.push("default".into());
|
||||||
names.push("base16_default".into());
|
names.push("base16_default".into());
|
||||||
|
names.sort();
|
||||||
|
|
||||||
let mut names: Vec<_> = names
|
let mut names: Vec<_> = names
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
|
|
@ -490,7 +490,7 @@ impl<T: Item + 'static> Component for Picker<T> {
|
||||||
_ => return EventResult::Ignored(None),
|
_ => return EventResult::Ignored(None),
|
||||||
};
|
};
|
||||||
|
|
||||||
let close_fn = EventResult::Consumed(Some(Box::new(|compositor: &mut Compositor, _| {
|
let close_fn = EventResult::Consumed(Some(Box::new(|compositor: &mut Compositor, _cx| {
|
||||||
// remove the layer
|
// remove the layer
|
||||||
compositor.last_picker = compositor.pop();
|
compositor.last_picker = compositor.pop();
|
||||||
})));
|
})));
|
||||||
|
|
|
@ -464,7 +464,6 @@ pub struct Editor {
|
||||||
pub registers: Registers,
|
pub registers: Registers,
|
||||||
pub macro_recording: Option<(char, Vec<KeyEvent>)>,
|
pub macro_recording: Option<(char, Vec<KeyEvent>)>,
|
||||||
pub macro_replaying: Vec<char>,
|
pub macro_replaying: Vec<char>,
|
||||||
pub theme: Theme,
|
|
||||||
pub language_servers: helix_lsp::Registry,
|
pub language_servers: helix_lsp::Registry,
|
||||||
pub diagnostics: BTreeMap<lsp::Url, Vec<lsp::Diagnostic>>,
|
pub diagnostics: BTreeMap<lsp::Url, Vec<lsp::Diagnostic>>,
|
||||||
|
|
||||||
|
@ -476,6 +475,12 @@ pub struct Editor {
|
||||||
|
|
||||||
pub syn_loader: Arc<syntax::Loader>,
|
pub syn_loader: Arc<syntax::Loader>,
|
||||||
pub theme_loader: Arc<theme::Loader>,
|
pub theme_loader: Arc<theme::Loader>,
|
||||||
|
/// last_theme is used for theme previews. We store the current theme here,
|
||||||
|
/// and if previewing is cancelled, we can return to it.
|
||||||
|
pub last_theme: Option<Theme>,
|
||||||
|
/// The currently applied editor theme. While previewing a theme, the previewed theme
|
||||||
|
/// is set here.
|
||||||
|
pub theme: Theme,
|
||||||
|
|
||||||
pub status_msg: Option<(Cow<'static, str>, Severity)>,
|
pub status_msg: Option<(Cow<'static, str>, Severity)>,
|
||||||
pub autoinfo: Option<Info>,
|
pub autoinfo: Option<Info>,
|
||||||
|
@ -500,6 +505,11 @@ pub enum ConfigEvent {
|
||||||
Update(Box<Config>),
|
Update(Box<Config>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum ThemeAction {
|
||||||
|
Set,
|
||||||
|
Preview,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct CompleteAction {
|
pub struct CompleteAction {
|
||||||
pub trigger_offset: usize,
|
pub trigger_offset: usize,
|
||||||
|
@ -544,6 +554,7 @@ impl Editor {
|
||||||
breakpoints: HashMap::new(),
|
breakpoints: HashMap::new(),
|
||||||
syn_loader,
|
syn_loader,
|
||||||
theme_loader,
|
theme_loader,
|
||||||
|
last_theme: None,
|
||||||
registers: Registers::default(),
|
registers: Registers::default(),
|
||||||
clipboard_provider: get_clipboard_provider(),
|
clipboard_provider: get_clipboard_provider(),
|
||||||
status_msg: None,
|
status_msg: None,
|
||||||
|
@ -613,7 +624,22 @@ impl Editor {
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn unset_theme_preview(&mut self) {
|
||||||
|
if let Some(last_theme) = self.last_theme.take() {
|
||||||
|
self.set_theme(last_theme);
|
||||||
|
}
|
||||||
|
// None likely occurs when the user types ":theme" and then exits before previewing
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_theme_preview(&mut self, theme: Theme) {
|
||||||
|
self.set_theme_impl(theme, ThemeAction::Preview);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_theme(&mut self, theme: Theme) {
|
pub fn set_theme(&mut self, theme: Theme) {
|
||||||
|
self.set_theme_impl(theme, ThemeAction::Set);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_theme_impl(&mut self, theme: Theme, preview: ThemeAction) {
|
||||||
// `ui.selection` is the only scope required to be able to render a theme.
|
// `ui.selection` is the only scope required to be able to render a theme.
|
||||||
if theme.find_scope_index("ui.selection").is_none() {
|
if theme.find_scope_index("ui.selection").is_none() {
|
||||||
self.set_error("Invalid theme: `ui.selection` required");
|
self.set_error("Invalid theme: `ui.selection` required");
|
||||||
|
@ -623,7 +649,18 @@ impl Editor {
|
||||||
let scopes = theme.scopes();
|
let scopes = theme.scopes();
|
||||||
self.syn_loader.set_scopes(scopes.to_vec());
|
self.syn_loader.set_scopes(scopes.to_vec());
|
||||||
|
|
||||||
|
match preview {
|
||||||
|
ThemeAction::Preview => {
|
||||||
|
let last_theme = std::mem::replace(&mut self.theme, theme);
|
||||||
|
// only insert on first preview: this will be the last theme the user has saved
|
||||||
|
self.last_theme.get_or_insert(last_theme);
|
||||||
|
}
|
||||||
|
ThemeAction::Set => {
|
||||||
|
self.last_theme = None;
|
||||||
self.theme = theme;
|
self.theme = theme;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
self._refresh();
|
self._refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -77,6 +77,14 @@ impl Loader {
|
||||||
names
|
names
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn default_theme(&self, true_color: bool) -> Theme {
|
||||||
|
if true_color {
|
||||||
|
self.default()
|
||||||
|
} else {
|
||||||
|
self.base16_default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the default theme
|
/// Returns the default theme
|
||||||
pub fn default(&self) -> Theme {
|
pub fn default(&self) -> Theme {
|
||||||
DEFAULT_THEME.clone()
|
DEFAULT_THEME.clone()
|
||||||
|
|
Loading…
Reference in New Issue