mirror of https://github.com/helix-editor/helix
commands: Simplify some code, only calling cx.doc() once.
parent
7877647cf0
commit
7da6bd6a71
|
@ -36,6 +36,15 @@ impl<'a> Context<'a> {
|
||||||
pub fn doc(&mut self) -> &mut Document {
|
pub fn doc(&mut self) -> &mut Document {
|
||||||
&mut self.editor.view_mut().doc
|
&mut self.editor.view_mut().doc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Push a new component onto the compositor.
|
||||||
|
pub fn push_layer(&mut self, component: Box<dyn crate::compositor::Component>) {
|
||||||
|
self.callback = Some(Box::new(
|
||||||
|
|compositor: &mut Compositor, editor: &mut Editor| {
|
||||||
|
compositor.push(component);
|
||||||
|
},
|
||||||
|
));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A command is a function that takes the current state and a count, and does a side-effect on the
|
/// A command is a function that takes the current state and a count, and does a side-effect on the
|
||||||
|
@ -44,42 +53,43 @@ pub type Command = fn(cx: &mut Context);
|
||||||
|
|
||||||
pub fn move_char_left(cx: &mut Context) {
|
pub fn move_char_left(cx: &mut Context) {
|
||||||
let count = cx.count;
|
let count = cx.count;
|
||||||
let selection =
|
let doc = cx.doc();
|
||||||
cx.doc()
|
let selection = doc
|
||||||
.state
|
.state
|
||||||
.move_selection(Direction::Backward, Granularity::Character, count);
|
.move_selection(Direction::Backward, Granularity::Character, count);
|
||||||
cx.doc().set_selection(selection);
|
doc.set_selection(selection);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn move_char_right(cx: &mut Context) {
|
pub fn move_char_right(cx: &mut Context) {
|
||||||
let count = cx.count;
|
let count = cx.count;
|
||||||
let selection =
|
let doc = cx.doc();
|
||||||
cx.doc()
|
let selection = doc
|
||||||
.state
|
.state
|
||||||
.move_selection(Direction::Forward, Granularity::Character, count);
|
.move_selection(Direction::Forward, Granularity::Character, count);
|
||||||
cx.doc().set_selection(selection);
|
doc.set_selection(selection);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn move_line_up(cx: &mut Context) {
|
pub fn move_line_up(cx: &mut Context) {
|
||||||
let count = cx.count;
|
let count = cx.count;
|
||||||
let selection = cx
|
let doc = cx.doc();
|
||||||
.doc()
|
let selection = doc
|
||||||
.state
|
.state
|
||||||
.move_selection(Direction::Backward, Granularity::Line, count);
|
.move_selection(Direction::Backward, Granularity::Line, count);
|
||||||
cx.doc().set_selection(selection);
|
doc.set_selection(selection);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn move_line_down(cx: &mut Context) {
|
pub fn move_line_down(cx: &mut Context) {
|
||||||
let count = cx.count;
|
let count = cx.count;
|
||||||
let selection = cx
|
let doc = cx.doc();
|
||||||
.doc()
|
let selection = doc
|
||||||
.state
|
.state
|
||||||
.move_selection(Direction::Forward, Granularity::Line, count);
|
.move_selection(Direction::Forward, Granularity::Line, count);
|
||||||
cx.doc().set_selection(selection);
|
doc.set_selection(selection);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn move_line_end(cx: &mut Context) {
|
pub fn move_line_end(cx: &mut Context) {
|
||||||
let lines = selection_lines(&cx.doc().state);
|
let doc = cx.doc();
|
||||||
|
let lines = selection_lines(&doc.state);
|
||||||
|
|
||||||
let positions = lines
|
let positions = lines
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
@ -88,29 +98,30 @@ pub fn move_line_end(cx: &mut Context) {
|
||||||
|
|
||||||
// Line end is pos at the start of next line - 1
|
// Line end is pos at the start of next line - 1
|
||||||
// subtract another 1 because the line ends with \n
|
// subtract another 1 because the line ends with \n
|
||||||
cx.doc().text().line_to_char(index + 1).saturating_sub(2)
|
doc.text().line_to_char(index + 1).saturating_sub(2)
|
||||||
})
|
})
|
||||||
.map(|pos| Range::new(pos, pos));
|
.map(|pos| Range::new(pos, pos));
|
||||||
|
|
||||||
let selection = Selection::new(positions.collect(), 0);
|
let selection = Selection::new(positions.collect(), 0);
|
||||||
|
|
||||||
cx.doc().set_selection(selection);
|
doc.set_selection(selection);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn move_line_start(cx: &mut Context) {
|
pub fn move_line_start(cx: &mut Context) {
|
||||||
let lines = selection_lines(&cx.doc().state);
|
let doc = cx.doc();
|
||||||
|
let lines = selection_lines(&doc.state);
|
||||||
|
|
||||||
let positions = lines
|
let positions = lines
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|index| {
|
.map(|index| {
|
||||||
// adjust all positions to the start of the line.
|
// adjust all positions to the start of the line.
|
||||||
cx.doc().text().line_to_char(index)
|
doc.text().line_to_char(index)
|
||||||
})
|
})
|
||||||
.map(|pos| Range::new(pos, pos));
|
.map(|pos| Range::new(pos, pos));
|
||||||
|
|
||||||
let selection = Selection::new(positions.collect(), 0);
|
let selection = Selection::new(positions.collect(), 0);
|
||||||
|
|
||||||
cx.doc().set_selection(selection);
|
doc.set_selection(selection);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn move_next_word_start(cx: &mut Context) {
|
pub fn move_next_word_start(cx: &mut Context) {
|
||||||
|
@ -139,17 +150,19 @@ pub fn move_next_word_end(cx: &mut Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn move_file_start(cx: &mut Context) {
|
pub fn move_file_start(cx: &mut Context) {
|
||||||
cx.doc().set_selection(Selection::point(0));
|
let doc = cx.doc();
|
||||||
|
doc.set_selection(Selection::point(0));
|
||||||
|
|
||||||
cx.doc().mode = Mode::Normal;
|
doc.mode = Mode::Normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn move_file_end(cx: &mut Context) {
|
pub fn move_file_end(cx: &mut Context) {
|
||||||
let text = &cx.doc().text();
|
let doc = cx.doc();
|
||||||
|
let text = doc.text();
|
||||||
let last_line = text.line_to_char(text.len_lines().saturating_sub(2));
|
let last_line = text.line_to_char(text.len_lines().saturating_sub(2));
|
||||||
cx.doc().set_selection(Selection::point(last_line));
|
doc.set_selection(Selection::point(last_line));
|
||||||
|
|
||||||
cx.doc().mode = Mode::Normal;
|
doc.mode = Mode::Normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn extend_next_word_start(cx: &mut Context) {
|
pub fn extend_next_word_start(cx: &mut Context) {
|
||||||
|
@ -161,7 +174,7 @@ pub fn extend_next_word_start(cx: &mut Context) {
|
||||||
range
|
range
|
||||||
}); // TODO: count
|
}); // TODO: count
|
||||||
|
|
||||||
cx.doc().set_selection(selection);
|
doc.set_selection(selection);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn extend_prev_word_start(cx: &mut Context) {
|
pub fn extend_prev_word_start(cx: &mut Context) {
|
||||||
|
@ -172,7 +185,7 @@ pub fn extend_prev_word_start(cx: &mut Context) {
|
||||||
range.head = pos;
|
range.head = pos;
|
||||||
range
|
range
|
||||||
}); // TODO: count
|
}); // TODO: count
|
||||||
cx.doc().set_selection(selection);
|
doc.set_selection(selection);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn extend_next_word_end(cx: &mut Context) {
|
pub fn extend_next_word_end(cx: &mut Context) {
|
||||||
|
@ -184,7 +197,7 @@ pub fn extend_next_word_end(cx: &mut Context) {
|
||||||
range
|
range
|
||||||
}); // TODO: count
|
}); // TODO: count
|
||||||
|
|
||||||
cx.doc().set_selection(selection);
|
doc.set_selection(selection);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_cursor_in_view(view: &View) -> bool {
|
pub fn check_cursor_in_view(view: &View) -> bool {
|
||||||
|
@ -309,11 +322,8 @@ pub fn select_regex(cx: &mut Context) {
|
||||||
selection::select_on_matches(text, doc.selection(), ®ex).expect("no matches");
|
selection::select_on_matches(text, doc.selection(), ®ex).expect("no matches");
|
||||||
doc.set_selection(selection);
|
doc.set_selection(selection);
|
||||||
});
|
});
|
||||||
cx.callback = Some(Box::new(
|
|
||||||
move |compositor: &mut Compositor, editor: &mut Editor| {
|
cx.push_layer(Box::new(prompt));
|
||||||
compositor.push(Box::new(prompt));
|
|
||||||
},
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn split_selection(cx: &mut Context) {
|
pub fn split_selection(cx: &mut Context) {
|
||||||
|
@ -336,11 +346,7 @@ pub fn split_selection(cx: &mut Context) {
|
||||||
doc.set_selection(selection);
|
doc.set_selection(selection);
|
||||||
});
|
});
|
||||||
|
|
||||||
cx.callback = Some(Box::new(
|
cx.push_layer(Box::new(prompt));
|
||||||
move |compositor: &mut Compositor, editor: &mut Editor| {
|
|
||||||
compositor.push(Box::new(prompt));
|
|
||||||
},
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn split_selection_on_newline(cx: &mut Context) {
|
pub fn split_selection_on_newline(cx: &mut Context) {
|
||||||
|
@ -393,11 +399,7 @@ pub fn search(cx: &mut Context) {
|
||||||
register::set('\\', vec![regex.as_str().to_string()]);
|
register::set('\\', vec![regex.as_str().to_string()]);
|
||||||
});
|
});
|
||||||
|
|
||||||
cx.callback = Some(Box::new(
|
cx.push_layer(Box::new(prompt));
|
||||||
move |compositor: &mut Compositor, editor: &mut Editor| {
|
|
||||||
compositor.push(Box::new(prompt));
|
|
||||||
},
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn search_next(cx: &mut Context) {
|
pub fn search_next(cx: &mut Context) {
|
||||||
|
@ -418,74 +420,76 @@ pub fn search_next(cx: &mut Context) {
|
||||||
|
|
||||||
pub fn select_line(cx: &mut Context) {
|
pub fn select_line(cx: &mut Context) {
|
||||||
// TODO: count
|
// TODO: count
|
||||||
let pos = cx.doc().selection().primary();
|
let doc = cx.doc();
|
||||||
let text = cx.doc().text();
|
let pos = doc.selection().primary();
|
||||||
|
let text = doc.text();
|
||||||
let line = text.char_to_line(pos.head);
|
let line = text.char_to_line(pos.head);
|
||||||
let start = text.line_to_char(line);
|
let start = text.line_to_char(line);
|
||||||
let end = text.line_to_char(line + 1).saturating_sub(1);
|
let end = text.line_to_char(line + 1).saturating_sub(1);
|
||||||
|
|
||||||
cx.doc().set_selection(Selection::single(start, end));
|
doc.set_selection(Selection::single(start, end));
|
||||||
}
|
}
|
||||||
|
|
||||||
// heuristic: append changes to history after each command, unless we're in insert mode
|
// heuristic: append changes to history after each command, unless we're in insert mode
|
||||||
|
|
||||||
fn _delete_selection(cx: &mut Context) {
|
fn _delete_selection(doc: &mut Document) {
|
||||||
let transaction = Transaction::change_by_selection(&cx.doc().state, |range| {
|
let transaction =
|
||||||
(range.from(), range.to() + 1, None)
|
Transaction::change_by_selection(&doc.state, |range| (range.from(), range.to() + 1, None));
|
||||||
});
|
doc.apply(&transaction);
|
||||||
cx.doc().apply(&transaction);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn delete_selection(cx: &mut Context) {
|
pub fn delete_selection(cx: &mut Context) {
|
||||||
_delete_selection(cx);
|
let doc = cx.doc();
|
||||||
|
_delete_selection(doc);
|
||||||
|
|
||||||
append_changes_to_history(cx);
|
append_changes_to_history(doc);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn change_selection(cx: &mut Context) {
|
pub fn change_selection(cx: &mut Context) {
|
||||||
_delete_selection(cx);
|
let doc = cx.doc();
|
||||||
|
_delete_selection(doc);
|
||||||
insert_mode(cx);
|
insert_mode(cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn collapse_selection(cx: &mut Context) {
|
pub fn collapse_selection(cx: &mut Context) {
|
||||||
let selection = cx
|
let doc = cx.doc();
|
||||||
.doc()
|
let selection = doc
|
||||||
.selection()
|
.selection()
|
||||||
.transform(|range| Range::new(range.head, range.head));
|
.transform(|range| Range::new(range.head, range.head));
|
||||||
|
|
||||||
cx.doc().set_selection(selection);
|
doc.set_selection(selection);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn flip_selections(cx: &mut Context) {
|
pub fn flip_selections(cx: &mut Context) {
|
||||||
let selection = cx
|
let doc = cx.doc();
|
||||||
.doc()
|
let selection = doc
|
||||||
.selection()
|
.selection()
|
||||||
.transform(|range| Range::new(range.head, range.anchor));
|
.transform(|range| Range::new(range.head, range.anchor));
|
||||||
|
|
||||||
cx.doc().set_selection(selection);
|
doc.set_selection(selection);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn enter_insert_mode(cx: &mut Context) {
|
fn enter_insert_mode(doc: &mut Document) {
|
||||||
cx.doc().mode = Mode::Insert;
|
doc.mode = Mode::Insert;
|
||||||
|
|
||||||
// TODO: store selection for undo
|
// TODO: store selection for undo
|
||||||
}
|
}
|
||||||
|
|
||||||
// inserts at the start of each selection
|
// inserts at the start of each selection
|
||||||
pub fn insert_mode(cx: &mut Context) {
|
pub fn insert_mode(cx: &mut Context) {
|
||||||
enter_insert_mode(cx);
|
let doc = cx.doc();
|
||||||
|
enter_insert_mode(doc);
|
||||||
|
|
||||||
let selection = cx
|
let selection = doc
|
||||||
.doc()
|
|
||||||
.selection()
|
.selection()
|
||||||
.transform(|range| Range::new(range.to(), range.from()));
|
.transform(|range| Range::new(range.to(), range.from()));
|
||||||
cx.doc().set_selection(selection);
|
doc.set_selection(selection);
|
||||||
}
|
}
|
||||||
|
|
||||||
// inserts at the end of each selection
|
// inserts at the end of each selection
|
||||||
pub fn append_mode(cx: &mut Context) {
|
pub fn append_mode(cx: &mut Context) {
|
||||||
enter_insert_mode(cx);
|
|
||||||
let doc = cx.doc();
|
let doc = cx.doc();
|
||||||
|
enter_insert_mode(doc);
|
||||||
doc.restore_cursor = true;
|
doc.restore_cursor = true;
|
||||||
|
|
||||||
// TODO: as transaction
|
// TODO: as transaction
|
||||||
|
@ -503,98 +507,56 @@ pub fn append_mode(cx: &mut Context) {
|
||||||
// TODO: I, A, o and O can share a lot of the primitives.
|
// TODO: I, A, o and O can share a lot of the primitives.
|
||||||
pub fn command_mode(cx: &mut Context) {
|
pub fn command_mode(cx: &mut Context) {
|
||||||
let executor = cx.executor;
|
let executor = cx.executor;
|
||||||
cx.callback = Some(Box::new(
|
let prompt = Prompt::new(
|
||||||
move |compositor: &mut Compositor, editor: &mut Editor| {
|
":".to_owned(),
|
||||||
let prompt = Prompt::new(
|
|_input: &str| {
|
||||||
":".to_owned(),
|
// TODO: i need this duplicate list right now to avoid borrow checker issues
|
||||||
|_input: &str| {
|
let command_list = vec![
|
||||||
// TODO: i need this duplicate list right now to avoid borrow checker issues
|
"q".to_string(),
|
||||||
let command_list = vec![
|
"o".to_string(),
|
||||||
"q".to_string(),
|
"w".to_string(),
|
||||||
"o".to_string(),
|
// String::from("q"),
|
||||||
"w".to_string(),
|
];
|
||||||
// String::from("q"),
|
command_list
|
||||||
// String::from("aaa"),
|
.into_iter()
|
||||||
// String::from("bbb"),
|
.filter(|command| command.contains(_input))
|
||||||
// String::from("ccc"),
|
.collect()
|
||||||
// String::from("ddd"),
|
}, // completion
|
||||||
// String::from("eee"),
|
move |editor: &mut Editor, input: &str, event: PromptEvent| {
|
||||||
// String::from("averylongcommandaverylongcommandaverylongcommandaverylongcommandaverylongcommand"),
|
if event != PromptEvent::Validate {
|
||||||
// String::from("q"),
|
return;
|
||||||
// String::from("aaa"),
|
}
|
||||||
// String::from("bbb"),
|
|
||||||
// String::from("ccc"),
|
|
||||||
// String::from("ddd"),
|
|
||||||
// String::from("eee"),
|
|
||||||
// String::from("q"),
|
|
||||||
// String::from("aaa"),
|
|
||||||
// String::from("bbb"),
|
|
||||||
// String::from("ccc"),
|
|
||||||
// String::from("ddd"),
|
|
||||||
// String::from("eee"),
|
|
||||||
// String::from("q"),
|
|
||||||
// String::from("aaa"),
|
|
||||||
// String::from("bbb"),
|
|
||||||
// String::from("ccc"),
|
|
||||||
// String::from("ddd"),
|
|
||||||
// String::from("eee"),
|
|
||||||
// String::from("q"),
|
|
||||||
// String::from("aaa"),
|
|
||||||
// String::from("bbb"),
|
|
||||||
// String::from("ccc"),
|
|
||||||
// String::from("ddd"),
|
|
||||||
// String::from("eee"),
|
|
||||||
];
|
|
||||||
command_list
|
|
||||||
.into_iter()
|
|
||||||
.filter(|command| command.contains(_input))
|
|
||||||
.collect()
|
|
||||||
}, // completion
|
|
||||||
move |editor: &mut Editor, input: &str, event: PromptEvent| {
|
|
||||||
if event != PromptEvent::Validate {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let parts = input.split_ascii_whitespace().collect::<Vec<&str>>();
|
let parts = input.split_ascii_whitespace().collect::<Vec<&str>>();
|
||||||
|
|
||||||
match *parts.as_slice() {
|
match *parts.as_slice() {
|
||||||
["q"] => {
|
["q"] => {
|
||||||
editor.tree.remove(editor.view().id);
|
editor.tree.remove(editor.view().id);
|
||||||
// editor.should_close = true,
|
// editor.should_close = true,
|
||||||
}
|
}
|
||||||
["o", path] => {
|
["o", path] => {
|
||||||
editor.open(path.into(), executor);
|
editor.open(path.into(), executor);
|
||||||
}
|
}
|
||||||
["w"] => {
|
["w"] => {
|
||||||
// TODO: non-blocking via save() command
|
// TODO: non-blocking via save() command
|
||||||
smol::block_on(editor.view_mut().doc.save());
|
smol::block_on(editor.view_mut().doc.save());
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
},
|
|
||||||
);
|
|
||||||
compositor.push(Box::new(prompt));
|
|
||||||
},
|
},
|
||||||
));
|
);
|
||||||
|
cx.push_layer(Box::new(prompt));
|
||||||
}
|
}
|
||||||
pub fn file_picker(cx: &mut Context) {
|
pub fn file_picker(cx: &mut Context) {
|
||||||
let picker = ui::file_picker("./", cx.executor);
|
let picker = ui::file_picker("./", cx.executor);
|
||||||
cx.callback = Some(Box::new(
|
cx.push_layer(Box::new(picker));
|
||||||
|compositor: &mut Compositor, editor: &mut Editor| {
|
|
||||||
compositor.push(Box::new(picker));
|
|
||||||
},
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn buffer_picker(cx: &mut Context) {
|
pub fn buffer_picker(cx: &mut Context) {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
// cx.callback = Some(Box::new(
|
// let picker = ui::buffer_picker(&editor.views, editor.focus);
|
||||||
// |compositor: &mut Compositor, editor: &mut Editor| {
|
// cx.push_layer(Box::new(picker));
|
||||||
// let picker = ui::buffer_picker(&editor.views, editor.focus);
|
|
||||||
// compositor.push(Box::new(picker));
|
|
||||||
// },
|
|
||||||
// ));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// calculate line numbers for each selection range
|
// calculate line numbers for each selection range
|
||||||
|
@ -614,23 +576,24 @@ fn selection_lines(state: &State) -> Vec<usize> {
|
||||||
|
|
||||||
// I inserts at the start of each line with a selection
|
// I inserts at the start of each line with a selection
|
||||||
pub fn prepend_to_line(cx: &mut Context) {
|
pub fn prepend_to_line(cx: &mut Context) {
|
||||||
enter_insert_mode(cx);
|
let doc = cx.doc();
|
||||||
|
enter_insert_mode(doc);
|
||||||
|
|
||||||
move_line_start(cx);
|
move_line_start(cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
// A inserts at the end of each line with a selection
|
// A inserts at the end of each line with a selection
|
||||||
pub fn append_to_line(cx: &mut Context) {
|
pub fn append_to_line(cx: &mut Context) {
|
||||||
enter_insert_mode(cx);
|
let doc = cx.doc();
|
||||||
|
enter_insert_mode(doc);
|
||||||
|
|
||||||
move_line_end(cx);
|
move_line_end(cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
// o inserts a new line after each line with a selection
|
// o inserts a new line after each line with a selection
|
||||||
pub fn open_below(cx: &mut Context) {
|
pub fn open_below(cx: &mut Context) {
|
||||||
enter_insert_mode(cx);
|
|
||||||
|
|
||||||
let doc = cx.doc();
|
let doc = cx.doc();
|
||||||
|
enter_insert_mode(doc);
|
||||||
|
|
||||||
let lines = selection_lines(&doc.state);
|
let lines = selection_lines(&doc.state);
|
||||||
|
|
||||||
|
@ -687,41 +650,41 @@ pub fn open_below(cx: &mut Context) {
|
||||||
|
|
||||||
// O inserts a new line before each line with a selection
|
// O inserts a new line before each line with a selection
|
||||||
|
|
||||||
fn append_changes_to_history(cx: &mut Context) {
|
fn append_changes_to_history(doc: &mut Document) {
|
||||||
if cx.doc().changes.is_empty() {
|
if doc.changes.is_empty() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: change -> change -> undo -> change -> change fails, probably old_state needs reset
|
// TODO: change -> change -> undo -> change -> change fails, probably old_state needs reset
|
||||||
|
|
||||||
let new_changeset = ChangeSet::new(cx.doc().text());
|
let new_changeset = ChangeSet::new(doc.text());
|
||||||
let changes = std::mem::replace(&mut cx.doc().changes, new_changeset);
|
let changes = std::mem::replace(&mut doc.changes, new_changeset);
|
||||||
// Instead of doing this messy merge we could always commit, and based on transaction
|
// Instead of doing this messy merge we could always commit, and based on transaction
|
||||||
// annotations either add a new layer or compose into the previous one.
|
// annotations either add a new layer or compose into the previous one.
|
||||||
let transaction = Transaction::from(changes).with_selection(cx.doc().selection().clone());
|
let transaction = Transaction::from(changes).with_selection(doc.selection().clone());
|
||||||
|
|
||||||
// increment document version
|
// increment document version
|
||||||
// TODO: needs to happen on undo/redo too
|
// TODO: needs to happen on undo/redo too
|
||||||
cx.doc().version += 1;
|
doc.version += 1;
|
||||||
|
|
||||||
// TODO: trigger lsp/documentDidChange with changes
|
// TODO: trigger lsp/documentDidChange with changes
|
||||||
|
|
||||||
// HAXX: we need to reconstruct the state as it was before the changes..
|
// HAXX: we need to reconstruct the state as it was before the changes..
|
||||||
let old_state = cx.doc().old_state.take().expect("no old_state available");
|
let old_state = doc.old_state.take().expect("no old_state available");
|
||||||
|
|
||||||
// TODO: take transaction by value?
|
// TODO: take transaction by value?
|
||||||
cx.doc().history.commit_revision(&transaction, &old_state);
|
doc.history.commit_revision(&transaction, &old_state);
|
||||||
|
|
||||||
// TODO: notify LSP of changes
|
// TODO: notify LSP of changes
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn normal_mode(cx: &mut Context) {
|
pub fn normal_mode(cx: &mut Context) {
|
||||||
cx.doc().mode = Mode::Normal;
|
|
||||||
|
|
||||||
append_changes_to_history(cx);
|
|
||||||
|
|
||||||
let doc = cx.doc();
|
let doc = cx.doc();
|
||||||
|
|
||||||
|
doc.mode = Mode::Normal;
|
||||||
|
|
||||||
|
append_changes_to_history(doc);
|
||||||
|
|
||||||
// if leaving append mode, move cursor back by 1
|
// if leaving append mode, move cursor back by 1
|
||||||
if doc.restore_cursor {
|
if doc.restore_cursor {
|
||||||
let text = doc.text().slice(..);
|
let text = doc.text().slice(..);
|
||||||
|
@ -746,10 +709,11 @@ pub mod insert {
|
||||||
use super::*;
|
use super::*;
|
||||||
// TODO: insert means add text just before cursor, on exit we should be on the last letter.
|
// TODO: insert means add text just before cursor, on exit we should be on the last letter.
|
||||||
pub fn insert_char(cx: &mut Context, c: char) {
|
pub fn insert_char(cx: &mut Context, c: char) {
|
||||||
|
let doc = cx.doc();
|
||||||
let c = Tendril::from_char(c);
|
let c = Tendril::from_char(c);
|
||||||
let transaction = Transaction::insert(&cx.doc().state, c);
|
let transaction = Transaction::insert(&doc.state, c);
|
||||||
|
|
||||||
cx.doc().apply(&transaction);
|
doc.apply(&transaction);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert_tab(cx: &mut Context) {
|
pub fn insert_tab(cx: &mut Context) {
|
||||||
|
@ -884,7 +848,7 @@ pub fn paste(cx: &mut Context) {
|
||||||
};
|
};
|
||||||
|
|
||||||
doc.apply(&transaction);
|
doc.apply(&transaction);
|
||||||
append_changes_to_history(cx);
|
append_changes_to_history(doc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -919,8 +883,8 @@ pub fn indent(cx: &mut Context) {
|
||||||
(pos, pos, Some(indent.clone()))
|
(pos, pos, Some(indent.clone()))
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
cx.doc().apply(&transaction);
|
doc.apply(&transaction);
|
||||||
append_changes_to_history(cx);
|
append_changes_to_history(doc);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unindent(cx: &mut Context) {
|
pub fn unindent(cx: &mut Context) {
|
||||||
|
@ -953,7 +917,7 @@ pub fn unindent(cx: &mut Context) {
|
||||||
let transaction = Transaction::change(&doc.state, changes.into_iter());
|
let transaction = Transaction::change(&doc.state, changes.into_iter());
|
||||||
|
|
||||||
doc.apply(&transaction);
|
doc.apply(&transaction);
|
||||||
append_changes_to_history(cx);
|
append_changes_to_history(doc);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -979,12 +943,11 @@ pub fn completion(cx: &mut Context) {
|
||||||
let pos = helix_lsp::util::pos_to_lsp_pos(doc.text().slice(..), doc.selection().cursor());
|
let pos = helix_lsp::util::pos_to_lsp_pos(doc.text().slice(..), doc.selection().cursor());
|
||||||
|
|
||||||
// TODO: handle fails
|
// TODO: handle fails
|
||||||
let res =
|
let res = smol::block_on(language_server.completion(doc.identifier(), pos)).unwrap_or_default();
|
||||||
smol::block_on(language_server.completion(cx.doc().identifier(), pos)).unwrap_or_default();
|
|
||||||
|
|
||||||
// TODO: if no completion, show some message or something
|
// TODO: if no completion, show some message or something
|
||||||
if !res.is_empty() {
|
if !res.is_empty() {
|
||||||
let snapshot = cx.doc().state.clone();
|
let snapshot = doc.state.clone();
|
||||||
let mut menu = ui::Menu::new(
|
let mut menu = ui::Menu::new(
|
||||||
res,
|
res,
|
||||||
|item| {
|
|item| {
|
||||||
|
@ -1047,7 +1010,7 @@ pub fn completion(cx: &mut Context) {
|
||||||
let transaction =
|
let transaction =
|
||||||
util::generate_transaction_from_edits(&doc.state, vec![edit]);
|
util::generate_transaction_from_edits(&doc.state, vec![edit]);
|
||||||
doc.apply(&transaction);
|
doc.apply(&transaction);
|
||||||
// TODO: append_changes_to_history(cx); if not in insert mode?
|
// TODO: append_changes_to_history(doc); if not in insert mode?
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
};
|
};
|
||||||
|
|
|
@ -436,7 +436,7 @@ impl Component for EditorView {
|
||||||
// mode => write!(stdout, "\x1B[2 q"),
|
// mode => write!(stdout, "\x1B[2 q"),
|
||||||
// };
|
// };
|
||||||
let view = editor.view();
|
let view = editor.view();
|
||||||
let cursor = view.doc.state.selection().cursor();
|
let cursor = view.doc.selection().cursor();
|
||||||
|
|
||||||
let mut pos = view
|
let mut pos = view
|
||||||
.screen_coords_at_pos(view.doc.text().slice(..), cursor)
|
.screen_coords_at_pos(view.doc.text().slice(..), cursor)
|
||||||
|
|
|
@ -54,8 +54,7 @@ impl Editor {
|
||||||
}
|
}
|
||||||
|
|
||||||
let view = View::new(doc)?;
|
let view = View::new(doc)?;
|
||||||
let id = self.tree.insert(view);
|
self.tree.insert(view);
|
||||||
self.tree.get_mut(id).id = id;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -99,6 +99,7 @@ impl Tree {
|
||||||
let mut node = Node::view(view);
|
let mut node = Node::view(view);
|
||||||
node.parent = parent;
|
node.parent = parent;
|
||||||
let node = self.nodes.insert(node);
|
let node = self.nodes.insert(node);
|
||||||
|
self.get_mut(node).id = node;
|
||||||
|
|
||||||
let container = match &mut self.nodes[parent] {
|
let container = match &mut self.nodes[parent] {
|
||||||
Node {
|
Node {
|
||||||
|
|
Loading…
Reference in New Issue