on master help sign in
Make some Document fields read-only.
9132c6aBlaž Hrastnik
helix-core/src/state.rs−4
@@ -198,9 +198,6 @@ impl State {
198 granularity: Granularity,
198 granularity: Granularity,
199 count: usize,
199 count: usize,
200 ) -> Selection {
200 ) -> Selection {
201− // move all selections according to normal cursor move semantics by collapsing it
202− // into cursors and moving them vertically
203−
204 self.selection
201 self.selection
205 .transform(|range| self.move_range(range, dir, granularity, count, false))
202 .transform(|range| self.move_range(range, dir, granularity, count, false))
206 }
203 }
@@ -255,7 +252,6 @@ fn move_vertically(
255 let pos = pos_at_coords(text, Position::new(new_line, new_col));
252 let pos = pos_at_coords(text, Position::new(new_line, new_col));
256
253
257 let mut range = Range::new(if extend { range.anchor } else { pos }, pos);
254 let mut range = Range::new(if extend { range.anchor } else { pos }, pos);
258− use std::convert::TryInto;
259 range.horiz = Some(horiz);
255 range.horiz = Some(horiz);
260 range
256 range
261}
257}
helix-term/src/application.rs+1−1
@@ -137,7 +137,7 @@ impl Application {
137 .tree
137 .tree
138 .views()
138 .views()
139 .map(|(view, _key)| view)
139 .map(|(view, _key)| view)
140− .find(|view| view.doc.path == path);
140+ .find(|view| view.doc.path() == path.as_ref());
141
141
142 if let Some(view) = view {
142 if let Some(view) = view {
143 let doc = view.doc.text().slice(..);
143 let doc = view.doc.text().slice(..);
helix-term/src/commands.rs+6−36
@@ -442,7 +442,7 @@ pub fn delete_selection(cx: &mut Context) {
442 let doc = cx.doc();
442 let doc = cx.doc();
443 _delete_selection(doc);
443 _delete_selection(doc);
444
444
445− append_changes_to_history(doc);
445+ doc.append_changes_to_history();
446}
446}
447
447
448pub fn change_selection(cx: &mut Context) {
448pub fn change_selection(cx: &mut Context) {
@@ -492,7 +492,6 @@ pub fn append_mode(cx: &mut Context) {
492 enter_insert_mode(doc);
492 enter_insert_mode(doc);
493 doc.restore_cursor = true;
493 doc.restore_cursor = true;
494
494
495− // TODO: as transaction
496 let text = doc.text().slice(..);
495 let text = doc.text().slice(..);
497 let selection = doc.selection().transform(|range| {
496 let selection = doc.selection().transform(|range| {
498 // TODO: to() + next char
497 // TODO: to() + next char
@@ -510,7 +509,6 @@ pub fn command_mode(cx: &mut Context) {
510 let prompt = Prompt::new(
509 let prompt = Prompt::new(
511 ":".to_owned(),
510 ":".to_owned(),
512 |_input: &str| {
511 |_input: &str| {
513− // TODO: i need this duplicate list right now to avoid borrow checker issues
514 let command_list = vec![
512 let command_list = vec![
515 "q".to_string(),
513 "q".to_string(),
516 "o".to_string(),
514 "o".to_string(),
@@ -650,40 +648,12 @@ pub fn open_below(cx: &mut Context) {
650
648
651// O inserts a new line before each line with a selection
649// O inserts a new line before each line with a selection
652
650
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−
681pub fn normal_mode(cx: &mut Context) {
651pub fn normal_mode(cx: &mut Context) {
682 let doc = cx.doc();
652 let doc = cx.doc();
683
653
684 doc.mode = Mode::Normal;
654 doc.mode = Mode::Normal;
685
655
686− append_changes_to_history(doc);
656+ doc.append_changes_to_history();
687
657
688 // if leaving append mode, move cursor back by 1
658 // if leaving append mode, move cursor back by 1
689 if doc.restore_cursor {
659 if doc.restore_cursor {
@@ -848,7 +818,7 @@ pub fn paste(cx: &mut Context) {
848 };
818 };
849
819
850 doc.apply(&transaction);
820 doc.apply(&transaction);
851− append_changes_to_history(doc);
821+ doc.append_changes_to_history();
852 }
822 }
853}
823}
854
824
@@ -884,7 +854,7 @@ pub fn indent(cx: &mut Context) {
884 }),
854 }),
885 );
855 );
886 doc.apply(&transaction);
856 doc.apply(&transaction);
887− append_changes_to_history(doc);
857+ doc.append_changes_to_history();
888}
858}
889
859
890pub fn unindent(cx: &mut Context) {
860pub fn unindent(cx: &mut Context) {
@@ -917,7 +887,7 @@ pub fn unindent(cx: &mut Context) {
917 let transaction = Transaction::change(&doc.state, changes.into_iter());
887 let transaction = Transaction::change(&doc.state, changes.into_iter());
918
888
919 doc.apply(&transaction);
889 doc.apply(&transaction);
920− append_changes_to_history(doc);
890+ doc.append_changes_to_history();
921}
891}
922
892
923//
893//
@@ -1010,7 +980,7 @@ pub fn completion(cx: &mut Context) {
1010 let transaction =
980 let transaction =
1011 util::generate_transaction_from_edits(&doc.state, vec![edit]);
981 util::generate_transaction_from_edits(&doc.state, vec![edit]);
1012 doc.apply(&transaction);
982 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?
1014 }
984 }
1015 _ => (),
985 _ => (),
1016 };
986 };
helix-view/src/document.rs+64−25
@@ -17,7 +17,7 @@ pub enum Mode {
17pub struct Document {
17pub struct Document {
18 pub state: State, // rope + selection
18 pub state: State, // rope + selection
19 /// File path on disk.
19 /// File path on disk.
20− pub path: Option<PathBuf>,
20+ path: Option<PathBuf>,
21
21
22 /// Current editing mode.
22 /// Current editing mode.
23 pub mode: Mode,
23 pub mode: Mode,
@@ -26,13 +26,16 @@ pub struct Document {
26 /// Tree-sitter AST tree
26 /// Tree-sitter AST tree
27 pub syntax: Option<Syntax>,
27 pub syntax: Option<Syntax>,
28 /// Corresponding language scope name. Usually `source.<lang>`.
28 /// Corresponding language scope name. Usually `source.<lang>`.
29− pub language: Option<String>,
29+ language: Option<String>,
30
30
31 /// Pending changes since last history commit.
31 /// Pending changes since last history commit.
32− pub changes: ChangeSet,
32+ changes: ChangeSet,
33+ /// State at last commit. Used for calculating reverts.
33− pub old_state: Option<State>,
34+ old_state: Option<State>,
35+ /// Undo tree.
34− pub history: History,
36+ history: History,
37+ /// Current document version, incremented at each change.
35− pub version: i32, // should be usize?
38+ version: i32, // should be usize?
36
39
37 pub diagnostics: Vec<Diagnostic>,
40 pub diagnostics: Vec<Diagnostic>,
38 pub language_server: Option<Arc<helix_lsp::Client>>,
41 pub language_server: Option<Arc<helix_lsp::Client>>,
@@ -90,23 +93,8 @@ impl Document {
90
93
91 let mut doc = Self::new(State::new(doc));
94 let mut doc = Self::new(State::new(doc));
92
95
93− if let Some(language_config) = LOADER.language_config_for_file_name(path.as_path()) {
96+ let language_config = LOADER.language_config_for_file_name(path.as_path());
94− let highlight_config = language_config.highlight_config(scopes).unwrap().unwrap();
97+ doc.set_language(language_config, scopes);
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− };
110
98
111 // canonicalize path to absolute value
99 // canonicalize path to absolute value
112 doc.path = Some(std::fs::canonicalize(path)?);
100 doc.path = Some(std::fs::canonicalize(path)?);
@@ -140,17 +128,35 @@ impl Document {
140 } // and_then notify save
128 } // and_then notify save
141 }
129 }
142
130
143− pub fn set_language(&mut self, scope: &str, scopes: &[String]) {
131+ pub fn set_language(
132+ &mut self,
133+ language_config: Option<Arc<helix_core::syntax::LanguageConfiguration>>,
134+ scopes: &[String],
135+ ) {
144− if let Some(language_config) = LOADER.language_config_for_scope(scope) {
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+
145 let highlight_config = language_config.highlight_config(scopes).unwrap().unwrap();
143 let highlight_config = language_config.highlight_config(scopes).unwrap().unwrap();
146 // TODO: config.configure(scopes) is now delayed, is that ok?
144 // TODO: config.configure(scopes) is now delayed, is that ok?
147
145
148 let syntax = Syntax::new(&self.state.doc, highlight_config.clone());
146 let syntax = Syntax::new(&self.state.doc, highlight_config.clone());
149
147
150 self.syntax = Some(syntax);
148 self.syntax = Some(syntax);
149+ } else {
150+ self.syntax = None;
151+ self.language = None;
151 };
152 };
152 }
153 }
153
154
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+
154 pub fn set_language_server(&mut self, language_server: Option<Arc<helix_lsp::Client>>) {
160 pub fn set_language_server(&mut self, language_server: Option<Arc<helix_lsp::Client>>) {
155 self.language_server = language_server;
161 self.language_server = language_server;
156 }
162 }
@@ -238,11 +244,44 @@ impl Document {
238 false
244 false
239 }
245 }
240
246
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+
241 #[inline]
269 #[inline]
242 pub fn mode(&self) -> Mode {
270 pub fn mode(&self) -> Mode {
243 self.mode
271 self.mode
244 }
272 }
245
273
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+
246 #[inline]
285 #[inline]
247 pub fn path(&self) -> Option<&PathBuf> {
286 pub fn path(&self) -> Option<&PathBuf> {
248 self.path.as_ref()
287 self.path.as_ref()
helix-view/src/editor.rs+3−4
@@ -37,9 +37,8 @@ impl Editor {
37
37
38 // try to find a language server based on the language name
38 // try to find a language server based on the language name
39 let language_server = doc
39 let language_server = doc
40− .language
40+ .language()
41− .as_ref()
42− .and_then(|language| self.language_servers.get(&language, &executor));
41+ .and_then(|language| self.language_servers.get(language, &executor));
43
42
44 if let Some(language_server) = language_server {
43 if let Some(language_server) = language_server {
45 // TODO: do this everywhere
44 // TODO: do this everywhere
@@ -47,7 +46,7 @@ impl Editor {
47
46
48 smol::block_on(language_server.text_document_did_open(
47 smol::block_on(language_server.text_document_did_open(
49 doc.url().unwrap(),
48 doc.url().unwrap(),
50− doc.version,
49+ doc.version(),
51 doc.text(),
50 doc.text(),
52 ))
51 ))
53 .unwrap();
52 .unwrap();