Make command implementation return a Result<()>

The error message is displayed with cx.editor.set_error.
This commit is contained in:
Lionel Flandrin 2021-06-26 18:50:44 +01:00 committed by Blaž Hrastnik
parent 3e4cd8f8e6
commit 9c02a1b070
2 changed files with 263 additions and 157 deletions

View file

@ -23,7 +23,7 @@ use helix_view::{
Document, DocumentId, Editor, ViewId, Document, DocumentId, Editor, ViewId,
}; };
use anyhow::anyhow; use anyhow::{anyhow, bail};
use helix_lsp::{ use helix_lsp::{
lsp, lsp,
util::{lsp_pos_to_pos, lsp_range_to_range, pos_to_lsp_pos, range_to_lsp_range}, util::{lsp_pos_to_pos, lsp_range_to_range, pos_to_lsp_pos, range_to_lsp_range},
@ -1161,34 +1161,52 @@ mod cmd {
pub alias: Option<&'static str>, pub alias: Option<&'static str>,
pub doc: &'static str, pub doc: &'static str,
// params, flags, helper, completer // params, flags, helper, completer
pub fun: fn(&mut compositor::Context, &[&str], PromptEvent), pub fun: fn(&mut compositor::Context, &[&str], PromptEvent) -> anyhow::Result<()>,
pub completer: Option<Completer>, pub completer: Option<Completer>,
} }
fn quit(cx: &mut compositor::Context, _args: &[&str], _event: PromptEvent) { fn quit(
cx: &mut compositor::Context,
_args: &[&str],
_event: PromptEvent,
) -> anyhow::Result<()> {
// last view and we have unsaved changes // last view and we have unsaved changes
if cx.editor.tree.views().count() == 1 && buffers_remaining_impl(cx.editor) { if cx.editor.tree.views().count() == 1 {
return; buffers_remaining_impl(cx.editor)?
} }
cx.editor cx.editor
.close(view!(cx.editor).id, /* close_buffer */ false); .close(view!(cx.editor).id, /* close_buffer */ false);
Ok(())
} }
fn force_quit(cx: &mut compositor::Context, _args: &[&str], _event: PromptEvent) { fn force_quit(
cx: &mut compositor::Context,
_args: &[&str],
_event: PromptEvent,
) -> anyhow::Result<()> {
cx.editor cx.editor
.close(view!(cx.editor).id, /* close_buffer */ false); .close(view!(cx.editor).id, /* close_buffer */ false);
Ok(())
} }
fn open(cx: &mut compositor::Context, args: &[&str], _event: PromptEvent) { fn open(
cx: &mut compositor::Context,
args: &[&str],
_event: PromptEvent,
) -> anyhow::Result<()> {
match args.get(0) { match args.get(0) {
Some(path) => { Some(path) => {
// TODO: handle error let _ = cx.editor.open(path.into(), Action::Replace)?;
let _ = cx.editor.open(path.into(), Action::Replace);
Ok(())
} }
None => { None => {
cx.editor.set_error("wrong argument count".to_string()); bail!("wrong argument count");
} }
}; }
} }
fn write_impl<P: AsRef<Path>>( fn write_impl<P: AsRef<Path>>(
@ -1200,11 +1218,11 @@ mod cmd {
if let Some(path) = path { if let Some(path) = path {
if let Err(err) = doc.set_path(path.as_ref()) { if let Err(err) = doc.set_path(path.as_ref()) {
return Err(anyhow!("invalid filepath: {}", err)); bail!("invalid filepath: {}", err);
}; };
} }
if doc.path().is_none() { if doc.path().is_none() {
return Err(anyhow!("cannot write a buffer without a filename")); bail!("cannot write a buffer without a filename");
} }
let fmt = doc.auto_format().map(|fmt| { let fmt = doc.auto_format().map(|fmt| {
let shared = fmt.shared(); let shared = fmt.shared();
@ -1220,21 +1238,33 @@ mod cmd {
Ok(tokio::spawn(doc.format_and_save(fmt))) Ok(tokio::spawn(doc.format_and_save(fmt)))
} }
fn write(cx: &mut compositor::Context, args: &[&str], _event: PromptEvent) { fn write(
match write_impl(cx, args.first()) { cx: &mut compositor::Context,
Err(e) => cx.editor.set_error(e.to_string()), args: &[&str],
Ok(handle) => { _event: PromptEvent,
cx.jobs ) -> anyhow::Result<()> {
.add(Job::new(handle.unwrap_or_else(|e| Err(e.into()))).wait_before_exiting()); let handle = write_impl(cx, args.first())?;
} cx.jobs
}; .add(Job::new(handle.unwrap_or_else(|e| Err(e.into()))).wait_before_exiting());
Ok(())
} }
fn new_file(cx: &mut compositor::Context, _args: &[&str], _event: PromptEvent) { fn new_file(
cx: &mut compositor::Context,
_args: &[&str],
_event: PromptEvent,
) -> anyhow::Result<()> {
cx.editor.new_file(Action::Replace); cx.editor.new_file(Action::Replace);
Ok(())
} }
fn format(cx: &mut compositor::Context, _args: &[&str], _event: PromptEvent) { fn format(
cx: &mut compositor::Context,
_args: &[&str],
_event: PromptEvent,
) -> anyhow::Result<()> {
let (_, doc) = current!(cx.editor); let (_, doc) = current!(cx.editor);
if let Some(format) = doc.format() { if let Some(format) = doc.format() {
@ -1242,9 +1272,14 @@ mod cmd {
make_format_callback(doc.id(), doc.version(), Modified::LeaveModified, format); make_format_callback(doc.id(), doc.version(), Modified::LeaveModified, format);
cx.jobs.callback(callback); cx.jobs.callback(callback);
} }
}
fn set_indent_style(cx: &mut compositor::Context, args: &[&str], _event: PromptEvent) { Ok(())
}
fn set_indent_style(
cx: &mut compositor::Context,
args: &[&str],
_event: PromptEvent,
) -> anyhow::Result<()> {
use IndentStyle::*; use IndentStyle::*;
// If no argument, report current indent style. // If no argument, report current indent style.
@ -1256,7 +1291,7 @@ mod cmd {
Spaces(n) if (2..=8).contains(&n) => format!("{} spaces", n), Spaces(n) if (2..=8).contains(&n) => format!("{} spaces", n),
_ => "error".into(), // Shouldn't happen. _ => "error".into(), // Shouldn't happen.
}); });
return; return Ok(());
} }
// Attempt to parse argument as an indent style. // Attempt to parse argument as an indent style.
@ -1274,15 +1309,19 @@ mod cmd {
if let Some(s) = style { if let Some(s) = style {
let doc = doc_mut!(cx.editor); let doc = doc_mut!(cx.editor);
doc.indent_style = s; doc.indent_style = s;
Ok(())
} else { } else {
// Invalid argument. bail!("invalid indent style '{}'", args[0]);
cx.editor
.set_error(format!("invalid indent style '{}'", args[0],));
} }
} }
/// Sets or reports the current document's line ending setting. /// Sets or reports the current document's line ending setting.
fn set_line_ending(cx: &mut compositor::Context, args: &[&str], _event: PromptEvent) { fn set_line_ending(
cx: &mut compositor::Context,
args: &[&str],
_event: PromptEvent,
) -> anyhow::Result<()> {
use LineEnding::*; use LineEnding::*;
// If no argument, report current line ending setting. // If no argument, report current line ending setting.
@ -1298,7 +1337,8 @@ mod cmd {
// These should never be a document's default line ending. // These should never be a document's default line ending.
VT | LS | PS => "error".into(), VT | LS | PS => "error".into(),
}); });
return;
return Ok(());
} }
// Attempt to parse argument as a line ending. // Attempt to parse argument as a line ending.
@ -1314,70 +1354,66 @@ mod cmd {
if let Some(le) = line_ending { if let Some(le) = line_ending {
doc_mut!(cx.editor).line_ending = le; doc_mut!(cx.editor).line_ending = le;
Ok(())
} else { } else {
// Invalid argument. bail!("invalid line ending '{}'", args[0]);
cx.editor
.set_error(format!("invalid line ending '{}'", args[0],));
} }
} }
fn earlier(cx: &mut compositor::Context, args: &[&str], _event: PromptEvent) { fn earlier(
let uk = match args.join(" ").parse::<helix_core::history::UndoKind>() { cx: &mut compositor::Context,
Ok(uk) => uk, args: &[&str],
Err(msg) => { _event: PromptEvent,
cx.editor.set_error(msg); ) -> anyhow::Result<()> {
return; let uk = args
} .join(" ")
}; .parse::<helix_core::history::UndoKind>()
.map_err(|s| anyhow!(s))?;
let (view, doc) = current!(cx.editor); let (view, doc) = current!(cx.editor);
doc.earlier(view.id, uk) doc.earlier(view.id, uk);
Ok(())
} }
fn later(cx: &mut compositor::Context, args: &[&str], _event: PromptEvent) { fn later(
let uk = match args.join(" ").parse::<helix_core::history::UndoKind>() { cx: &mut compositor::Context,
Ok(uk) => uk, args: &[&str],
Err(msg) => { _event: PromptEvent,
cx.editor.set_error(msg); ) -> anyhow::Result<()> {
return; let uk = args
} .join(" ")
}; .parse::<helix_core::history::UndoKind>()
.map_err(|s| anyhow!(s))?;
let (view, doc) = current!(cx.editor); let (view, doc) = current!(cx.editor);
doc.later(view.id, uk) doc.later(view.id, uk);
Ok(())
} }
fn write_quit(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) { fn write_quit(
match write_impl(cx, args.first()) { cx: &mut compositor::Context,
Ok(handle) => { args: &[&str],
if let Err(e) = helix_lsp::block_on(handle) { event: PromptEvent,
cx.editor.set_error(e.to_string()); ) -> anyhow::Result<()> {
} else { let handle = write_impl(cx, args.first())?;
quit(cx, &[], event); helix_lsp::block_on(handle)?;
} quit(cx, &[], event)
}
Err(e) => {
cx.editor.set_error(e.to_string());
}
}
} }
fn force_write_quit(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) { fn force_write_quit(
match write_impl(cx, args.first()) { cx: &mut compositor::Context,
Ok(handle) => { args: &[&str],
if let Err(e) = helix_lsp::block_on(handle) { event: PromptEvent,
cx.editor.set_error(e.to_string()); ) -> anyhow::Result<()> {
} else { let handle = write_impl(cx, args.first())?;
force_quit(cx, &[], event); helix_lsp::block_on(handle)?;
} force_quit(cx, &[], event)
}
Err(e) => {
cx.editor.set_error(e.to_string());
}
}
} }
/// Returns `true` if there are modified buffers remaining and sets editor error, /// Results an error if there are modified buffers remaining and sets editor error,
/// otherwise returns `false` /// otherwise returns `Ok(())`
fn buffers_remaining_impl(editor: &mut Editor) -> bool { fn buffers_remaining_impl(editor: &mut Editor) -> anyhow::Result<()> {
let modified: Vec<_> = editor let modified: Vec<_> = editor
.documents() .documents()
.filter(|doc| doc.is_modified()) .filter(|doc| doc.is_modified())
@ -1388,16 +1424,13 @@ mod cmd {
}) })
.collect(); .collect();
if !modified.is_empty() { if !modified.is_empty() {
let err = format!( bail!(
"{} unsaved buffer(s) remaining: {:?}", "{} unsaved buffer(s) remaining: {:?}",
modified.len(), modified.len(),
modified modified
); );
editor.set_error(err);
true
} else {
false
} }
Ok(())
} }
fn write_all_impl( fn write_all_impl(
@ -1406,7 +1439,7 @@ mod cmd {
_event: PromptEvent, _event: PromptEvent,
quit: bool, quit: bool,
force: bool, force: bool,
) { ) -> anyhow::Result<()> {
let mut errors = String::new(); let mut errors = String::new();
// save all documents // save all documents
@ -1419,11 +1452,10 @@ mod cmd {
// TODO: handle error. // TODO: handle error.
let _ = helix_lsp::block_on(tokio::spawn(doc.save())); let _ = helix_lsp::block_on(tokio::spawn(doc.save()));
} }
editor.set_error(errors);
if quit { if quit {
if !force && buffers_remaining_impl(editor) { if !force {
return; buffers_remaining_impl(editor)?;
} }
// close all views // close all views
@ -1432,23 +1464,42 @@ mod cmd {
editor.close(view_id, false); editor.close(view_id, false);
} }
} }
bail!(errors)
} }
fn write_all(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) { fn write_all(
cx: &mut compositor::Context,
args: &[&str],
event: PromptEvent,
) -> anyhow::Result<()> {
write_all_impl(&mut cx.editor, args, event, false, false) write_all_impl(&mut cx.editor, args, event, false, false)
} }
fn write_all_quit(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) { fn write_all_quit(
cx: &mut compositor::Context,
args: &[&str],
event: PromptEvent,
) -> anyhow::Result<()> {
write_all_impl(&mut cx.editor, args, event, true, false) write_all_impl(&mut cx.editor, args, event, true, false)
} }
fn force_write_all_quit(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) { fn force_write_all_quit(
cx: &mut compositor::Context,
args: &[&str],
event: PromptEvent,
) -> anyhow::Result<()> {
write_all_impl(&mut cx.editor, args, event, true, true) write_all_impl(&mut cx.editor, args, event, true, true)
} }
fn quit_all_impl(editor: &mut Editor, _args: &[&str], _event: PromptEvent, force: bool) { fn quit_all_impl(
if !force && buffers_remaining_impl(editor) { editor: &mut Editor,
return; _args: &[&str],
_event: PromptEvent,
force: bool,
) -> anyhow::Result<()> {
if !force {
buffers_remaining_impl(editor)?;
} }
// close all views // close all views
@ -1456,57 +1507,82 @@ mod cmd {
for view_id in views { for view_id in views {
editor.close(view_id, false); editor.close(view_id, false);
} }
Ok(())
} }
fn quit_all(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) { fn quit_all(
cx: &mut compositor::Context,
args: &[&str],
event: PromptEvent,
) -> anyhow::Result<()> {
quit_all_impl(&mut cx.editor, args, event, false) quit_all_impl(&mut cx.editor, args, event, false)
} }
fn force_quit_all(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) { fn force_quit_all(
cx: &mut compositor::Context,
args: &[&str],
event: PromptEvent,
) -> anyhow::Result<()> {
quit_all_impl(&mut cx.editor, args, event, true) quit_all_impl(&mut cx.editor, args, event, true)
} }
fn theme(cx: &mut compositor::Context, args: &[&str], _event: PromptEvent) { fn theme(
cx: &mut compositor::Context,
args: &[&str],
_event: PromptEvent,
) -> anyhow::Result<()> {
let theme = if let Some(theme) = args.first() { let theme = if let Some(theme) = args.first() {
theme theme
} else { } else {
cx.editor.set_error("theme name not provided".into()); bail!("theme name not provided");
return;
}; };
cx.editor.set_theme_from_name(theme); cx.editor.set_theme_from_name(theme)
} }
fn yank_main_selection_to_clipboard( fn yank_main_selection_to_clipboard(
cx: &mut compositor::Context, cx: &mut compositor::Context,
_args: &[&str], _args: &[&str],
_event: PromptEvent, _event: PromptEvent,
) { ) -> anyhow::Result<()> {
yank_main_selection_to_clipboard_impl(&mut cx.editor); yank_main_selection_to_clipboard_impl(&mut cx.editor)
} }
fn yank_joined_to_clipboard(cx: &mut compositor::Context, args: &[&str], _event: PromptEvent) { fn yank_joined_to_clipboard(
cx: &mut compositor::Context,
args: &[&str],
_event: PromptEvent,
) -> anyhow::Result<()> {
let (_, doc) = current!(cx.editor); let (_, doc) = current!(cx.editor);
let separator = args let separator = args
.first() .first()
.copied() .copied()
.unwrap_or_else(|| doc.line_ending.as_str()); .unwrap_or_else(|| doc.line_ending.as_str());
yank_joined_to_clipboard_impl(&mut cx.editor, separator); yank_joined_to_clipboard_impl(&mut cx.editor, separator)
} }
fn paste_clipboard_after(cx: &mut compositor::Context, _args: &[&str], _event: PromptEvent) { fn paste_clipboard_after(
paste_clipboard_impl(&mut cx.editor, Paste::After); cx: &mut compositor::Context,
_args: &[&str],
_event: PromptEvent,
) -> anyhow::Result<()> {
paste_clipboard_impl(&mut cx.editor, Paste::After)
} }
fn paste_clipboard_before(cx: &mut compositor::Context, _args: &[&str], _event: PromptEvent) { fn paste_clipboard_before(
paste_clipboard_impl(&mut cx.editor, Paste::After); cx: &mut compositor::Context,
_args: &[&str],
_event: PromptEvent,
) -> anyhow::Result<()> {
paste_clipboard_impl(&mut cx.editor, Paste::After)
} }
fn replace_selections_with_clipboard( fn replace_selections_with_clipboard(
cx: &mut compositor::Context, cx: &mut compositor::Context,
_args: &[&str], _args: &[&str],
_event: PromptEvent, _event: PromptEvent,
) { ) -> anyhow::Result<()> {
let (view, doc) = current!(cx.editor); let (view, doc) = current!(cx.editor);
match cx.editor.clipboard_provider.get_contents() { match cx.editor.clipboard_provider.get_contents() {
@ -1520,71 +1596,89 @@ mod cmd {
doc.apply(&transaction, view.id); doc.apply(&transaction, view.id);
doc.append_changes_to_history(view.id); doc.append_changes_to_history(view.id);
Ok(())
}
Err(e) => {
log::error!("Couldn't get system clipboard contents: {:?}", e);
bail!("Couldn't get system clipboard contents: {:?}", e);
} }
Err(e) => log::error!("Couldn't get system clipboard contents: {:?}", e),
} }
} }
fn show_clipboard_provider(cx: &mut compositor::Context, _args: &[&str], _event: PromptEvent) { fn show_clipboard_provider(
cx: &mut compositor::Context,
_args: &[&str],
_event: PromptEvent,
) -> anyhow::Result<()> {
cx.editor cx.editor
.set_status(cx.editor.clipboard_provider.name().into()); .set_status(cx.editor.clipboard_provider.name().into());
Ok(())
} }
fn change_current_directory(cx: &mut compositor::Context, args: &[&str], _event: PromptEvent) { fn change_current_directory(
let dir = match args.first() { cx: &mut compositor::Context,
Some(dir) => dir, args: &[&str],
None => { _event: PromptEvent,
cx.editor.set_error("target directory not provided".into()); ) -> anyhow::Result<()> {
return; let dir = args
} .first()
}; .ok_or_else(|| anyhow!("target directory not provided"))?;
if let Err(e) = std::env::set_current_dir(dir) { if let Err(e) = std::env::set_current_dir(dir) {
cx.editor.set_error(format!( bail!("Couldn't change the current working directory: {:?}", e);
"Couldn't change the current working directory: {:?}",
e
));
return;
} }
match std::env::current_dir() { match std::env::current_dir() {
Ok(cwd) => cx.editor.set_status(format!( Ok(cwd) => {
"Current working directory is now {}", cx.editor.set_status(format!(
cwd.display() "Current working directory is now {}",
)), cwd.display()
Err(e) => cx ));
.editor Ok(())
.set_error(format!("Couldn't get the new working directory: {}", e)), }
Err(e) => bail!("Couldn't get the new working directory: {}", e),
} }
} }
fn show_current_directory(cx: &mut compositor::Context, _args: &[&str], _event: PromptEvent) { fn show_current_directory(
cx: &mut compositor::Context,
_args: &[&str],
_event: PromptEvent,
) -> anyhow::Result<()> {
match std::env::current_dir() { match std::env::current_dir() {
Ok(cwd) => cx Ok(cwd) => {
.editor cx.editor
.set_status(format!("Current working directory is {}", cwd.display())), .set_status(format!("Current working directory is {}", cwd.display()));
Err(e) => cx Ok(())
.editor }
.set_error(format!("Couldn't get the current working directory: {}", e)), Err(e) => bail!("Couldn't get the current working directory: {}", e),
} }
} }
/// Sets the [`Document`]'s encoding.. /// Sets the [`Document`]'s encoding..
fn set_encoding(cx: &mut compositor::Context, args: &[&str], _: PromptEvent) { fn set_encoding(
cx: &mut compositor::Context,
args: &[&str],
_event: PromptEvent,
) -> anyhow::Result<()> {
let (_, doc) = current!(cx.editor); let (_, doc) = current!(cx.editor);
if let Some(label) = args.first() { if let Some(label) = args.first() {
doc.set_encoding(label) doc.set_encoding(label)
.unwrap_or_else(|e| cx.editor.set_error(e.to_string()));
} else { } else {
let encoding = doc.encoding().name().to_string(); let encoding = doc.encoding().name().to_string();
cx.editor.set_status(encoding) cx.editor.set_status(encoding);
Ok(())
} }
} }
/// Reload the [`Document`] from its source file. /// Reload the [`Document`] from its source file.
fn reload(cx: &mut compositor::Context, _args: &[&str], _: PromptEvent) { fn reload(
cx: &mut compositor::Context,
_args: &[&str],
_event: PromptEvent,
) -> anyhow::Result<()> {
let (view, doc) = current!(cx.editor); let (view, doc) = current!(cx.editor);
doc.reload(view.id).unwrap(); doc.reload(view.id)
} }
pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[
@ -1849,7 +1943,9 @@ fn command_mode(cx: &mut Context) {
} }
if let Some(cmd) = cmd::COMMANDS.get(parts[0]) { if let Some(cmd) = cmd::COMMANDS.get(parts[0]) {
(cmd.fun)(cx, &parts[1..], event); if let Err(e) = (cmd.fun)(cx, &parts[1..], event) {
cx.editor.set_error(format!("{}", e));
}
} else { } else {
cx.editor cx.editor
.set_error(format!("no such command: '{}'", parts[0])); .set_error(format!("no such command: '{}'", parts[0]));
@ -2758,7 +2854,7 @@ fn yank(cx: &mut Context) {
cx.editor.set_status(msg) cx.editor.set_status(msg)
} }
fn yank_joined_to_clipboard_impl(editor: &mut Editor, separator: &str) { fn yank_joined_to_clipboard_impl(editor: &mut Editor, separator: &str) -> anyhow::Result<()> {
let (view, doc) = current!(editor); let (view, doc) = current!(editor);
let values: Vec<String> = doc let values: Vec<String> = doc
@ -2776,17 +2872,20 @@ fn yank_joined_to_clipboard_impl(editor: &mut Editor, separator: &str) {
if let Err(e) = editor.clipboard_provider.set_contents(joined) { if let Err(e) = editor.clipboard_provider.set_contents(joined) {
log::error!("Couldn't set system clipboard content: {:?}", e); log::error!("Couldn't set system clipboard content: {:?}", e);
bail!("Couldn't set system clipboard content: {:?}", e);
} }
editor.set_status(msg); editor.set_status(msg);
Ok(())
} }
fn yank_joined_to_clipboard(cx: &mut Context) { fn yank_joined_to_clipboard(cx: &mut Context) {
let line_ending = current!(cx.editor).1.line_ending; let line_ending = current!(cx.editor).1.line_ending;
yank_joined_to_clipboard_impl(&mut cx.editor, line_ending.as_str()); let _ = yank_joined_to_clipboard_impl(&mut cx.editor, line_ending.as_str());
} }
fn yank_main_selection_to_clipboard_impl(editor: &mut Editor) { fn yank_main_selection_to_clipboard_impl(editor: &mut Editor) -> anyhow::Result<()> {
let (view, doc) = current!(editor); let (view, doc) = current!(editor);
let value = doc let value = doc
@ -2796,13 +2895,15 @@ fn yank_main_selection_to_clipboard_impl(editor: &mut Editor) {
if let Err(e) = editor.clipboard_provider.set_contents(value.into_owned()) { if let Err(e) = editor.clipboard_provider.set_contents(value.into_owned()) {
log::error!("Couldn't set system clipboard content: {:?}", e); log::error!("Couldn't set system clipboard content: {:?}", e);
bail!("Couldn't set system clipboard content: {:?}", e);
} }
editor.set_status("yanked main selection to system clipboard".to_owned()); editor.set_status("yanked main selection to system clipboard".to_owned());
Ok(())
} }
fn yank_main_selection_to_clipboard(cx: &mut Context) { fn yank_main_selection_to_clipboard(cx: &mut Context) {
yank_main_selection_to_clipboard_impl(&mut cx.editor); let _ = yank_main_selection_to_clipboard_impl(&mut cx.editor);
} }
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
@ -2850,7 +2951,7 @@ fn paste_impl(
Some(transaction) Some(transaction)
} }
fn paste_clipboard_impl(editor: &mut Editor, action: Paste) { fn paste_clipboard_impl(editor: &mut Editor, action: Paste) -> anyhow::Result<()> {
let (view, doc) = current!(editor); let (view, doc) = current!(editor);
match editor match editor
@ -2861,18 +2962,22 @@ fn paste_clipboard_impl(editor: &mut Editor, action: Paste) {
Ok(Some(transaction)) => { Ok(Some(transaction)) => {
doc.apply(&transaction, view.id); doc.apply(&transaction, view.id);
doc.append_changes_to_history(view.id); doc.append_changes_to_history(view.id);
Ok(())
}
Ok(None) => Ok(()),
Err(e) => {
log::error!("Couldn't get system clipboard contents: {:?}", e);
bail!("Couldn't get system clipboard contents: {:?}", e);
} }
Ok(None) => {}
Err(e) => log::error!("Couldn't get system clipboard contents: {:?}", e),
} }
} }
fn paste_clipboard_after(cx: &mut Context) { fn paste_clipboard_after(cx: &mut Context) {
paste_clipboard_impl(&mut cx.editor, Paste::After); let _ = paste_clipboard_impl(&mut cx.editor, Paste::After);
} }
fn paste_clipboard_before(cx: &mut Context) { fn paste_clipboard_before(cx: &mut Context) {
paste_clipboard_impl(&mut cx.editor, Paste::Before); let _ = paste_clipboard_impl(&mut cx.editor, Paste::Before);
} }
fn replace_with_yanked(cx: &mut Context) { fn replace_with_yanked(cx: &mut Context) {

View file

@ -97,16 +97,17 @@ impl Editor {
self._refresh(); self._refresh();
} }
pub fn set_theme_from_name(&mut self, theme: &str) { pub fn set_theme_from_name(&mut self, theme: &str) -> anyhow::Result<()> {
let theme = match self.theme_loader.load(theme.as_ref()) { let theme = match self.theme_loader.load(theme.as_ref()) {
Ok(theme) => theme, Ok(theme) => theme,
Err(e) => { Err(e) => {
log::warn!("failed setting theme `{}` - {}", theme, e); log::warn!("failed setting theme `{}` - {}", theme, e);
return; anyhow::bail!("failed setting theme `{}` - {}", theme, e);
} }
}; };
self.set_theme(theme); self.set_theme(theme);
Ok(())
} }
fn _refresh(&mut self) { fn _refresh(&mut self) {