Use proper NodeRuntime in the formatter interface

Kirill Bulatov created

Change summary

Cargo.lock                                        |  2 +
crates/prettier/Cargo.toml                        |  1 
crates/prettier/prettier_server/.gitignore        |  1 
crates/prettier/prettier_server/package-lock.json | 29 +++++++++++++++++
crates/prettier/prettier_server/package.json      | 21 +++++++-----
crates/prettier/prettier_server/src/index.js      |  1 
crates/prettier/src/prettier.rs                   |  9 ++--
crates/project/Cargo.toml                         |  1 
crates/project/src/project.rs                     | 24 +++++++++++--
crates/zed/src/main.rs                            |  2 
10 files changed, 71 insertions(+), 20 deletions(-)

Detailed changes

Cargo.lock 🔗

@@ -5526,6 +5526,7 @@ dependencies = [
  "futures 0.3.28",
  "gpui",
  "language",
+ "node_runtime",
  "serde",
  "serde_derive",
  "serde_json",
@@ -5643,6 +5644,7 @@ dependencies = [
  "lazy_static",
  "log",
  "lsp",
+ "node_runtime",
  "parking_lot 0.11.2",
  "postage",
  "prettier",

crates/prettier/Cargo.toml 🔗

@@ -10,6 +10,7 @@ path = "src/prettier.rs"
 language = { path = "../language" }
 gpui = { path = "../gpui" }
 fs = { path = "../fs" }
+node_runtime = { path = "../node_runtime"}
 
 serde.workspace = true
 serde_derive.workspace = true

crates/prettier/prettier_server/package-lock.json 🔗

@@ -0,0 +1,29 @@
+{
+  "name": "prettier_server",
+  "version": "1.0.0",
+  "lockfileVersion": 3,
+  "requires": true,
+  "packages": {
+    "": {
+      "name": "prettier_server",
+      "version": "1.0.0",
+      "dependencies": {
+        "prettier": "^3.0.3"
+      }
+    },
+    "node_modules/prettier": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.3.tgz",
+      "integrity": "sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==",
+      "bin": {
+        "prettier": "bin/prettier.cjs"
+      },
+      "engines": {
+        "node": ">=14"
+      },
+      "funding": {
+        "url": "https://github.com/prettier/prettier?sponsor=1"
+      }
+    }
+  }
+}

crates/prettier/prettier_server/package.json 🔗

@@ -1,11 +1,14 @@
 {
-  "name": "prettier_server",
-  "version": "1.0.0",
-  "description": "",
-  "main": "src/index.js",
-  "scripts": {
-    "start": "node src/index.js",
-    "test": "echo \"Error: no test specified\" && exit 1"
-  },
-  "author": "Zed Industries"
+    "name": "prettier_server",
+    "version": "1.0.0",
+    "description": "",
+    "main": "src/index.js",
+    "scripts": {
+        "start": "node src/index.js",
+        "test": "echo \"Error: no test specified\" && exit 1"
+    },
+    "author": "Zed Industries",
+    "dependencies": {
+        "prettier": "^3.0"
+    }
 }

crates/prettier/src/prettier.rs 🔗

@@ -1,18 +1,17 @@
 use std::collections::{HashMap, VecDeque};
-pub use std::path::{Path, PathBuf};
-pub use std::sync::Arc;
+use std::path::{Path, PathBuf};
+use std::sync::Arc;
 
 use anyhow::Context;
 use fs::Fs;
 use gpui::ModelHandle;
 use language::{Buffer, Diff};
+use node_runtime::NodeRuntime;
 
 pub struct Prettier {
     _private: (),
 }
 
-pub struct NodeRuntime;
-
 #[derive(Debug)]
 pub struct LocateStart {
     pub worktree_root_path: Arc<Path>,
@@ -143,7 +142,7 @@ impl Prettier {
         }
     }
 
-    pub async fn start(prettier_path: &Path, node: Arc<NodeRuntime>) -> anyhow::Result<Self> {
+    pub async fn start(prettier_path: &Path, node: Arc<dyn NodeRuntime>) -> anyhow::Result<Self> {
         todo!()
     }
 

crates/project/Cargo.toml 🔗

@@ -31,6 +31,7 @@ git = { path = "../git" }
 gpui = { path = "../gpui" }
 language = { path = "../language" }
 lsp = { path = "../lsp" }
+node_runtime = { path = "../node_runtime" }
 prettier = { path = "../prettier" }
 rpc = { path = "../rpc" }
 settings = { path = "../settings" }

crates/project/src/project.rs 🔗

@@ -49,8 +49,9 @@ use lsp::{
     DocumentHighlightKind, LanguageServer, LanguageServerBinary, LanguageServerId, OneOf,
 };
 use lsp_command::*;
+use node_runtime::NodeRuntime;
 use postage::watch;
-use prettier::{LocateStart, NodeRuntime, Prettier};
+use prettier::{LocateStart, Prettier};
 use project_settings::{LspSettings, ProjectSettings};
 use rand::prelude::*;
 use search::SearchQuery;
@@ -71,7 +72,7 @@ use std::{
     str,
     sync::{
         atomic::{AtomicUsize, Ordering::SeqCst},
-        Arc,
+        Arc, OnceLock,
     },
     time::{Duration, Instant},
 };
@@ -553,14 +554,27 @@ impl SearchMatchCandidate {
     }
 }
 
+static NODE_RUNTIME: OnceLock<Arc<dyn NodeRuntime>> = OnceLock::new();
+
 impl Project {
     pub fn init_settings(cx: &mut AppContext) {
         settings::register::<ProjectSettings>(cx);
     }
 
-    pub fn init(client: &Arc<Client>, cx: &mut AppContext) {
+    pub fn init(
+        client: &Arc<Client>,
+        node_runtime: Option<Arc<dyn NodeRuntime>>,
+        cx: &mut AppContext,
+    ) {
         Self::init_settings(cx);
 
+        // TODO kb move it to Project::local and other constructors?
+        if let Some(node_runtime) = node_runtime {
+            NODE_RUNTIME
+                .set(node_runtime)
+                .unwrap_or_else(|_| panic!("multiple init calls tried to set node runtime"));
+        }
+
         client.add_model_message_handler(Self::handle_add_collaborator);
         client.add_model_message_handler(Self::handle_update_project_collaborator);
         client.add_model_message_handler(Self::handle_remove_collaborator);
@@ -8187,6 +8201,7 @@ impl Project {
         buffer: &ModelHandle<Buffer>,
         cx: &mut ModelContext<Self>,
     ) -> Option<Task<Shared<Task<Result<Arc<Prettier>, Arc<anyhow::Error>>>>>> {
+        let node_runtime = Arc::clone(NODE_RUNTIME.get()?);
         let buffer_file = File::from_dyn(buffer.read(cx).file());
         let buffer_path = buffer_file.map(|file| Arc::clone(file.path()));
         let worktree_path = buffer_file
@@ -8253,13 +8268,12 @@ impl Project {
                 return existing_prettier;
             }
 
-            let task_node_runtime = Arc::new(NodeRuntime);
             let task_prettier_path = prettier_path.clone();
             let new_prettier_task = cx
                 .background()
                 .spawn(async move {
                     Ok(Arc::new(
-                        Prettier::start(&task_prettier_path, task_node_runtime)
+                        Prettier::start(&task_prettier_path, node_runtime)
                             .await
                             .with_context(|| {
                                 format!("starting new prettier for path {task_prettier_path:?}")

crates/zed/src/main.rs 🔗

@@ -138,7 +138,7 @@ fn main() {
 
         theme::init(Assets, cx);
         context_menu::init(cx);
-        project::Project::init(&client, cx);
+        project::Project::init(&client, Some(Arc::clone(&node_runtime)), cx);
         client::init(&client, cx);
         command_palette::init(cx);
         language::init(cx);