@@ -23,7 +23,7 @@ use helix_view::{
23 Document, DocumentId, Editor, ViewId,
23 Document, DocumentId, Editor, ViewId,
26−use anyhow::anyhow;
26+use anyhow::{anyhow, bail};
27use helix_lsp::{
27use helix_lsp::{
29 util::{lsp_pos_to_pos, lsp_range_to_range, pos_to_lsp_pos, range_to_lsp_range},
29 util::{lsp_pos_to_pos, lsp_range_to_range, pos_to_lsp_pos, range_to_lsp_range},
@@ -1161,34 +1161,52 @@ mod cmd {
1161 pub alias: Option<&'static str>,
1161 pub alias: Option<&'static str>,
1162 pub doc: &'static str,
1162 pub doc: &'static str,
1163 // params, flags, helper, completer
1163 // params, flags, helper, completer
1164− pub fun: fn(&mut compositor::Context, &[&str], PromptEvent),
1164+ pub fun: fn(&mut compositor::Context, &[&str], PromptEvent) -> anyhow::Result<()>,
1165 pub completer: Option<Completer>,
1165 pub completer: Option<Completer>,
1168− fn quit(cx: &mut compositor::Context, _args: &[&str], _event: PromptEvent) {
1169+ cx: &mut compositor::Context,
1171+ _event: PromptEvent,
1172+ ) -> anyhow::Result<()> {
1169 // last view and we have unsaved changes
1173 // last view and we have unsaved changes
1170− if cx.editor.tree.views().count() == 1 && buffers_remaining_impl(cx.editor) {
1174+ if cx.editor.tree.views().count() == 1 {
1171− return;
1175+ buffers_remaining_impl(cx.editor)?
1173 cx.editor
1178 cx.editor
1174 .close(view!(cx.editor).id, /* close_buffer */ false);
1179 .close(view!(cx.editor).id, /* close_buffer */ false);
1177− fn force_quit(cx: &mut compositor::Context, _args: &[&str], _event: PromptEvent) {
1185+ cx: &mut compositor::Context,
1187+ _event: PromptEvent,
1188+ ) -> anyhow::Result<()> {
1178 cx.editor
1189 cx.editor
1179 .close(view!(cx.editor).id, /* close_buffer */ false);
1190 .close(view!(cx.editor).id, /* close_buffer */ false);
1182− fn open(cx: &mut compositor::Context, args: &[&str], _event: PromptEvent) {
1196+ cx: &mut compositor::Context,
1198+ _event: PromptEvent,
1199+ ) -> anyhow::Result<()> {
1183 match args.get(0) {
1200 match args.get(0) {
1184 Some(path) => {
1201 Some(path) => {
1185− // TODO: handle error
1186− let _ = cx.editor.open(path.into(), Action::Replace);
1202+ let _ = cx.editor.open(path.into(), Action::Replace)?;
1188 None => {
1206 None => {
1189− cx.editor.set_error("wrong argument count".to_string());
1207+ bail!("wrong argument count");
1194 fn write_impl<P: AsRef<Path>>(
1212 fn write_impl<P: AsRef<Path>>(
@@ -1200,11 +1218,11 @@ mod cmd {
1201 if let Some(path) = path {
1219 if let Some(path) = path {
1202 if let Err(err) = doc.set_path(path.as_ref()) {
1220 if let Err(err) = doc.set_path(path.as_ref()) {
1203− return Err(anyhow!("invalid filepath: {}", err));
1221+ bail!("invalid filepath: {}", err);
1206 if doc.path().is_none() {
1224 if doc.path().is_none() {
1207− return Err(anyhow!("cannot write a buffer without a filename"));
1225+ bail!("cannot write a buffer without a filename");
1209 let fmt = doc.auto_format().map(|fmt| {
1227 let fmt = doc.auto_format().map(|fmt| {
1210 let shared = fmt.shared();
1228 let shared = fmt.shared();
@@ -1220,21 +1238,33 @@ mod cmd {
1220 Ok(tokio::spawn(doc.format_and_save(fmt)))
1238 Ok(tokio::spawn(doc.format_and_save(fmt)))
1223− fn write(cx: &mut compositor::Context, args: &[&str], _event: PromptEvent) {
1242+ cx: &mut compositor::Context,
1244+ _event: PromptEvent,
1245+ ) -> anyhow::Result<()> {
1224− match write_impl(cx, args.first()) {
1246+ let handle = write_impl(cx, args.first())?;
1225− Err(e) => cx.editor.set_error(e.to_string()),
1227− cx.jobs
1247+ cx.jobs
1228− .add(Job::new(handle.unwrap_or_else(|e| Err(e.into()))).wait_before_exiting());
1248+ .add(Job::new(handle.unwrap_or_else(|e| Err(e.into()))).wait_before_exiting());
1233− fn new_file(cx: &mut compositor::Context, _args: &[&str], _event: PromptEvent) {
1254+ cx: &mut compositor::Context,
1256+ _event: PromptEvent,
1257+ ) -> anyhow::Result<()> {
1234 cx.editor.new_file(Action::Replace);
1258 cx.editor.new_file(Action::Replace);
1237− fn format(cx: &mut compositor::Context, _args: &[&str], _event: PromptEvent) {
1264+ cx: &mut compositor::Context,
1266+ _event: PromptEvent,
1267+ ) -> anyhow::Result<()> {
1238 let (_, doc) = current!(cx.editor);
1268 let (_, doc) = current!(cx.editor);
1240 if let Some(format) = doc.format() {
1270 if let Some(format) = doc.format() {
@@ -1242,9 +1272,14 @@ mod cmd {
1242 make_format_callback(doc.id(), doc.version(), Modified::LeaveModified, format);
1272 make_format_callback(doc.id(), doc.version(), Modified::LeaveModified, format);
1243 cx.jobs.callback(callback);
1273 cx.jobs.callback(callback);
1278+ fn set_indent_style(
1247− fn set_indent_style(cx: &mut compositor::Context, args: &[&str], _event: PromptEvent) {
1279+ cx: &mut compositor::Context,
1281+ _event: PromptEvent,
1282+ ) -> anyhow::Result<()> {
1248 use IndentStyle::*;
1283 use IndentStyle::*;
1250 // If no argument, report current indent style.
1285 // If no argument, report current indent style.
@@ -1256,7 +1291,7 @@ mod cmd {
1256 Spaces(n) if (2..=8).contains(&n) => format!("{} spaces", n),
1291 Spaces(n) if (2..=8).contains(&n) => format!("{} spaces", n),
1257 _ => "error".into(), // Shouldn't happen.
1292 _ => "error".into(), // Shouldn't happen.
1259− return;
1294+ return Ok(());
1262 // Attempt to parse argument as an indent style.
1297 // Attempt to parse argument as an indent style.
@@ -1274,15 +1309,19 @@ mod cmd {
1274 if let Some(s) = style {
1309 if let Some(s) = style {
1275 let doc = doc_mut!(cx.editor);
1310 let doc = doc_mut!(cx.editor);
1276 doc.indent_style = s;
1311 doc.indent_style = s;
1277 } else {
1314 } else {
1278− // Invalid argument.
1280− .set_error(format!("invalid indent style '{}'", args[0],));
1315+ bail!("invalid indent style '{}'", args[0]);
1284 /// Sets or reports the current document's line ending setting.
1319 /// Sets or reports the current document's line ending setting.
1320+ fn set_line_ending(
1285− fn set_line_ending(cx: &mut compositor::Context, args: &[&str], _event: PromptEvent) {
1321+ cx: &mut compositor::Context,
1323+ _event: PromptEvent,
1324+ ) -> anyhow::Result<()> {
1286 use LineEnding::*;
1325 use LineEnding::*;
1288 // If no argument, report current line ending setting.
1327 // If no argument, report current line ending setting.
@@ -1298,7 +1337,8 @@ mod cmd {
1298 // These should never be a document's default line ending.
1337 // These should never be a document's default line ending.
1299 VT | LS | PS => "error".into(),
1338 VT | LS | PS => "error".into(),
1301− return;
1341+ return Ok(());
1304 // Attempt to parse argument as a line ending.
1344 // Attempt to parse argument as a line ending.
@@ -1314,70 +1354,66 @@ mod cmd {
1315 if let Some(le) = line_ending {
1355 if let Some(le) = line_ending {
1316 doc_mut!(cx.editor).line_ending = le;
1356 doc_mut!(cx.editor).line_ending = le;
1317 } else {
1358 } else {
1318− // Invalid argument.
1320− .set_error(format!("invalid line ending '{}'", args[0],));
1359+ bail!("invalid line ending '{}'", args[0]);
1324− fn earlier(cx: &mut compositor::Context, args: &[&str], _event: PromptEvent) {
1364+ cx: &mut compositor::Context,
1366+ _event: PromptEvent,
1367+ ) -> anyhow::Result<()> {
1325− let uk = match args.join(" ").parse::<helix_core::history::UndoKind>() {
1370+ .parse::<helix_core::history::UndoKind>()
1326− Ok(uk) => uk,
1371+ .map_err(|s| anyhow!(s))?;
1328− cx.editor.set_error(msg);
1332 let (view, doc) = current!(cx.editor);
1373 let (view, doc) = current!(cx.editor);
1333− doc.earlier(view.id, uk)
1374+ doc.earlier(view.id, uk);
1336− fn later(cx: &mut compositor::Context, args: &[&str], _event: PromptEvent) {
1380+ cx: &mut compositor::Context,
1382+ _event: PromptEvent,
1383+ ) -> anyhow::Result<()> {
1337− let uk = match args.join(" ").parse::<helix_core::history::UndoKind>() {
1386+ .parse::<helix_core::history::UndoKind>()
1338− Ok(uk) => uk,
1387+ .map_err(|s| anyhow!(s))?;
1340− cx.editor.set_error(msg);
1344 let (view, doc) = current!(cx.editor);
1388 let (view, doc) = current!(cx.editor);
1345− doc.later(view.id, uk)
1389+ doc.later(view.id, uk);
1348− fn write_quit(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) {
1395+ cx: &mut compositor::Context,
1397+ event: PromptEvent,
1398+ ) -> anyhow::Result<()> {
1349− match write_impl(cx, args.first()) {
1399+ let handle = write_impl(cx, args.first())?;
1351− if let Err(e) = helix_lsp::block_on(handle) {
1400+ helix_lsp::block_on(handle)?;
1352− cx.editor.set_error(e.to_string());
1354− quit(cx, &[], event);
1401+ quit(cx, &[], event)
1358− cx.editor.set_error(e.to_string());
1404+ fn force_write_quit(
1363− fn force_write_quit(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) {
1405+ cx: &mut compositor::Context,
1407+ event: PromptEvent,
1408+ ) -> anyhow::Result<()> {
1364− match write_impl(cx, args.first()) {
1409+ let handle = write_impl(cx, args.first())?;
1366− if let Err(e) = helix_lsp::block_on(handle) {
1410+ helix_lsp::block_on(handle)?;
1367− cx.editor.set_error(e.to_string());
1369− force_quit(cx, &[], event);
1411+ force_quit(cx, &[], event)
1373− cx.editor.set_error(e.to_string());
1378− /// Returns `true` if there are modified buffers remaining and sets editor error,
1414+ /// Results an error if there are modified buffers remaining and sets editor error,
1379− /// otherwise returns `false`
1415+ /// otherwise returns `Ok(())`
1380− fn buffers_remaining_impl(editor: &mut Editor) -> bool {
1416+ fn buffers_remaining_impl(editor: &mut Editor) -> anyhow::Result<()> {
1381 let modified: Vec<_> = editor
1417 let modified: Vec<_> = editor
1382 .documents()
1418 .documents()
1383 .filter(|doc| doc.is_modified())
1419 .filter(|doc| doc.is_modified())
@@ -1388,16 +1424,13 @@ mod cmd {
1389 .collect();
1425 .collect();
1390 if !modified.is_empty() {
1426 if !modified.is_empty() {
1391− let err = format!(
1427+ bail!(
1392 "{} unsaved buffer(s) remaining: {:?}",
1428 "{} unsaved buffer(s) remaining: {:?}",
1393 modified.len(),
1429 modified.len(),
1394 modified
1430 modified
1396− editor.set_error(err);
1403 fn write_all_impl(
1436 fn write_all_impl(
@@ -1406,7 +1439,7 @@ mod cmd {
1406 _event: PromptEvent,
1439 _event: PromptEvent,
1407 quit: bool,
1440 quit: bool,
1408 force: bool,
1441 force: bool,
1409− ) {
1442+ ) -> anyhow::Result<()> {
1410 let mut errors = String::new();
1443 let mut errors = String::new();
1412 // save all documents
1445 // save all documents
@@ -1419,11 +1452,10 @@ mod cmd {
1419 // TODO: handle error.
1452 // TODO: handle error.
1420 let _ = helix_lsp::block_on(tokio::spawn(doc.save()));
1453 let _ = helix_lsp::block_on(tokio::spawn(doc.save()));
1422− editor.set_error(errors);
1424 if quit {
1456 if quit {
1425− if !force && buffers_remaining_impl(editor) {
1458+ buffers_remaining_impl(editor)?;
1429 // close all views
1461 // close all views
@@ -1432,23 +1464,42 @@ mod cmd {
1432 editor.close(view_id, false);
1464 editor.close(view_id, false);
1437− fn write_all(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) {
1472+ cx: &mut compositor::Context,
1474+ event: PromptEvent,
1475+ ) -> anyhow::Result<()> {
1438 write_all_impl(&mut cx.editor, args, event, false, false)
1476 write_all_impl(&mut cx.editor, args, event, false, false)
1441− fn write_all_quit(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) {
1480+ cx: &mut compositor::Context,
1482+ event: PromptEvent,
1483+ ) -> anyhow::Result<()> {
1442 write_all_impl(&mut cx.editor, args, event, true, false)
1484 write_all_impl(&mut cx.editor, args, event, true, false)
1445− fn force_write_all_quit(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) {
1487+ fn force_write_all_quit(
1488+ cx: &mut compositor::Context,
1490+ event: PromptEvent,
1491+ ) -> anyhow::Result<()> {
1446 write_all_impl(&mut cx.editor, args, event, true, true)
1492 write_all_impl(&mut cx.editor, args, event, true, true)
1496+ editor: &mut Editor,
1449− fn quit_all_impl(editor: &mut Editor, _args: &[&str], _event: PromptEvent, force: bool) {
1498+ _event: PromptEvent,
1500+ ) -> anyhow::Result<()> {
1450− if !force && buffers_remaining_impl(editor) {
1502+ buffers_remaining_impl(editor)?;
1454 // close all views
1505 // close all views
@@ -1456,57 +1507,82 @@ mod cmd {
1456 for view_id in views {
1507 for view_id in views {
1457 editor.close(view_id, false);
1508 editor.close(view_id, false);
1461− fn quit_all(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) {
1515+ cx: &mut compositor::Context,
1517+ event: PromptEvent,
1518+ ) -> anyhow::Result<()> {
1462 quit_all_impl(&mut cx.editor, args, event, false)
1519 quit_all_impl(&mut cx.editor, args, event, false)
1465− fn force_quit_all(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) {
1523+ cx: &mut compositor::Context,
1525+ event: PromptEvent,
1526+ ) -> anyhow::Result<()> {
1466 quit_all_impl(&mut cx.editor, args, event, true)
1527 quit_all_impl(&mut cx.editor, args, event, true)
1469− fn theme(cx: &mut compositor::Context, args: &[&str], _event: PromptEvent) {
1531+ cx: &mut compositor::Context,
1533+ _event: PromptEvent,
1534+ ) -> anyhow::Result<()> {
1470 let theme = if let Some(theme) = args.first() {
1535 let theme = if let Some(theme) = args.first() {
1472 } else {
1537 } else {
1473− cx.editor.set_error("theme name not provided".into());
1538+ bail!("theme name not provided");
1477− cx.editor.set_theme_from_name(theme);
1541+ cx.editor.set_theme_from_name(theme)
1480 fn yank_main_selection_to_clipboard(
1544 fn yank_main_selection_to_clipboard(
1481 cx: &mut compositor::Context,
1545 cx: &mut compositor::Context,
1482 _args: &[&str],
1546 _args: &[&str],
1483 _event: PromptEvent,
1547 _event: PromptEvent,
1484− ) {
1548+ ) -> anyhow::Result<()> {
1485− yank_main_selection_to_clipboard_impl(&mut cx.editor);
1549+ yank_main_selection_to_clipboard_impl(&mut cx.editor)
1488− fn yank_joined_to_clipboard(cx: &mut compositor::Context, args: &[&str], _event: PromptEvent) {
1552+ fn yank_joined_to_clipboard(
1553+ cx: &mut compositor::Context,
1555+ _event: PromptEvent,
1556+ ) -> anyhow::Result<()> {
1489 let (_, doc) = current!(cx.editor);
1557 let (_, doc) = current!(cx.editor);
1490 let separator = args
1558 let separator = args
1491 .first()
1559 .first()
1492 .copied()
1560 .copied()
1493 .unwrap_or_else(|| doc.line_ending.as_str());
1561 .unwrap_or_else(|| doc.line_ending.as_str());
1494− yank_joined_to_clipboard_impl(&mut cx.editor, separator);
1562+ yank_joined_to_clipboard_impl(&mut cx.editor, separator)
1497− fn paste_clipboard_after(cx: &mut compositor::Context, _args: &[&str], _event: PromptEvent) {
1565+ fn paste_clipboard_after(
1566+ cx: &mut compositor::Context,
1568+ _event: PromptEvent,
1569+ ) -> anyhow::Result<()> {
1498− paste_clipboard_impl(&mut cx.editor, Paste::After);
1570+ paste_clipboard_impl(&mut cx.editor, Paste::After)
1501− fn paste_clipboard_before(cx: &mut compositor::Context, _args: &[&str], _event: PromptEvent) {
1573+ fn paste_clipboard_before(
1574+ cx: &mut compositor::Context,
1576+ _event: PromptEvent,
1577+ ) -> anyhow::Result<()> {
1502− paste_clipboard_impl(&mut cx.editor, Paste::After);
1578+ paste_clipboard_impl(&mut cx.editor, Paste::After)
1505 fn replace_selections_with_clipboard(
1581 fn replace_selections_with_clipboard(
1506 cx: &mut compositor::Context,
1582 cx: &mut compositor::Context,
1507 _args: &[&str],
1583 _args: &[&str],
1508 _event: PromptEvent,
1584 _event: PromptEvent,
1509− ) {
1585+ ) -> anyhow::Result<()> {
1510 let (view, doc) = current!(cx.editor);
1586 let (view, doc) = current!(cx.editor);
1512 match cx.editor.clipboard_provider.get_contents() {
1588 match cx.editor.clipboard_provider.get_contents() {
@@ -1520,71 +1596,89 @@ mod cmd {
1521 doc.apply(&transaction, view.id);
1597 doc.apply(&transaction, view.id);
1522 doc.append_changes_to_history(view.id);
1598 doc.append_changes_to_history(view.id);
1602+ log::error!("Couldn't get system clipboard contents: {:?}", e);
1603+ bail!("Couldn't get system clipboard contents: {:?}", e);
1524− Err(e) => log::error!("Couldn't get system clipboard contents: {:?}", e),
1528− fn show_clipboard_provider(cx: &mut compositor::Context, _args: &[&str], _event: PromptEvent) {
1608+ fn show_clipboard_provider(
1609+ cx: &mut compositor::Context,
1611+ _event: PromptEvent,
1612+ ) -> anyhow::Result<()> {
1529 cx.editor
1613 cx.editor
1530 .set_status(cx.editor.clipboard_provider.name().into());
1614 .set_status(cx.editor.clipboard_provider.name().into());
1533− fn change_current_directory(cx: &mut compositor::Context, args: &[&str], _event: PromptEvent) {
1618+ fn change_current_directory(
1619+ cx: &mut compositor::Context,
1621+ _event: PromptEvent,
1622+ ) -> anyhow::Result<()> {
1534− let dir = match args.first() {
1623+ let dir = args
1535− Some(dir) => dir,
1624+ .first()
1537− cx.editor.set_error("target directory not provided".into());
1625+ .ok_or_else(|| anyhow!("target directory not provided"))?;
1542 if let Err(e) = std::env::set_current_dir(dir) {
1627 if let Err(e) = std::env::set_current_dir(dir) {
1543− cx.editor.set_error(format!(
1544− "Couldn't change the current working directory: {:?}",
1628+ bail!("Couldn't change the current working directory: {:?}", e);
1550 match std::env::current_dir() {
1631 match std::env::current_dir() {
1551− Ok(cwd) => cx.editor.set_status(format!(
1633+ cx.editor.set_status(format!(
1552− "Current working directory is now {}",
1634+ "Current working directory is now {}",
1553− cwd.display()
1635+ cwd.display()
1555− Err(e) => cx
1638+ }
1557− .set_error(format!("Couldn't get the new working directory: {}", e)),
1639+ Err(e) => bail!("Couldn't get the new working directory: {}", e),
1561− fn show_current_directory(cx: &mut compositor::Context, _args: &[&str], _event: PromptEvent) {
1643+ fn show_current_directory(
1644+ cx: &mut compositor::Context,
1646+ _event: PromptEvent,
1647+ ) -> anyhow::Result<()> {
1562 match std::env::current_dir() {
1648 match std::env::current_dir() {
1563− Ok(cwd) => cx
1649+ Ok(cwd) => {
1564− .editor
1650+ cx.editor
1565− .set_status(format!("Current working directory is {}", cwd.display())),
1651+ .set_status(format!("Current working directory is {}", cwd.display()));
1566− Err(e) => cx
1652+ Ok(())
1568− .set_error(format!("Couldn't get the current working directory: {}", e)),
1654+ Err(e) => bail!("Couldn't get the current working directory: {}", e),
1572 /// Sets the [`Document`]'s encoding..
1658 /// Sets the [`Document`]'s encoding..
1573− fn set_encoding(cx: &mut compositor::Context, args: &[&str], _: PromptEvent) {
1660+ cx: &mut compositor::Context,
1662+ _event: PromptEvent,
1663+ ) -> anyhow::Result<()> {
1574 let (_, doc) = current!(cx.editor);
1664 let (_, doc) = current!(cx.editor);
1575 if let Some(label) = args.first() {
1665 if let Some(label) = args.first() {
1576 doc.set_encoding(label)
1666 doc.set_encoding(label)
1577− .unwrap_or_else(|e| cx.editor.set_error(e.to_string()));
1578 } else {
1667 } else {
1579 let encoding = doc.encoding().name().to_string();
1668 let encoding = doc.encoding().name().to_string();
1580− cx.editor.set_status(encoding)
1669+ cx.editor.set_status(encoding);
1584 /// Reload the [`Document`] from its source file.
1674 /// Reload the [`Document`] from its source file.
1585− fn reload(cx: &mut compositor::Context, _args: &[&str], _: PromptEvent) {
1676+ cx: &mut compositor::Context,
1678+ _event: PromptEvent,
1679+ ) -> anyhow::Result<()> {
1586 let (view, doc) = current!(cx.editor);
1680 let (view, doc) = current!(cx.editor);
1587− doc.reload(view.id).unwrap();
1681+ doc.reload(view.id)
1590 pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[
1684 pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[
@@ -1849,7 +1943,9 @@ fn command_mode(cx: &mut Context) {
1851 if let Some(cmd) = cmd::COMMANDS.get(parts[0]) {
1945 if let Some(cmd) = cmd::COMMANDS.get(parts[0]) {
1852− (cmd.fun)(cx, &parts[1..], event);
1946+ if let Err(e) = (cmd.fun)(cx, &parts[1..], event) {
1947+ cx.editor.set_error(format!("{}", e));
1853 } else {
1949 } else {
1854 cx.editor
1950 cx.editor
1855 .set_error(format!("no such command: '{}'", parts[0]));
1951 .set_error(format!("no such command: '{}'", parts[0]));
@@ -2758,7 +2854,7 @@ fn yank(cx: &mut Context) {
2758 cx.editor.set_status(msg)
2854 cx.editor.set_status(msg)
2761−fn yank_joined_to_clipboard_impl(editor: &mut Editor, separator: &str) {
2857+fn yank_joined_to_clipboard_impl(editor: &mut Editor, separator: &str) -> anyhow::Result<()> {
2762 let (view, doc) = current!(editor);
2858 let (view, doc) = current!(editor);
2764 let values: Vec<String> = doc
2860 let values: Vec<String> = doc
@@ -2776,17 +2872,20 @@ fn yank_joined_to_clipboard_impl(editor: &mut Editor, separator: &str) {
2777 if let Err(e) = editor.clipboard_provider.set_contents(joined) {
2873 if let Err(e) = editor.clipboard_provider.set_contents(joined) {
2778 log::error!("Couldn't set system clipboard content: {:?}", e);
2874 log::error!("Couldn't set system clipboard content: {:?}", e);
2875+ bail!("Couldn't set system clipboard content: {:?}", e);
2781 editor.set_status(msg);
2878 editor.set_status(msg);
2784fn yank_joined_to_clipboard(cx: &mut Context) {
2883fn yank_joined_to_clipboard(cx: &mut Context) {
2785 let line_ending = current!(cx.editor).1.line_ending;
2884 let line_ending = current!(cx.editor).1.line_ending;
2786− yank_joined_to_clipboard_impl(&mut cx.editor, line_ending.as_str());
2885+ let _ = yank_joined_to_clipboard_impl(&mut cx.editor, line_ending.as_str());
2789−fn yank_main_selection_to_clipboard_impl(editor: &mut Editor) {
2888+fn yank_main_selection_to_clipboard_impl(editor: &mut Editor) -> anyhow::Result<()> {
2790 let (view, doc) = current!(editor);
2889 let (view, doc) = current!(editor);
2792 let value = doc
2891 let value = doc
@@ -2796,13 +2895,15 @@ fn yank_main_selection_to_clipboard_impl(editor: &mut Editor) {
2797 if let Err(e) = editor.clipboard_provider.set_contents(value.into_owned()) {
2896 if let Err(e) = editor.clipboard_provider.set_contents(value.into_owned()) {
2798 log::error!("Couldn't set system clipboard content: {:?}", e);
2897 log::error!("Couldn't set system clipboard content: {:?}", e);
2898+ bail!("Couldn't set system clipboard content: {:?}", e);
2801 editor.set_status("yanked main selection to system clipboard".to_owned());
2901 editor.set_status("yanked main selection to system clipboard".to_owned());
2804fn yank_main_selection_to_clipboard(cx: &mut Context) {
2905fn yank_main_selection_to_clipboard(cx: &mut Context) {
2805− yank_main_selection_to_clipboard_impl(&mut cx.editor);
2906+ let _ = yank_main_selection_to_clipboard_impl(&mut cx.editor);
2808#[derive(Copy, Clone)]
2909#[derive(Copy, Clone)]
@@ -2850,7 +2951,7 @@ fn paste_impl(
2850 Some(transaction)
2951 Some(transaction)
2853−fn paste_clipboard_impl(editor: &mut Editor, action: Paste) {
2954+fn paste_clipboard_impl(editor: &mut Editor, action: Paste) -> anyhow::Result<()> {
2854 let (view, doc) = current!(editor);
2955 let (view, doc) = current!(editor);
2856 match editor
2957 match editor
@@ -2861,18 +2962,22 @@ fn paste_clipboard_impl(editor: &mut Editor, action: Paste) {
2861 Ok(Some(transaction)) => {
2962 Ok(Some(transaction)) => {
2862 doc.apply(&transaction, view.id);
2963 doc.apply(&transaction, view.id);
2863 doc.append_changes_to_history(view.id);
2964 doc.append_changes_to_history(view.id);
2967+ Ok(None) => Ok(()),
2969+ log::error!("Couldn't get system clipboard contents: {:?}", e);
2970+ bail!("Couldn't get system clipboard contents: {:?}", e);
2866− Err(e) => log::error!("Couldn't get system clipboard contents: {:?}", e),
2870fn paste_clipboard_after(cx: &mut Context) {
2975fn paste_clipboard_after(cx: &mut Context) {
2871− paste_clipboard_impl(&mut cx.editor, Paste::After);
2976+ let _ = paste_clipboard_impl(&mut cx.editor, Paste::After);
2874fn paste_clipboard_before(cx: &mut Context) {
2979fn paste_clipboard_before(cx: &mut Context) {
2875− paste_clipboard_impl(&mut cx.editor, Paste::Before);
2980+ let _ = paste_clipboard_impl(&mut cx.editor, Paste::Before);
2878fn replace_with_yanked(cx: &mut Context) {
2983fn replace_with_yanked(cx: &mut Context) {