Merge pull request #158 from zed-industries/highlight-new-files

Nathan Sobo created

Set the language on new buffers when they are saved

Change summary

gpui/Cargo.toml          |  3 +++
gpui/src/elements/svg.rs |  5 +++--
zed/Cargo.toml           |  3 ++-
zed/src/editor.rs        |  5 +++++
zed/src/editor/buffer.rs | 17 ++++++++++++++++-
zed/src/workspace.rs     | 10 ++++++----
zed/src/worktree.rs      |  7 +++++++
7 files changed, 42 insertions(+), 8 deletions(-)

Detailed changes

gpui/Cargo.toml 🔗

@@ -4,6 +4,9 @@ edition = "2018"
 name = "gpui"
 version = "0.1.0"
 
+[features]
+test-support = []
+
 [dependencies]
 arrayvec = "0.7.1"
 async-task = "4.0.3"

gpui/src/elements/svg.rs 🔗

@@ -47,8 +47,9 @@ impl Element for Svg {
                 );
                 (size, Some(tree))
             }
-            Err(error) => {
-                log::error!("{}", error);
+            Err(_error) => {
+                #[cfg(not(any(test, feature = "test-support")))]
+                log::error!("{}", _error);
                 (constraint.min, None)
             }
         }

zed/Cargo.toml 🔗

@@ -14,7 +14,7 @@ name = "Zed"
 path = "src/main.rs"
 
 [features]
-test-support = ["tempdir", "zrpc/test-support"]
+test-support = ["tempdir", "zrpc/test-support", "gpui/test-support"]
 
 [dependencies]
 anyhow = "1.0.38"
@@ -69,6 +69,7 @@ serde_json = { version = "1.0.64", features = ["preserve_order"] }
 tempdir = { version = "0.3.7" }
 unindent = "0.1.7"
 zrpc = { path = "../zrpc", features = ["test-support"] }
+gpui = { path = "../gpui", features = ["test-support"] }
 
 [package.metadata.bundle]
 icon = ["app-icon@2x.png", "app-icon.png"]

zed/src/editor.rs 🔗

@@ -4,6 +4,7 @@ mod element;
 pub mod movement;
 
 use crate::{
+    language::Language,
     settings::Settings,
     theme::Theme,
     time::ReplicaId,
@@ -449,6 +450,10 @@ impl Editor {
         }
     }
 
+    pub fn language<'a>(&self, cx: &'a AppContext) -> Option<&'a Arc<Language>> {
+        self.buffer.read(cx).language()
+    }
+
     pub fn set_placeholder_text(
         &mut self,
         placeholder_text: impl Into<Arc<str>>,

zed/src/editor/buffer.rs 🔗

@@ -714,9 +714,16 @@ impl Buffer {
         path: impl Into<Arc<Path>>,
         cx: &mut ModelContext<Self>,
     ) -> Task<Result<()>> {
+        let path = path.into();
         let handle = cx.handle();
         let text = self.visible_text.clone();
         let version = self.version.clone();
+
+        if let Some(language) = worktree.read(cx).languages().select_language(&path).cloned() {
+            self.language = Some(language);
+            self.reparse(cx);    
+        }
+
         let save_as = worktree.update(cx, |worktree, cx| {
             worktree
                 .as_local_mut()
@@ -794,6 +801,10 @@ impl Buffer {
         cx.emit(Event::FileHandleChanged);
     }
 
+    pub fn language(&self) -> Option<&Arc<Language>> {
+        self.language.as_ref()
+    }
+
     pub fn parse_count(&self) -> usize {
         self.parse_count
     }
@@ -871,7 +882,11 @@ impl Buffer {
                     cx.spawn(move |this, mut cx| async move {
                         let new_tree = parse_task.await;
                         this.update(&mut cx, move |this, cx| {
-                            let parse_again = this.version > parsed_version;
+                            let language_changed =
+                                this.language.as_ref().map_or(true, |curr_language| {
+                                    !Arc::ptr_eq(curr_language, &language)
+                                });
+                            let parse_again = this.version > parsed_version || language_changed;
                             *this.syntax_tree.lock() = Some(SyntaxTree {
                                 tree: new_tree,
                                 dirty: false,

zed/src/workspace.rs 🔗

@@ -1476,7 +1476,7 @@ mod tests {
         });
         cx.simulate_new_path_selection(|parent_dir| {
             assert_eq!(parent_dir, dir.path());
-            Some(parent_dir.join("the-new-name"))
+            Some(parent_dir.join("the-new-name.rs"))
         });
         cx.read(|cx| {
             assert!(editor.is_dirty(cx));
@@ -1489,8 +1489,10 @@ mod tests {
             .await;
         cx.read(|cx| {
             assert!(!editor.is_dirty(cx));
-            assert_eq!(editor.title(cx), "the-new-name");
+            assert_eq!(editor.title(cx), "the-new-name.rs");
         });
+        // The language is assigned based on the path
+        editor.read_with(&cx, |editor, cx| assert!(editor.language(cx).is_some()));
 
         // Edit the file and save it again. This time, there is no filename prompt.
         editor.update(&mut cx, |editor, cx| {
@@ -1504,7 +1506,7 @@ mod tests {
         editor
             .condition(&cx, |editor, cx| !editor.is_dirty(cx))
             .await;
-        cx.read(|cx| assert_eq!(editor.title(cx), "the-new-name"));
+        cx.read(|cx| assert_eq!(editor.title(cx), "the-new-name.rs"));
 
         // Open the same newly-created file in another pane item. The new editor should reuse
         // the same buffer.
@@ -1512,7 +1514,7 @@ mod tests {
             workspace.open_new_file(&OpenNew(app_state.clone()), cx);
             workspace.split_pane(workspace.active_pane().clone(), SplitDirection::Right, cx);
             assert!(workspace
-                .open_entry((tree.id(), Path::new("the-new-name").into()), cx)
+                .open_entry((tree.id(), Path::new("the-new-name.rs").into()), cx)
                 .is_none());
         });
         let editor2 = workspace.update(&mut cx, |workspace, cx| {

zed/src/worktree.rs 🔗

@@ -268,6 +268,13 @@ impl Worktree {
         }
     }
 
+    pub fn languages(&self) -> &Arc<LanguageRegistry> {
+        match self {
+            Worktree::Local(worktree) => &worktree.languages,
+            Worktree::Remote(worktree) => &worktree.languages,
+        }
+    }
+
     pub fn snapshot(&self) -> Snapshot {
         match self {
             Worktree::Local(worktree) => worktree.snapshot(),