on master help sign in
Make the prompt callback take a Context.
fd1ae35Joe Neeman
helix-term/src/commands.rs+76−70
@@ -28,7 +28,7 @@ use insert::*;
28use movement::Movement;
28use movement::Movement;
29
29
30use crate::{
30use crate::{
31− compositor::{Callback, Component, Compositor},
31+ compositor::{self, Callback, Component, Compositor},
32 ui::{self, Completion, Picker, Popup, Prompt, PromptEvent},
32 ui::{self, Completion, Picker, Popup, Prompt, PromptEvent},
33};
33};
34
34
@@ -1032,30 +1032,32 @@ mod cmd {
1032 pub alias: Option<&'static str>,
1032 pub alias: Option<&'static str>,
1033 pub doc: &'static str,
1033 pub doc: &'static str,
1034 // params, flags, helper, completer
1034 // params, flags, helper, completer
1035− pub fun: fn(&mut Editor, &[&str], PromptEvent),
1035+ pub fun: fn(&mut compositor::Context, &[&str], PromptEvent),
1036 pub completer: Option<Completer>,
1036 pub completer: Option<Completer>,
1037 }
1037 }
1038
1038
1039− fn quit(editor: &mut Editor, args: &[&str], event: PromptEvent) {
1039+ fn quit(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) {
1040 // last view and we have unsaved changes
1040 // last view and we have unsaved changes
1041− if editor.tree.views().count() == 1 && buffers_remaining_impl(editor) {
1041+ if cx.editor.tree.views().count() == 1 && buffers_remaining_impl(cx.editor) {
1042 return;
1042 return;
1043 }
1043 }
1044+ cx.editor
1044− editor.close(view!(editor).id, /* close_buffer */ false);
1045+ .close(view!(cx.editor).id, /* close_buffer */ false);
1045 }
1046 }
1046
1047
1047− fn force_quit(editor: &mut Editor, args: &[&str], event: PromptEvent) {
1048+ fn force_quit(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) {
1049+ cx.editor
1048− editor.close(view!(editor).id, /* close_buffer */ false);
1050+ .close(view!(cx.editor).id, /* close_buffer */ false);
1049 }
1051 }
1050
1052
1051− fn open(editor: &mut Editor, args: &[&str], event: PromptEvent) {
1053+ fn open(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) {
1052 match args.get(0) {
1054 match args.get(0) {
1053 Some(path) => {
1055 Some(path) => {
1054 // TODO: handle error
1056 // TODO: handle error
1055− editor.open(path.into(), Action::Replace);
1057+ cx.editor.open(path.into(), Action::Replace);
1056 }
1058 }
1057 None => {
1059 None => {
1058− editor.set_error("wrong argument count".to_string());
1060+ cx.editor.set_error("wrong argument count".to_string());
1059 }
1061 }
1060 };
1062 };
1061 }
1063 }
@@ -1086,30 +1088,30 @@ mod cmd {
1086 Ok(())
1088 Ok(())
1087 }
1089 }
1088
1090
1089− fn write(editor: &mut Editor, args: &[&str], event: PromptEvent) {
1091+ fn write(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) {
1090− let (view, doc) = current!(editor);
1092+ let (view, doc) = current!(cx.editor);
1091 if let Err(e) = write_impl(view, doc, args.first()) {
1093 if let Err(e) = write_impl(view, doc, args.first()) {
1092− editor.set_error(e.to_string());
1094+ cx.editor.set_error(e.to_string());
1093 };
1095 };
1094 }
1096 }
1095
1097
1096− fn new_file(editor: &mut Editor, args: &[&str], event: PromptEvent) {
1098+ fn new_file(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) {
1097− editor.new_file(Action::Replace);
1099+ cx.editor.new_file(Action::Replace);
1098 }
1100 }
1099
1101
1100− fn format(editor: &mut Editor, args: &[&str], event: PromptEvent) {
1102+ fn format(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) {
1101− let (view, doc) = current!(editor);
1103+ let (view, doc) = current!(cx.editor);
1102
1104
1103 doc.format(view.id)
1105 doc.format(view.id)
1104 }
1106 }
1105
1107
1106− fn set_indent_style(editor: &mut Editor, args: &[&str], event: PromptEvent) {
1108+ fn set_indent_style(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) {
1107 use IndentStyle::*;
1109 use IndentStyle::*;
1108
1110
1109 // If no argument, report current indent style.
1111 // If no argument, report current indent style.
1110 if args.is_empty() {
1112 if args.is_empty() {
1111− let style = current!(editor).1.indent_style;
1113+ let style = current!(cx.editor).1.indent_style;
1112− editor.set_status(match style {
1114+ cx.editor.set_status(match style {
1113 Tabs => "tabs".into(),
1115 Tabs => "tabs".into(),
1114 Spaces(1) => "1 space".into(),
1116 Spaces(1) => "1 space".into(),
1115 Spaces(n) if (2..=8).contains(&n) => format!("{} spaces", n),
1117 Spaces(n) if (2..=8).contains(&n) => format!("{} spaces", n),
@@ -1131,22 +1133,23 @@ mod cmd {
1131 };
1133 };
1132
1134
1133 if let Some(s) = style {
1135 if let Some(s) = style {
1134− let doc = doc_mut!(editor);
1136+ let doc = doc_mut!(cx.editor);
1135 doc.indent_style = s;
1137 doc.indent_style = s;
1136 } else {
1138 } else {
1137 // Invalid argument.
1139 // Invalid argument.
1140+ cx.editor
1138− editor.set_error(format!("invalid indent style '{}'", args[0],));
1141+ .set_error(format!("invalid indent style '{}'", args[0],));
1139 }
1142 }
1140 }
1143 }
1141
1144
1142 /// Sets or reports the current document's line ending setting.
1145 /// Sets or reports the current document's line ending setting.
1143− fn set_line_ending(editor: &mut Editor, args: &[&str], event: PromptEvent) {
1146+ fn set_line_ending(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) {
1144 use LineEnding::*;
1147 use LineEnding::*;
1145
1148
1146 // If no argument, report current line ending setting.
1149 // If no argument, report current line ending setting.
1147 if args.is_empty() {
1150 if args.is_empty() {
1148− let line_ending = current!(editor).1.line_ending;
1151+ let line_ending = current!(cx.editor).1.line_ending;
1149− editor.set_status(match line_ending {
1152+ cx.editor.set_status(match line_ending {
1150 Crlf => "crlf".into(),
1153 Crlf => "crlf".into(),
1151 LF => "line feed".into(),
1154 LF => "line feed".into(),
1152 FF => "form feed".into(),
1155 FF => "form feed".into(),
@@ -1171,49 +1174,50 @@ mod cmd {
1171 };
1174 };
1172
1175
1173 if let Some(le) = line_ending {
1176 if let Some(le) = line_ending {
1174− doc_mut!(editor).line_ending = le;
1177+ doc_mut!(cx.editor).line_ending = le;
1175 } else {
1178 } else {
1176 // Invalid argument.
1179 // Invalid argument.
1180+ cx.editor
1177− editor.set_error(format!("invalid line ending '{}'", args[0],));
1181+ .set_error(format!("invalid line ending '{}'", args[0],));
1178 }
1182 }
1179 }
1183 }
1180
1184
1181− fn earlier(editor: &mut Editor, args: &[&str], event: PromptEvent) {
1185+ fn earlier(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) {
1182 let uk = match args.join(" ").parse::<helix_core::history::UndoKind>() {
1186 let uk = match args.join(" ").parse::<helix_core::history::UndoKind>() {
1183 Ok(uk) => uk,
1187 Ok(uk) => uk,
1184 Err(msg) => {
1188 Err(msg) => {
1185− editor.set_error(msg);
1189+ cx.editor.set_error(msg);
1186 return;
1190 return;
1187 }
1191 }
1188 };
1192 };
1189− let (view, doc) = current!(editor);
1193+ let (view, doc) = current!(cx.editor);
1190 doc.earlier(view.id, uk)
1194 doc.earlier(view.id, uk)
1191 }
1195 }
1192
1196
1193− fn later(editor: &mut Editor, args: &[&str], event: PromptEvent) {
1197+ fn later(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) {
1194 let uk = match args.join(" ").parse::<helix_core::history::UndoKind>() {
1198 let uk = match args.join(" ").parse::<helix_core::history::UndoKind>() {
1195 Ok(uk) => uk,
1199 Ok(uk) => uk,
1196 Err(msg) => {
1200 Err(msg) => {
1197− editor.set_error(msg);
1201+ cx.editor.set_error(msg);
1198 return;
1202 return;
1199 }
1203 }
1200 };
1204 };
1201− let (view, doc) = current!(editor);
1205+ let (view, doc) = current!(cx.editor);
1202 doc.later(view.id, uk)
1206 doc.later(view.id, uk)
1203 }
1207 }
1204
1208
1205− fn write_quit(editor: &mut Editor, args: &[&str], event: PromptEvent) {
1209+ fn write_quit(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) {
1206− let (view, doc) = current!(editor);
1210+ let (view, doc) = current!(cx.editor);
1207 if let Err(e) = write_impl(view, doc, args.first()) {
1211 if let Err(e) = write_impl(view, doc, args.first()) {
1208− editor.set_error(e.to_string());
1212+ cx.editor.set_error(e.to_string());
1209 return;
1213 return;
1210 };
1214 };
1211− quit(editor, &[], event)
1215+ quit(cx, &[], event)
1212 }
1216 }
1213
1217
1214− fn force_write_quit(editor: &mut Editor, args: &[&str], event: PromptEvent) {
1218+ fn force_write_quit(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) {
1215− write(editor, args, event);
1219+ write(cx, args, event);
1216− force_quit(editor, &[], event);
1220+ force_quit(cx, &[], event);
1217 }
1221 }
1218
1222
1219 /// Returns `true` if there are modified buffers remaining and sets editor error,
1223 /// Returns `true` if there are modified buffers remaining and sets editor error,
@@ -1273,16 +1277,16 @@ mod cmd {
1273 }
1277 }
1274 }
1278 }
1275
1279
1276− fn write_all(editor: &mut Editor, args: &[&str], event: PromptEvent) {
1280+ fn write_all(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) {
1277− write_all_impl(editor, args, event, false, false)
1281+ write_all_impl(&mut cx.editor, args, event, false, false)
1278 }
1282 }
1279
1283
1280− fn write_all_quit(editor: &mut Editor, args: &[&str], event: PromptEvent) {
1284+ fn write_all_quit(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) {
1281− write_all_impl(editor, args, event, true, false)
1285+ write_all_impl(&mut cx.editor, args, event, true, false)
1282 }
1286 }
1283
1287
1284− fn force_write_all_quit(editor: &mut Editor, args: &[&str], event: PromptEvent) {
1288+ fn force_write_all_quit(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) {
1285− write_all_impl(editor, args, event, true, true)
1289+ write_all_impl(&mut cx.editor, args, event, true, true)
1286 }
1290 }
1287
1291
1288 fn quit_all_impl(editor: &mut Editor, args: &[&str], event: PromptEvent, force: bool) {
1292 fn quit_all_impl(editor: &mut Editor, args: &[&str], event: PromptEvent, force: bool) {
@@ -1297,50 +1301,50 @@ mod cmd {
1297 }
1301 }
1298 }
1302 }
1299
1303
1300− fn quit_all(editor: &mut Editor, args: &[&str], event: PromptEvent) {
1304+ fn quit_all(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) {
1301− quit_all_impl(editor, args, event, false)
1305+ quit_all_impl(&mut cx.editor, args, event, false)
1302 }
1306 }
1303
1307
1304− fn force_quit_all(editor: &mut Editor, args: &[&str], event: PromptEvent) {
1308+ fn force_quit_all(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) {
1305− quit_all_impl(editor, args, event, true)
1309+ quit_all_impl(&mut cx.editor, args, event, true)
1306 }
1310 }
1307
1311
1308− fn theme(editor: &mut Editor, args: &[&str], event: PromptEvent) {
1312+ fn theme(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) {
1309 let theme = if let Some(theme) = args.first() {
1313 let theme = if let Some(theme) = args.first() {
1310 theme
1314 theme
1311 } else {
1315 } else {
1312− editor.set_error("theme name not provided".into());
1316+ cx.editor.set_error("theme name not provided".into());
1313 return;
1317 return;
1314 };
1318 };
1315
1319
1316− editor.set_theme_from_name(theme);
1320+ cx.editor.set_theme_from_name(theme);
1317 }
1321 }
1318
1322
1319− fn yank_main_selection_to_clipboard(editor: &mut Editor, _: &[&str], _: PromptEvent) {
1323+ fn yank_main_selection_to_clipboard(cx: &mut compositor::Context, _: &[&str], _: PromptEvent) {
1320− yank_main_selection_to_clipboard_impl(editor);
1324+ yank_main_selection_to_clipboard_impl(&mut cx.editor);
1321 }
1325 }
1322
1326
1323− fn yank_joined_to_clipboard(editor: &mut Editor, args: &[&str], _: PromptEvent) {
1327+ fn yank_joined_to_clipboard(cx: &mut compositor::Context, args: &[&str], _: PromptEvent) {
1324− let (_, doc) = current!(editor);
1328+ let (_, doc) = current!(cx.editor);
1325 let separator = args
1329 let separator = args
1326 .first()
1330 .first()
1327 .copied()
1331 .copied()
1328 .unwrap_or_else(|| doc.line_ending.as_str());
1332 .unwrap_or_else(|| doc.line_ending.as_str());
1329− yank_joined_to_clipboard_impl(editor, separator);
1333+ yank_joined_to_clipboard_impl(&mut cx.editor, separator);
1330 }
1334 }
1331
1335
1332− fn paste_clipboard_after(editor: &mut Editor, _: &[&str], _: PromptEvent) {
1336+ fn paste_clipboard_after(cx: &mut compositor::Context, _: &[&str], _: PromptEvent) {
1333− paste_clipboard_impl(editor, Paste::After);
1337+ paste_clipboard_impl(&mut cx.editor, Paste::After);
1334 }
1338 }
1335
1339
1336− fn paste_clipboard_before(editor: &mut Editor, _: &[&str], _: PromptEvent) {
1340+ fn paste_clipboard_before(cx: &mut compositor::Context, _: &[&str], _: PromptEvent) {
1337− paste_clipboard_impl(editor, Paste::After);
1341+ paste_clipboard_impl(&mut cx.editor, Paste::After);
1338 }
1342 }
1339
1343
1340− fn replace_selections_with_clipboard(editor: &mut Editor, _: &[&str], _: PromptEvent) {
1344+ fn replace_selections_with_clipboard(cx: &mut compositor::Context, _: &[&str], _: PromptEvent) {
1341− let (view, doc) = current!(editor);
1345+ let (view, doc) = current!(cx.editor);
1342
1346
1343− match editor.clipboard_provider.get_contents() {
1347+ match cx.editor.clipboard_provider.get_contents() {
1344 Ok(contents) => {
1348 Ok(contents) => {
1345 let transaction =
1349 let transaction =
1346 Transaction::change_by_selection(doc.text(), doc.selection(view.id), |range| {
1350 Transaction::change_by_selection(doc.text(), doc.selection(view.id), |range| {
@@ -1356,8 +1360,9 @@ mod cmd {
1356 }
1360 }
1357 }
1361 }
1358
1362
1359− fn show_clipboard_provider(editor: &mut Editor, _: &[&str], _: PromptEvent) {
1363+ fn show_clipboard_provider(cx: &mut compositor::Context, _: &[&str], _: PromptEvent) {
1364+ cx.editor
1360− editor.set_status(editor.clipboard_provider.name().into());
1365+ .set_status(cx.editor.clipboard_provider.name().into());
1361 }
1366 }
1362
1367
1363 fn change_current_directory(editor: &mut Editor, args: &[&str], _: PromptEvent) {
1368 fn change_current_directory(editor: &mut Editor, args: &[&str], _: PromptEvent) {
@@ -1633,7 +1638,7 @@ fn command_mode(cx: &mut Context) {
1633 }
1638 }
1634 }
1639 }
1635 }, // completion
1640 }, // completion
1636− move |editor: &mut Editor, input: &str, event: PromptEvent| {
1641+ move |cx: &mut compositor::Context, input: &str, event: PromptEvent| {
1637 use helix_view::editor::Action;
1642 use helix_view::editor::Action;
1638
1643
1639 if event != PromptEvent::Validate {
1644 if event != PromptEvent::Validate {
@@ -1646,9 +1651,10 @@ fn command_mode(cx: &mut Context) {
1646 }
1651 }
1647
1652
1648 if let Some(cmd) = cmd::COMMANDS.get(parts[0]) {
1653 if let Some(cmd) = cmd::COMMANDS.get(parts[0]) {
1649− (cmd.fun)(editor, &parts[1..], event);
1654+ (cmd.fun)(cx, &parts[1..], event);
1650 } else {
1655 } else {
1656+ cx.editor
1651− editor.set_error(format!("no such command: '{}'", parts[0]));
1657+ .set_error(format!("no such command: '{}'", parts[0]));
1652 };
1658 };
1653 },
1659 },
1654 );
1660 );
helix-term/src/ui/mod.rs+4−4
@@ -39,10 +39,10 @@ pub fn regex_prompt(
39 Prompt::new(
39 Prompt::new(
40 prompt,
40 prompt,
41 |input: &str| Vec::new(), // this is fine because Vec::new() doesn't allocate
41 |input: &str| Vec::new(), // this is fine because Vec::new() doesn't allocate
42− move |editor: &mut Editor, input: &str, event: PromptEvent| {
42+ move |cx: &mut crate::compositor::Context, input: &str, event: PromptEvent| {
43 match event {
43 match event {
44 PromptEvent::Abort => {
44 PromptEvent::Abort => {
45− let (view, doc) = current!(editor);
45+ let (view, doc) = current!(cx.editor);
46 doc.set_selection(view.id, snapshot.clone());
46 doc.set_selection(view.id, snapshot.clone());
47 }
47 }
48 PromptEvent::Validate => {
48 PromptEvent::Validate => {
@@ -56,8 +56,8 @@ pub fn regex_prompt(
56
56
57 match Regex::new(input) {
57 match Regex::new(input) {
58 Ok(regex) => {
58 Ok(regex) => {
59− let (view, doc) = current!(editor);
59+ let (view, doc) = current!(cx.editor);
60− let registers = &mut editor.registers;
60+ let registers = &mut cx.editor.registers;
61
61
62 // revert state to what it was before the last update
62 // revert state to what it was before the last update
63 doc.set_selection(view.id, snapshot.clone());
63 doc.set_selection(view.id, snapshot.clone());
helix-term/src/ui/picker.rs+1−1
@@ -44,7 +44,7 @@ impl<T> Picker<T> {
44 let prompt = Prompt::new(
44 let prompt = Prompt::new(
45 "".to_string(),
45 "".to_string(),
46 |pattern: &str| Vec::new(),
46 |pattern: &str| Vec::new(),
47− |editor: &mut Editor, pattern: &str, event: PromptEvent| {
47+ |editor: &mut Context, pattern: &str, event: PromptEvent| {
48 //
48 //
49 },
49 },
50 );
50 );
helix-term/src/ui/prompt.rs+6−6
@@ -20,7 +20,7 @@ pub struct Prompt {
20 completion: Vec<Completion>,
20 completion: Vec<Completion>,
21 selection: Option<usize>,
21 selection: Option<usize>,
22 completion_fn: Box<dyn FnMut(&str) -> Vec<Completion>>,
22 completion_fn: Box<dyn FnMut(&str) -> Vec<Completion>>,
23− callback_fn: Box<dyn FnMut(&mut Editor, &str, PromptEvent)>,
23+ callback_fn: Box<dyn FnMut(&mut Context, &str, PromptEvent)>,
24 pub doc_fn: Box<dyn Fn(&str) -> Option<&'static str>>,
24 pub doc_fn: Box<dyn Fn(&str) -> Option<&'static str>>,
25}
25}
26
26
@@ -54,7 +54,7 @@ impl Prompt {
54 pub fn new(
54 pub fn new(
55 prompt: String,
55 prompt: String,
56 mut completion_fn: impl FnMut(&str) -> Vec<Completion> + 'static,
56 mut completion_fn: impl FnMut(&str) -> Vec<Completion> + 'static,
57− callback_fn: impl FnMut(&mut Editor, &str, PromptEvent) + 'static,
57+ callback_fn: impl FnMut(&mut Context, &str, PromptEvent) + 'static,
58 ) -> Self {
58 ) -> Self {
59 Self {
59 Self {
60 prompt,
60 prompt,
@@ -386,7 +386,7 @@ impl Component for Prompt {
386 modifiers: KeyModifiers::SHIFT,
386 modifiers: KeyModifiers::SHIFT,
387 } => {
387 } => {
388 self.insert_char(c);
388 self.insert_char(c);
389− (self.callback_fn)(cx.editor, &self.line, PromptEvent::Update);
389+ (self.callback_fn)(cx, &self.line, PromptEvent::Update);
390 }
390 }
391 KeyEvent {
391 KeyEvent {
392 code: KeyCode::Char('c'),
392 code: KeyCode::Char('c'),
@@ -395,7 +395,7 @@ impl Component for Prompt {
395 | KeyEvent {
395 | KeyEvent {
396 code: KeyCode::Esc, ..
396 code: KeyCode::Esc, ..
397 } => {
397 } => {
398− (self.callback_fn)(cx.editor, &self.line, PromptEvent::Abort);
398+ (self.callback_fn)(cx, &self.line, PromptEvent::Abort);
399 return close_fn;
399 return close_fn;
400 }
400 }
401 KeyEvent {
401 KeyEvent {
@@ -459,7 +459,7 @@ impl Component for Prompt {
459 modifiers: KeyModifiers::NONE,
459 modifiers: KeyModifiers::NONE,
460 } => {
460 } => {
461 self.delete_char_backwards();
461 self.delete_char_backwards();
462− (self.callback_fn)(cx.editor, &self.line, PromptEvent::Update);
462+ (self.callback_fn)(cx, &self.line, PromptEvent::Update);
463 }
463 }
464 KeyEvent {
464 KeyEvent {
465 code: KeyCode::Enter,
465 code: KeyCode::Enter,
@@ -469,7 +469,7 @@ impl Component for Prompt {
469 self.completion = (self.completion_fn)(&self.line);
469 self.completion = (self.completion_fn)(&self.line);
470 self.exit_selection();
470 self.exit_selection();
471 } else {
471 } else {
472− (self.callback_fn)(cx.editor, &self.line, PromptEvent::Validate);
472+ (self.callback_fn)(cx, &self.line, PromptEvent::Validate);
473 return close_fn;
473 return close_fn;
474 }
474 }
475 }
475 }