on master help sign in
Make some Document fields read-only.
commit9132c6a591fc4515cdddfd16cc382fc3368ed27c authorBlaž Hrastnik <blaz@mxxn.io> dateSun 21 Feb 2021, 19:47 (6 years ago) parent7da6bd6
5 files changed+74−70
helix-core/src/state.rs−4 helix-term/src/application.rs+1−1 helix-term/src/commands.rs+6−36 helix-view/src/document.rs+64−25 helix-view/src/editor.rs+3−4
helix-core/src/state.rs−4
@@ -198,9 +198,6 @@ impl State {
198198 granularity: Granularity,
199199 count: usize,
200200 ) -> Selection {
201− // move all selections according to normal cursor move semantics by collapsing it
202− // into cursors and moving them vertically
203−
204201 self.selection
205202 .transform(|range| self.move_range(range, dir, granularity, count, false))
206203 }
@@ -255,7 +252,6 @@ fn move_vertically(
255252 let pos = pos_at_coords(text, Position::new(new_line, new_col));
256253
257254 let mut range = Range::new(if extend { range.anchor } else { pos }, pos);
258− use std::convert::TryInto;
259255 range.horiz = Some(horiz);
260256 range
261257}
helix-term/src/application.rs+1−1
@@ -137,7 +137,7 @@ impl Application {
137137 .tree
138138 .views()
139139 .map(|(view, _key)| view)
140− .find(|view| view.doc.path == path);
140+ .find(|view| view.doc.path() == path.as_ref());
141141
142142 if let Some(view) = view {
143143 let doc = view.doc.text().slice(..);
helix-term/src/commands.rs+6−36
@@ -442,7 +442,7 @@ pub fn delete_selection(cx: &mut Context) {
442442 let doc = cx.doc();
443443 _delete_selection(doc);
444444
445− append_changes_to_history(doc);
445+ doc.append_changes_to_history();
446446}
447447
448448pub fn change_selection(cx: &mut Context) {
@@ -492,7 +492,6 @@ pub fn append_mode(cx: &mut Context) {
492492 enter_insert_mode(doc);
493493 doc.restore_cursor = true;
494494
495− // TODO: as transaction
496495 let text = doc.text().slice(..);
497496 let selection = doc.selection().transform(|range| {
498497 // TODO: to() + next char
@@ -510,7 +509,6 @@ pub fn command_mode(cx: &mut Context) {
510509 let prompt = Prompt::new(
511510 ":".to_owned(),
512511 |_input: &str| {
513− // TODO: i need this duplicate list right now to avoid borrow checker issues
514512 let command_list = vec![
515513 "q".to_string(),
516514 "o".to_string(),
@@ -650,40 +648,12 @@ pub fn open_below(cx: &mut Context) {
650648
651649// O inserts a new line before each line with a selection
652650
653−fn append_changes_to_history(doc: &mut Document) {
654− if doc.changes.is_empty() {
655− return;
656− }
657−
658− // TODO: change -> change -> undo -> change -> change fails, probably old_state needs reset
659−
660− let new_changeset = ChangeSet::new(doc.text());
661− let changes = std::mem::replace(&mut doc.changes, new_changeset);
662− // Instead of doing this messy merge we could always commit, and based on transaction
663− // annotations either add a new layer or compose into the previous one.
664− let transaction = Transaction::from(changes).with_selection(doc.selection().clone());
665−
666− // increment document version
667− // TODO: needs to happen on undo/redo too
668− doc.version += 1;
669−
670− // TODO: trigger lsp/documentDidChange with changes
671−
672− // HAXX: we need to reconstruct the state as it was before the changes..
673− let old_state = doc.old_state.take().expect("no old_state available");
674−
675− // TODO: take transaction by value?
676− doc.history.commit_revision(&transaction, &old_state);
677−
678− // TODO: notify LSP of changes
679−}
680−
681651pub fn normal_mode(cx: &mut Context) {
682652 let doc = cx.doc();
683653
684654 doc.mode = Mode::Normal;
685655
686− append_changes_to_history(doc);
656+ doc.append_changes_to_history();
687657
688658 // if leaving append mode, move cursor back by 1
689659 if doc.restore_cursor {
@@ -848,7 +818,7 @@ pub fn paste(cx: &mut Context) {
848818 };
849819
850820 doc.apply(&transaction);
851− append_changes_to_history(doc);
821+ doc.append_changes_to_history();
852822 }
853823}
854824
@@ -884,7 +854,7 @@ pub fn indent(cx: &mut Context) {
884854 }),
885855 );
886856 doc.apply(&transaction);
887− append_changes_to_history(doc);
857+ doc.append_changes_to_history();
888858}
889859
890860pub fn unindent(cx: &mut Context) {
@@ -917,7 +887,7 @@ pub fn unindent(cx: &mut Context) {
917887 let transaction = Transaction::change(&doc.state, changes.into_iter());
918888
919889 doc.apply(&transaction);
920− append_changes_to_history(doc);
890+ doc.append_changes_to_history();
921891}
922892
923893//
@@ -1010,7 +980,7 @@ pub fn completion(cx: &mut Context) {
1010980 let transaction =
1011981 util::generate_transaction_from_edits(&doc.state, vec![edit]);
1012982 doc.apply(&transaction);
1013− // TODO: append_changes_to_history(doc); if not in insert mode?
983+ // TODO: doc.append_changes_to_history(); if not in insert mode?
1014984 }
1015985 _ => (),
1016986 };
helix-view/src/document.rs+64−25
@@ -17,7 +17,7 @@ pub enum Mode {
1717pub struct Document {
1818 pub state: State, // rope + selection
1919 /// File path on disk.
20− pub path: Option<PathBuf>,
20+ path: Option<PathBuf>,
2121
2222 /// Current editing mode.
2323 pub mode: Mode,
@@ -26,13 +26,16 @@ pub struct Document {
2626 /// Tree-sitter AST tree
2727 pub syntax: Option<Syntax>,
2828 /// Corresponding language scope name. Usually `source.<lang>`.
29− pub language: Option<String>,
29+ language: Option<String>,
3030
3131 /// Pending changes since last history commit.
32− pub changes: ChangeSet,
33− pub old_state: Option<State>,
34− pub history: History,
35− pub version: i32, // should be usize?
32+ changes: ChangeSet,
33+ /// State at last commit. Used for calculating reverts.
34+ old_state: Option<State>,
35+ /// Undo tree.
36+ history: History,
37+ /// Current document version, incremented at each change.
38+ version: i32, // should be usize?
3639
3740 pub diagnostics: Vec<Diagnostic>,
3841 pub language_server: Option<Arc<helix_lsp::Client>>,
@@ -90,23 +93,8 @@ impl Document {
9093
9194 let mut doc = Self::new(State::new(doc));
9295
93− if let Some(language_config) = LOADER.language_config_for_file_name(path.as_path()) {
94− let highlight_config = language_config.highlight_config(scopes).unwrap().unwrap();
95− // TODO: config.configure(scopes) is now delayed, is that ok?
96−
97− let syntax = Syntax::new(&doc.state.doc, highlight_config.clone());
98−
99− doc.syntax = Some(syntax);
100− // TODO: maybe just keep an Arc<> pointer to the language_config?
101− doc.language = Some(language_config.scope().to_string());
102−
103− // TODO: this ties lsp support to tree-sitter enabled languages for now. Language
104− // config should use Option<HighlightConfig> to let us have non-tree-sitter configs.
105−
106− // TODO: circular dep: view <-> lsp
107− // helix_lsp::REGISTRY;
108− // view should probably depend on lsp
109− };
96+ let language_config = LOADER.language_config_for_file_name(path.as_path());
97+ doc.set_language(language_config, scopes);
11098
11199 // canonicalize path to absolute value
112100 doc.path = Some(std::fs::canonicalize(path)?);
@@ -140,17 +128,35 @@ impl Document {
140128 } // and_then notify save
141129 }
142130
143− pub fn set_language(&mut self, scope: &str, scopes: &[String]) {
144− if let Some(language_config) = LOADER.language_config_for_scope(scope) {
131+ pub fn set_language(
132+ &mut self,
133+ language_config: Option<Arc<helix_core::syntax::LanguageConfiguration>>,
134+ scopes: &[String],
135+ ) {
136+ if let Some(language_config) = language_config {
137+ // TODO: maybe just keep an Arc<> pointer to the language_config?
138+ self.language = Some(language_config.scope().to_string());
139+
140+ // TODO: this ties lsp support to tree-sitter enabled languages for now. Language
141+ // config should use Option<HighlightConfig> to let us have non-tree-sitter configs.
142+
145143 let highlight_config = language_config.highlight_config(scopes).unwrap().unwrap();
146144 // TODO: config.configure(scopes) is now delayed, is that ok?
147145
148146 let syntax = Syntax::new(&self.state.doc, highlight_config.clone());
149147
150148 self.syntax = Some(syntax);
149+ } else {
150+ self.syntax = None;
151+ self.language = None;
151152 };
152153 }
153154
155+ pub fn set_language2(&mut self, scope: &str, scopes: &[String]) {
156+ let language_config = LOADER.language_config_for_scope(scope);
157+ self.set_language(language_config, scopes);
158+ }
159+
154160 pub fn set_language_server(&mut self, language_server: Option<Arc<helix_lsp::Client>>) {
155161 self.language_server = language_server;
156162 }
@@ -238,11 +244,44 @@ impl Document {
238244 false
239245 }
240246
247+ pub fn append_changes_to_history(&mut self) {
248+ if self.changes.is_empty() {
249+ return;
250+ }
251+
252+ // TODO: change -> change -> undo -> change -> change fails, probably old_state needs reset
253+
254+ let new_changeset = ChangeSet::new(self.text());
255+ let changes = std::mem::replace(&mut self.changes, new_changeset);
256+ // Instead of doing this messy merge we could always commit, and based on transaction
257+ // annotations either add a new layer or compose into the previous one.
258+ let transaction = Transaction::from(changes).with_selection(self.selection().clone());
259+
260+ // increment document version
261+ self.version += 1;
262+
263+ // HAXX: we need to reconstruct the state as it was before the changes..
264+ let old_state = self.old_state.take().expect("no old_state available");
265+
266+ self.history.commit_revision(&transaction, &old_state);
267+ }
268+
241269 #[inline]
242270 pub fn mode(&self) -> Mode {
243271 self.mode
244272 }
245273
274+ #[inline]
275+ /// Corresponding language scope name. Usually `source.<lang>`.
276+ pub fn language(&self) -> Option<&str> {
277+ self.language.as_ref().map(String::as_str)
278+ }
279+
280+ #[inline]
281+ pub fn version(&self) -> i32 {
282+ self.version
283+ }
284+
246285 #[inline]
247286 pub fn path(&self) -> Option<&PathBuf> {
248287 self.path.as_ref()
helix-view/src/editor.rs+3−4
@@ -37,9 +37,8 @@ impl Editor {
3737
3838 // try to find a language server based on the language name
3939 let language_server = doc
40− .language
41− .as_ref()
42− .and_then(|language| self.language_servers.get(&language, &executor));
40+ .language()
41+ .and_then(|language| self.language_servers.get(language, &executor));
4342
4443 if let Some(language_server) = language_server {
4544 // TODO: do this everywhere
@@ -47,7 +46,7 @@ impl Editor {
4746
4847 smol::block_on(language_server.text_document_did_open(
4948 doc.url().unwrap(),
50− doc.version,
49+ doc.version(),
5150 doc.text(),
5251 ))
5352 .unwrap();