Refactor prettier (#17977)
In preparation for making formatting work on ssh remotes Release Notes: - N/A Co-authored-by: Mikayla <mikayla@zed.dev>
This commit is contained in:
parent
db18f7a2b0
commit
8e45bf71ca
6 changed files with 911 additions and 705 deletions
|
@ -462,3 +462,52 @@ impl NodeRuntime for FakeNodeRuntime {
|
||||||
unreachable!("Should not install packages {packages:?}")
|
unreachable!("Should not install packages {packages:?}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Remove this when headless binary can run node
|
||||||
|
pub struct DummyNodeRuntime;
|
||||||
|
|
||||||
|
impl DummyNodeRuntime {
|
||||||
|
pub fn new() -> Arc<dyn NodeRuntime> {
|
||||||
|
Arc::new(Self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl NodeRuntime for DummyNodeRuntime {
|
||||||
|
async fn binary_path(&self) -> anyhow::Result<PathBuf> {
|
||||||
|
anyhow::bail!("Dummy Node Runtime")
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn node_environment_path(&self) -> anyhow::Result<OsString> {
|
||||||
|
anyhow::bail!("Dummy node runtime")
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn run_npm_subcommand(
|
||||||
|
&self,
|
||||||
|
_: Option<&Path>,
|
||||||
|
_subcommand: &str,
|
||||||
|
_args: &[&str],
|
||||||
|
) -> anyhow::Result<Output> {
|
||||||
|
anyhow::bail!("Dummy node runtime")
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn npm_package_latest_version(&self, _name: &str) -> anyhow::Result<String> {
|
||||||
|
anyhow::bail!("Dummy node runtime")
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn npm_package_installed_version(
|
||||||
|
&self,
|
||||||
|
_local_package_directory: &Path,
|
||||||
|
_name: &str,
|
||||||
|
) -> Result<Option<String>> {
|
||||||
|
anyhow::bail!("Dummy node runtime")
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn npm_install_packages(
|
||||||
|
&self,
|
||||||
|
_: &Path,
|
||||||
|
_packages: &[(&str, &str)],
|
||||||
|
) -> anyhow::Result<()> {
|
||||||
|
anyhow::bail!("Dummy node runtime")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ use crate::{
|
||||||
environment::ProjectEnvironment,
|
environment::ProjectEnvironment,
|
||||||
lsp_command::{self, *},
|
lsp_command::{self, *},
|
||||||
lsp_ext_command,
|
lsp_ext_command,
|
||||||
|
prettier_store::{self, PrettierStore, PrettierStoreEvent},
|
||||||
project_settings::{LspSettings, ProjectSettings},
|
project_settings::{LspSettings, ProjectSettings},
|
||||||
relativize_path, resolve_path,
|
relativize_path, resolve_path,
|
||||||
worktree_store::{WorktreeStore, WorktreeStoreEvent},
|
worktree_store::{WorktreeStore, WorktreeStoreEvent},
|
||||||
|
@ -101,6 +102,8 @@ pub struct LocalLspStore {
|
||||||
HashMap<LanguageServerId, HashMap<String, Vec<FileSystemWatcher>>>,
|
HashMap<LanguageServerId, HashMap<String, Vec<FileSystemWatcher>>>,
|
||||||
supplementary_language_servers:
|
supplementary_language_servers:
|
||||||
HashMap<LanguageServerId, (LanguageServerName, Arc<LanguageServer>)>,
|
HashMap<LanguageServerId, (LanguageServerName, Arc<LanguageServer>)>,
|
||||||
|
prettier_store: Model<PrettierStore>,
|
||||||
|
current_lsp_settings: HashMap<Arc<str>, LspSettings>,
|
||||||
_subscription: gpui::Subscription,
|
_subscription: gpui::Subscription,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,6 +138,7 @@ impl RemoteLspStore {}
|
||||||
|
|
||||||
pub struct SshLspStore {
|
pub struct SshLspStore {
|
||||||
upstream_client: AnyProtoClient,
|
upstream_client: AnyProtoClient,
|
||||||
|
current_lsp_settings: HashMap<Arc<str>, LspSettings>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::large_enum_variant)]
|
#[allow(clippy::large_enum_variant)]
|
||||||
|
@ -310,9 +314,32 @@ impl LspStore {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn swap_current_lsp_settings(
|
||||||
|
&mut self,
|
||||||
|
new_settings: HashMap<Arc<str>, LspSettings>,
|
||||||
|
) -> Option<HashMap<Arc<str>, LspSettings>> {
|
||||||
|
match &mut self.mode {
|
||||||
|
LspStoreMode::Ssh(SshLspStore {
|
||||||
|
current_lsp_settings,
|
||||||
|
..
|
||||||
|
})
|
||||||
|
| LspStoreMode::Local(LocalLspStore {
|
||||||
|
current_lsp_settings,
|
||||||
|
..
|
||||||
|
}) => {
|
||||||
|
let ret = mem::take(current_lsp_settings);
|
||||||
|
*current_lsp_settings = new_settings;
|
||||||
|
Some(ret)
|
||||||
|
}
|
||||||
|
LspStoreMode::Remote(_) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn new_local(
|
pub fn new_local(
|
||||||
buffer_store: Model<BufferStore>,
|
buffer_store: Model<BufferStore>,
|
||||||
worktree_store: Model<WorktreeStore>,
|
worktree_store: Model<WorktreeStore>,
|
||||||
|
prettier_store: Model<PrettierStore>,
|
||||||
environment: Model<ProjectEnvironment>,
|
environment: Model<ProjectEnvironment>,
|
||||||
languages: Arc<LanguageRegistry>,
|
languages: Arc<LanguageRegistry>,
|
||||||
http_client: Option<Arc<dyn HttpClient>>,
|
http_client: Option<Arc<dyn HttpClient>>,
|
||||||
|
@ -324,6 +351,10 @@ impl LspStore {
|
||||||
.detach();
|
.detach();
|
||||||
cx.subscribe(&worktree_store, Self::on_worktree_store_event)
|
cx.subscribe(&worktree_store, Self::on_worktree_store_event)
|
||||||
.detach();
|
.detach();
|
||||||
|
cx.subscribe(&prettier_store, Self::on_prettier_store_event)
|
||||||
|
.detach();
|
||||||
|
cx.observe_global::<SettingsStore>(Self::on_settings_changed)
|
||||||
|
.detach();
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
mode: LspStoreMode::Local(LocalLspStore {
|
mode: LspStoreMode::Local(LocalLspStore {
|
||||||
|
@ -332,6 +363,8 @@ impl LspStore {
|
||||||
last_workspace_edits_by_language_server: Default::default(),
|
last_workspace_edits_by_language_server: Default::default(),
|
||||||
language_server_watched_paths: Default::default(),
|
language_server_watched_paths: Default::default(),
|
||||||
language_server_watcher_registrations: Default::default(),
|
language_server_watcher_registrations: Default::default(),
|
||||||
|
current_lsp_settings: ProjectSettings::get_global(cx).lsp.clone(),
|
||||||
|
prettier_store,
|
||||||
environment,
|
environment,
|
||||||
http_client,
|
http_client,
|
||||||
fs,
|
fs,
|
||||||
|
@ -387,9 +420,14 @@ impl LspStore {
|
||||||
.detach();
|
.detach();
|
||||||
cx.subscribe(&worktree_store, Self::on_worktree_store_event)
|
cx.subscribe(&worktree_store, Self::on_worktree_store_event)
|
||||||
.detach();
|
.detach();
|
||||||
|
cx.observe_global::<SettingsStore>(Self::on_settings_changed)
|
||||||
|
.detach();
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
mode: LspStoreMode::Ssh(SshLspStore { upstream_client }),
|
mode: LspStoreMode::Ssh(SshLspStore {
|
||||||
|
upstream_client,
|
||||||
|
current_lsp_settings: Default::default(),
|
||||||
|
}),
|
||||||
downstream_client: None,
|
downstream_client: None,
|
||||||
project_id,
|
project_id,
|
||||||
buffer_store,
|
buffer_store,
|
||||||
|
@ -401,6 +439,7 @@ impl LspStore {
|
||||||
buffer_snapshots: Default::default(),
|
buffer_snapshots: Default::default(),
|
||||||
next_diagnostic_group_id: Default::default(),
|
next_diagnostic_group_id: Default::default(),
|
||||||
diagnostic_summaries: Default::default(),
|
diagnostic_summaries: Default::default(),
|
||||||
|
|
||||||
diagnostics: Default::default(),
|
diagnostics: Default::default(),
|
||||||
active_entry: None,
|
active_entry: None,
|
||||||
_maintain_workspace_config: Self::maintain_workspace_config(cx),
|
_maintain_workspace_config: Self::maintain_workspace_config(cx),
|
||||||
|
@ -498,6 +537,36 @@ impl LspStore {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn on_prettier_store_event(
|
||||||
|
&mut self,
|
||||||
|
_: Model<PrettierStore>,
|
||||||
|
event: &PrettierStoreEvent,
|
||||||
|
cx: &mut ModelContext<Self>,
|
||||||
|
) {
|
||||||
|
match event {
|
||||||
|
PrettierStoreEvent::LanguageServerRemoved(prettier_server_id) => {
|
||||||
|
self.unregister_supplementary_language_server(*prettier_server_id, cx);
|
||||||
|
}
|
||||||
|
PrettierStoreEvent::LanguageServerAdded {
|
||||||
|
new_server_id,
|
||||||
|
name,
|
||||||
|
prettier_server,
|
||||||
|
} => {
|
||||||
|
self.register_supplementary_language_server(
|
||||||
|
*new_server_id,
|
||||||
|
name.clone(),
|
||||||
|
prettier_server.clone(),
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo!
|
||||||
|
pub fn prettier_store(&self) -> Option<Model<PrettierStore>> {
|
||||||
|
self.as_local().map(|local| local.prettier_store.clone())
|
||||||
|
}
|
||||||
|
|
||||||
fn on_buffer_event(
|
fn on_buffer_event(
|
||||||
&mut self,
|
&mut self,
|
||||||
buffer: Model<Buffer>,
|
buffer: Model<Buffer>,
|
||||||
|
@ -656,11 +725,29 @@ impl LspStore {
|
||||||
});
|
});
|
||||||
|
|
||||||
let buffer_file = buffer.read(cx).file().cloned();
|
let buffer_file = buffer.read(cx).file().cloned();
|
||||||
|
let settings = language_settings(Some(&new_language), buffer_file.as_ref(), cx).clone();
|
||||||
let buffer_file = File::from_dyn(buffer_file.as_ref());
|
let buffer_file = File::from_dyn(buffer_file.as_ref());
|
||||||
|
|
||||||
if let Some(file) = buffer_file {
|
let worktree_id = if let Some(file) = buffer_file {
|
||||||
let worktree = file.worktree.clone();
|
let worktree = file.worktree.clone();
|
||||||
self.start_language_servers(&worktree, new_language.name(), cx)
|
self.start_language_servers(&worktree, new_language.name(), cx);
|
||||||
|
|
||||||
|
Some(worktree.read(cx).id())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(prettier_plugins) = prettier_store::prettier_plugins_for_language(&settings) {
|
||||||
|
let prettier_store = self.as_local().map(|s| s.prettier_store.clone());
|
||||||
|
if let Some(prettier_store) = prettier_store {
|
||||||
|
prettier_store.update(cx, |prettier_store, cx| {
|
||||||
|
prettier_store.install_default_prettier(
|
||||||
|
worktree_id,
|
||||||
|
prettier_plugins.iter().map(|s| Arc::from(s.as_str())),
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cx.emit(LspStoreEvent::LanguageDetected {
|
cx.emit(LspStoreEvent::LanguageDetected {
|
||||||
|
@ -799,6 +886,95 @@ impl LspStore {
|
||||||
Task::ready(Ok(Default::default()))
|
Task::ready(Ok(Default::default()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn on_settings_changed(&mut self, cx: &mut ModelContext<Self>) {
|
||||||
|
let mut language_servers_to_start = Vec::new();
|
||||||
|
let mut language_formatters_to_check = Vec::new();
|
||||||
|
for buffer in self.buffer_store.read(cx).buffers() {
|
||||||
|
let buffer = buffer.read(cx);
|
||||||
|
let buffer_file = File::from_dyn(buffer.file());
|
||||||
|
let buffer_language = buffer.language();
|
||||||
|
let settings = language_settings(buffer_language, buffer.file(), cx);
|
||||||
|
if let Some(language) = buffer_language {
|
||||||
|
if settings.enable_language_server {
|
||||||
|
if let Some(file) = buffer_file {
|
||||||
|
language_servers_to_start.push((file.worktree.clone(), language.name()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
language_formatters_to_check
|
||||||
|
.push((buffer_file.map(|f| f.worktree_id(cx)), settings.clone()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut language_servers_to_stop = Vec::new();
|
||||||
|
let mut language_servers_to_restart = Vec::new();
|
||||||
|
let languages = self.languages.to_vec();
|
||||||
|
|
||||||
|
let new_lsp_settings = ProjectSettings::get_global(cx).lsp.clone();
|
||||||
|
let Some(current_lsp_settings) = self.swap_current_lsp_settings(new_lsp_settings.clone())
|
||||||
|
else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
for (worktree_id, started_lsp_name) in self.started_language_servers() {
|
||||||
|
let language = languages.iter().find_map(|l| {
|
||||||
|
let adapter = self
|
||||||
|
.languages
|
||||||
|
.lsp_adapters(&l.name())
|
||||||
|
.iter()
|
||||||
|
.find(|adapter| adapter.name == started_lsp_name)?
|
||||||
|
.clone();
|
||||||
|
Some((l, adapter))
|
||||||
|
});
|
||||||
|
if let Some((language, adapter)) = language {
|
||||||
|
let worktree = self.worktree_for_id(worktree_id, cx).ok();
|
||||||
|
let file = worktree.as_ref().and_then(|tree| {
|
||||||
|
tree.update(cx, |tree, cx| tree.root_file(cx).map(|f| f as _))
|
||||||
|
});
|
||||||
|
if !language_settings(Some(language), file.as_ref(), cx).enable_language_server {
|
||||||
|
language_servers_to_stop.push((worktree_id, started_lsp_name.clone()));
|
||||||
|
} else if let Some(worktree) = worktree {
|
||||||
|
let server_name = &adapter.name.0;
|
||||||
|
match (
|
||||||
|
current_lsp_settings.get(server_name),
|
||||||
|
new_lsp_settings.get(server_name),
|
||||||
|
) {
|
||||||
|
(None, None) => {}
|
||||||
|
(Some(_), None) | (None, Some(_)) => {
|
||||||
|
language_servers_to_restart.push((worktree, language.name()));
|
||||||
|
}
|
||||||
|
(Some(current_lsp_settings), Some(new_lsp_settings)) => {
|
||||||
|
if current_lsp_settings != new_lsp_settings {
|
||||||
|
language_servers_to_restart.push((worktree, language.name()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (worktree_id, adapter_name) in language_servers_to_stop {
|
||||||
|
self.stop_language_server(worktree_id, adapter_name, cx)
|
||||||
|
.detach();
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(prettier_store) = self.as_local().map(|s| s.prettier_store.clone()) {
|
||||||
|
prettier_store.update(cx, |prettier_store, cx| {
|
||||||
|
prettier_store.on_settings_changed(language_formatters_to_check, cx)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start all the newly-enabled language servers.
|
||||||
|
for (worktree, language) in language_servers_to_start {
|
||||||
|
self.start_language_servers(&worktree, language, cx);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restart all language servers with changed initialization options.
|
||||||
|
for (worktree, language) in language_servers_to_restart {
|
||||||
|
self.restart_language_servers(worktree, language, cx);
|
||||||
|
}
|
||||||
|
|
||||||
|
cx.notify();
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn execute_code_actions_on_servers(
|
pub async fn execute_code_actions_on_servers(
|
||||||
this: &WeakModel<LspStore>,
|
this: &WeakModel<LspStore>,
|
||||||
adapters_and_servers: &[(Arc<CachedLspAdapter>, Arc<LanguageServer>)],
|
adapters_and_servers: &[(Arc<CachedLspAdapter>, Arc<LanguageServer>)],
|
||||||
|
@ -2375,7 +2551,7 @@ impl LspStore {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut ModelContext<Self>) {
|
fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut ModelContext<Self>) {
|
||||||
self.diagnostics.remove(&id_to_remove);
|
self.diagnostics.remove(&id_to_remove);
|
||||||
self.diagnostic_summaries.remove(&id_to_remove);
|
self.diagnostic_summaries.remove(&id_to_remove);
|
||||||
|
|
||||||
|
@ -2406,6 +2582,12 @@ impl LspStore {
|
||||||
}
|
}
|
||||||
cx.emit(LspStoreEvent::LanguageServerRemoved(server_id_to_remove));
|
cx.emit(LspStoreEvent::LanguageServerRemoved(server_id_to_remove));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(local) = self.as_local() {
|
||||||
|
local.prettier_store.update(cx, |prettier_store, cx| {
|
||||||
|
prettier_store.remove_worktree(id_to_remove, cx);
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn shared(
|
pub fn shared(
|
||||||
|
@ -6117,6 +6299,10 @@ impl LspStore {
|
||||||
|
|
||||||
let Some(local) = self.as_local() else { return };
|
let Some(local) = self.as_local() else { return };
|
||||||
|
|
||||||
|
local.prettier_store.update(cx, |prettier_store, cx| {
|
||||||
|
prettier_store.update_prettier_settings(&worktree_handle, changes, cx)
|
||||||
|
});
|
||||||
|
|
||||||
let worktree_id = worktree_handle.read(cx).id();
|
let worktree_id = worktree_handle.read(cx).id();
|
||||||
let mut language_server_ids = self
|
let mut language_server_ids = self
|
||||||
.language_server_ids
|
.language_server_ids
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -4,7 +4,7 @@ pub mod debounced_delay;
|
||||||
pub mod lsp_command;
|
pub mod lsp_command;
|
||||||
pub mod lsp_ext_command;
|
pub mod lsp_ext_command;
|
||||||
pub mod lsp_store;
|
pub mod lsp_store;
|
||||||
mod prettier_support;
|
pub mod prettier_store;
|
||||||
pub mod project_settings;
|
pub mod project_settings;
|
||||||
pub mod search;
|
pub mod search;
|
||||||
mod task_inventory;
|
mod task_inventory;
|
||||||
|
@ -31,7 +31,6 @@ pub use environment::ProjectEnvironment;
|
||||||
use futures::{
|
use futures::{
|
||||||
channel::mpsc::{self, UnboundedReceiver},
|
channel::mpsc::{self, UnboundedReceiver},
|
||||||
future::try_join_all,
|
future::try_join_all,
|
||||||
stream::FuturesUnordered,
|
|
||||||
AsyncWriteExt, FutureExt, StreamExt,
|
AsyncWriteExt, FutureExt, StreamExt,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -59,8 +58,8 @@ use lsp_command::*;
|
||||||
use node_runtime::NodeRuntime;
|
use node_runtime::NodeRuntime;
|
||||||
use parking_lot::{Mutex, RwLock};
|
use parking_lot::{Mutex, RwLock};
|
||||||
use paths::{local_tasks_file_relative_path, local_vscode_tasks_file_relative_path};
|
use paths::{local_tasks_file_relative_path, local_vscode_tasks_file_relative_path};
|
||||||
use prettier_support::{DefaultPrettier, PrettierInstance};
|
pub use prettier_store::PrettierStore;
|
||||||
use project_settings::{LspSettings, ProjectSettings, SettingsObserver};
|
use project_settings::{ProjectSettings, SettingsObserver};
|
||||||
use remote::SshSession;
|
use remote::SshSession;
|
||||||
use rpc::{proto::SSH_PROJECT_ID, AnyProtoClient, ErrorCode};
|
use rpc::{proto::SSH_PROJECT_ID, AnyProtoClient, ErrorCode};
|
||||||
use search::{SearchInputKind, SearchQuery, SearchResult};
|
use search::{SearchInputKind, SearchQuery, SearchResult};
|
||||||
|
@ -140,7 +139,6 @@ pub struct Project {
|
||||||
buffer_ordered_messages_tx: mpsc::UnboundedSender<BufferOrderedMessage>,
|
buffer_ordered_messages_tx: mpsc::UnboundedSender<BufferOrderedMessage>,
|
||||||
languages: Arc<LanguageRegistry>,
|
languages: Arc<LanguageRegistry>,
|
||||||
client: Arc<client::Client>,
|
client: Arc<client::Client>,
|
||||||
current_lsp_settings: HashMap<Arc<str>, LspSettings>,
|
|
||||||
join_project_response_message_id: u32,
|
join_project_response_message_id: u32,
|
||||||
user_store: Model<UserStore>,
|
user_store: Model<UserStore>,
|
||||||
fs: Arc<dyn Fs>,
|
fs: Arc<dyn Fs>,
|
||||||
|
@ -157,9 +155,6 @@ pub struct Project {
|
||||||
remotely_created_buffers: Arc<Mutex<RemotelyCreatedBuffers>>,
|
remotely_created_buffers: Arc<Mutex<RemotelyCreatedBuffers>>,
|
||||||
terminals: Terminals,
|
terminals: Terminals,
|
||||||
node: Option<Arc<dyn NodeRuntime>>,
|
node: Option<Arc<dyn NodeRuntime>>,
|
||||||
default_prettier: DefaultPrettier,
|
|
||||||
prettiers_per_worktree: HashMap<WorktreeId, HashSet<Option<PathBuf>>>,
|
|
||||||
prettier_instances: HashMap<PathBuf, PrettierInstance>,
|
|
||||||
tasks: Model<Inventory>,
|
tasks: Model<Inventory>,
|
||||||
hosted_project_id: Option<ProjectId>,
|
hosted_project_id: Option<ProjectId>,
|
||||||
dev_server_project_id: Option<client::DevServerProjectId>,
|
dev_server_project_id: Option<client::DevServerProjectId>,
|
||||||
|
@ -634,6 +629,16 @@ impl Project {
|
||||||
cx.subscribe(&buffer_store, Self::on_buffer_store_event)
|
cx.subscribe(&buffer_store, Self::on_buffer_store_event)
|
||||||
.detach();
|
.detach();
|
||||||
|
|
||||||
|
let prettier_store = cx.new_model(|cx| {
|
||||||
|
PrettierStore::new(
|
||||||
|
node.clone(),
|
||||||
|
fs.clone(),
|
||||||
|
languages.clone(),
|
||||||
|
worktree_store.clone(),
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
let settings_observer = cx.new_model(|cx| {
|
let settings_observer = cx.new_model(|cx| {
|
||||||
SettingsObserver::new_local(fs.clone(), worktree_store.clone(), cx)
|
SettingsObserver::new_local(fs.clone(), worktree_store.clone(), cx)
|
||||||
});
|
});
|
||||||
|
@ -643,6 +648,7 @@ impl Project {
|
||||||
LspStore::new_local(
|
LspStore::new_local(
|
||||||
buffer_store.clone(),
|
buffer_store.clone(),
|
||||||
worktree_store.clone(),
|
worktree_store.clone(),
|
||||||
|
prettier_store.clone(),
|
||||||
environment.clone(),
|
environment.clone(),
|
||||||
languages.clone(),
|
languages.clone(),
|
||||||
Some(client.http_client()),
|
Some(client.http_client()),
|
||||||
|
@ -658,14 +664,10 @@ impl Project {
|
||||||
worktree_store,
|
worktree_store,
|
||||||
buffer_store,
|
buffer_store,
|
||||||
lsp_store,
|
lsp_store,
|
||||||
current_lsp_settings: ProjectSettings::get_global(cx).lsp.clone(),
|
|
||||||
join_project_response_message_id: 0,
|
join_project_response_message_id: 0,
|
||||||
client_state: ProjectClientState::Local,
|
client_state: ProjectClientState::Local,
|
||||||
client_subscriptions: Vec::new(),
|
client_subscriptions: Vec::new(),
|
||||||
_subscriptions: vec![
|
_subscriptions: vec![cx.on_release(Self::release)],
|
||||||
cx.observe_global::<SettingsStore>(Self::on_settings_changed),
|
|
||||||
cx.on_release(Self::release),
|
|
||||||
],
|
|
||||||
active_entry: None,
|
active_entry: None,
|
||||||
snippets,
|
snippets,
|
||||||
languages,
|
languages,
|
||||||
|
@ -680,9 +682,6 @@ impl Project {
|
||||||
local_handles: Vec::new(),
|
local_handles: Vec::new(),
|
||||||
},
|
},
|
||||||
node: Some(node),
|
node: Some(node),
|
||||||
default_prettier: DefaultPrettier::default(),
|
|
||||||
prettiers_per_worktree: HashMap::default(),
|
|
||||||
prettier_instances: HashMap::default(),
|
|
||||||
tasks,
|
tasks,
|
||||||
hosted_project_id: None,
|
hosted_project_id: None,
|
||||||
dev_server_project_id: None,
|
dev_server_project_id: None,
|
||||||
|
@ -751,14 +750,10 @@ impl Project {
|
||||||
worktree_store,
|
worktree_store,
|
||||||
buffer_store,
|
buffer_store,
|
||||||
lsp_store,
|
lsp_store,
|
||||||
current_lsp_settings: ProjectSettings::get_global(cx).lsp.clone(),
|
|
||||||
join_project_response_message_id: 0,
|
join_project_response_message_id: 0,
|
||||||
client_state: ProjectClientState::Local,
|
client_state: ProjectClientState::Local,
|
||||||
client_subscriptions: Vec::new(),
|
client_subscriptions: Vec::new(),
|
||||||
_subscriptions: vec![
|
_subscriptions: vec![cx.on_release(Self::release)],
|
||||||
cx.observe_global::<SettingsStore>(Self::on_settings_changed),
|
|
||||||
cx.on_release(Self::release),
|
|
||||||
],
|
|
||||||
active_entry: None,
|
active_entry: None,
|
||||||
snippets,
|
snippets,
|
||||||
languages,
|
languages,
|
||||||
|
@ -773,9 +768,6 @@ impl Project {
|
||||||
local_handles: Vec::new(),
|
local_handles: Vec::new(),
|
||||||
},
|
},
|
||||||
node: Some(node),
|
node: Some(node),
|
||||||
default_prettier: DefaultPrettier::default(),
|
|
||||||
prettiers_per_worktree: HashMap::default(),
|
|
||||||
prettier_instances: HashMap::default(),
|
|
||||||
tasks,
|
tasks,
|
||||||
hosted_project_id: None,
|
hosted_project_id: None,
|
||||||
dev_server_project_id: None,
|
dev_server_project_id: None,
|
||||||
|
@ -928,7 +920,6 @@ impl Project {
|
||||||
buffer_store: buffer_store.clone(),
|
buffer_store: buffer_store.clone(),
|
||||||
worktree_store: worktree_store.clone(),
|
worktree_store: worktree_store.clone(),
|
||||||
lsp_store: lsp_store.clone(),
|
lsp_store: lsp_store.clone(),
|
||||||
current_lsp_settings: ProjectSettings::get_global(cx).lsp.clone(),
|
|
||||||
active_entry: None,
|
active_entry: None,
|
||||||
collaborators: Default::default(),
|
collaborators: Default::default(),
|
||||||
join_project_response_message_id: response.message_id,
|
join_project_response_message_id: response.message_id,
|
||||||
|
@ -954,9 +945,6 @@ impl Project {
|
||||||
local_handles: Vec::new(),
|
local_handles: Vec::new(),
|
||||||
},
|
},
|
||||||
node: None,
|
node: None,
|
||||||
default_prettier: DefaultPrettier::default(),
|
|
||||||
prettiers_per_worktree: HashMap::default(),
|
|
||||||
prettier_instances: HashMap::default(),
|
|
||||||
tasks,
|
tasks,
|
||||||
hosted_project_id: None,
|
hosted_project_id: None,
|
||||||
dev_server_project_id: response
|
dev_server_project_id: response
|
||||||
|
@ -1176,112 +1164,6 @@ impl Project {
|
||||||
self.worktree_store.clone()
|
self.worktree_store.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_settings_changed(&mut self, cx: &mut ModelContext<Self>) {
|
|
||||||
let mut language_servers_to_start = Vec::new();
|
|
||||||
let mut language_formatters_to_check = Vec::new();
|
|
||||||
for buffer in self.buffer_store.read(cx).buffers() {
|
|
||||||
let buffer = buffer.read(cx);
|
|
||||||
let buffer_file = File::from_dyn(buffer.file());
|
|
||||||
let buffer_language = buffer.language();
|
|
||||||
let settings = language_settings(buffer_language, buffer.file(), cx);
|
|
||||||
if let Some(language) = buffer_language {
|
|
||||||
if settings.enable_language_server {
|
|
||||||
if let Some(file) = buffer_file {
|
|
||||||
language_servers_to_start.push((file.worktree.clone(), language.name()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
language_formatters_to_check
|
|
||||||
.push((buffer_file.map(|f| f.worktree_id(cx)), settings.clone()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut language_servers_to_stop = Vec::new();
|
|
||||||
let mut language_servers_to_restart = Vec::new();
|
|
||||||
let languages = self.languages.to_vec();
|
|
||||||
|
|
||||||
let new_lsp_settings = ProjectSettings::get_global(cx).lsp.clone();
|
|
||||||
let current_lsp_settings = &self.current_lsp_settings;
|
|
||||||
for (worktree_id, started_lsp_name) in self.lsp_store.read(cx).started_language_servers() {
|
|
||||||
let language = languages.iter().find_map(|l| {
|
|
||||||
let adapter = self
|
|
||||||
.languages
|
|
||||||
.lsp_adapters(&l.name())
|
|
||||||
.iter()
|
|
||||||
.find(|adapter| adapter.name == started_lsp_name)?
|
|
||||||
.clone();
|
|
||||||
Some((l, adapter))
|
|
||||||
});
|
|
||||||
if let Some((language, adapter)) = language {
|
|
||||||
let worktree = self.worktree_for_id(worktree_id, cx);
|
|
||||||
let file = worktree.as_ref().and_then(|tree| {
|
|
||||||
tree.update(cx, |tree, cx| tree.root_file(cx).map(|f| f as _))
|
|
||||||
});
|
|
||||||
if !language_settings(Some(language), file.as_ref(), cx).enable_language_server {
|
|
||||||
language_servers_to_stop.push((worktree_id, started_lsp_name.clone()));
|
|
||||||
} else if let Some(worktree) = worktree {
|
|
||||||
let server_name = &adapter.name.0;
|
|
||||||
match (
|
|
||||||
current_lsp_settings.get(server_name),
|
|
||||||
new_lsp_settings.get(server_name),
|
|
||||||
) {
|
|
||||||
(None, None) => {}
|
|
||||||
(Some(_), None) | (None, Some(_)) => {
|
|
||||||
language_servers_to_restart.push((worktree, language.name()));
|
|
||||||
}
|
|
||||||
(Some(current_lsp_settings), Some(new_lsp_settings)) => {
|
|
||||||
if current_lsp_settings != new_lsp_settings {
|
|
||||||
language_servers_to_restart.push((worktree, language.name()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.current_lsp_settings = new_lsp_settings;
|
|
||||||
|
|
||||||
// Stop all newly-disabled language servers.
|
|
||||||
self.lsp_store.update(cx, |lsp_store, cx| {
|
|
||||||
for (worktree_id, adapter_name) in language_servers_to_stop {
|
|
||||||
lsp_store
|
|
||||||
.stop_language_server(worktree_id, adapter_name, cx)
|
|
||||||
.detach();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let mut prettier_plugins_by_worktree = HashMap::default();
|
|
||||||
for (worktree, language_settings) in language_formatters_to_check {
|
|
||||||
if let Some(plugins) =
|
|
||||||
prettier_support::prettier_plugins_for_language(&language_settings)
|
|
||||||
{
|
|
||||||
prettier_plugins_by_worktree
|
|
||||||
.entry(worktree)
|
|
||||||
.or_insert_with(HashSet::default)
|
|
||||||
.extend(plugins.iter().cloned());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (worktree, prettier_plugins) in prettier_plugins_by_worktree {
|
|
||||||
self.install_default_prettier(
|
|
||||||
worktree,
|
|
||||||
prettier_plugins.into_iter().map(Arc::from),
|
|
||||||
cx,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start all the newly-enabled language servers.
|
|
||||||
self.lsp_store.update(cx, |lsp_store, cx| {
|
|
||||||
for (worktree, language) in language_servers_to_start {
|
|
||||||
lsp_store.start_language_servers(&worktree, language, cx);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Restart all language servers with changed initialization options.
|
|
||||||
for (worktree, language) in language_servers_to_restart {
|
|
||||||
lsp_store.restart_language_servers(worktree, language, cx);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
cx.notify();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn buffer_for_id(&self, remote_id: BufferId, cx: &AppContext) -> Option<Model<Buffer>> {
|
pub fn buffer_for_id(&self, remote_id: BufferId, cx: &AppContext) -> Option<Model<Buffer>> {
|
||||||
self.buffer_store.read(cx).get(remote_id)
|
self.buffer_store.read(cx).get(remote_id)
|
||||||
}
|
}
|
||||||
|
@ -2160,24 +2042,10 @@ impl Project {
|
||||||
buffer,
|
buffer,
|
||||||
new_language,
|
new_language,
|
||||||
} => {
|
} => {
|
||||||
let Some(new_language) = new_language else {
|
let Some(_) = new_language else {
|
||||||
cx.emit(Event::LanguageNotFound(buffer.clone()));
|
cx.emit(Event::LanguageNotFound(buffer.clone()));
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
let buffer_file = buffer.read(cx).file().cloned();
|
|
||||||
let settings =
|
|
||||||
language_settings(Some(new_language), buffer_file.as_ref(), cx).clone();
|
|
||||||
let buffer_file = File::from_dyn(buffer_file.as_ref());
|
|
||||||
let worktree = buffer_file.as_ref().map(|f| f.worktree_id(cx));
|
|
||||||
if let Some(prettier_plugins) =
|
|
||||||
prettier_support::prettier_plugins_for_language(&settings)
|
|
||||||
{
|
|
||||||
self.install_default_prettier(
|
|
||||||
worktree,
|
|
||||||
prettier_plugins.iter().map(|s| Arc::from(s.as_str())),
|
|
||||||
cx,
|
|
||||||
);
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
LspStoreEvent::RefreshInlayHints => cx.emit(Event::RefreshInlayHints),
|
LspStoreEvent::RefreshInlayHints => cx.emit(Event::RefreshInlayHints),
|
||||||
LspStoreEvent::LanguageServerPrompt(prompt) => {
|
LspStoreEvent::LanguageServerPrompt(prompt) => {
|
||||||
|
@ -2253,7 +2121,6 @@ impl Project {
|
||||||
worktree::Event::UpdatedEntries(changes) => {
|
worktree::Event::UpdatedEntries(changes) => {
|
||||||
if is_local {
|
if is_local {
|
||||||
this.update_local_worktree_settings(&worktree, changes, cx);
|
this.update_local_worktree_settings(&worktree, changes, cx);
|
||||||
this.update_prettier_settings(&worktree, changes, cx);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cx.emit(Event::WorktreeUpdatedEntries(
|
cx.emit(Event::WorktreeUpdatedEntries(
|
||||||
|
@ -2300,37 +2167,6 @@ impl Project {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut prettier_instances_to_clean = FuturesUnordered::new();
|
|
||||||
if let Some(prettier_paths) = self.prettiers_per_worktree.remove(&id_to_remove) {
|
|
||||||
for path in prettier_paths.iter().flatten() {
|
|
||||||
if let Some(prettier_instance) = self.prettier_instances.remove(path) {
|
|
||||||
prettier_instances_to_clean.push(async move {
|
|
||||||
prettier_instance
|
|
||||||
.server()
|
|
||||||
.await
|
|
||||||
.map(|server| server.server_id())
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cx.spawn(|project, mut cx| async move {
|
|
||||||
while let Some(prettier_server_id) = prettier_instances_to_clean.next().await {
|
|
||||||
if let Some(prettier_server_id) = prettier_server_id {
|
|
||||||
project
|
|
||||||
.update(&mut cx, |project, cx| {
|
|
||||||
project.lsp_store.update(cx, |lsp_store, cx| {
|
|
||||||
lsp_store.unregister_supplementary_language_server(
|
|
||||||
prettier_server_id,
|
|
||||||
cx,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.ok();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.detach();
|
|
||||||
|
|
||||||
self.task_inventory().update(cx, |inventory, _| {
|
self.task_inventory().update(cx, |inventory, _| {
|
||||||
inventory.remove_worktree_sources(id_to_remove);
|
inventory.remove_worktree_sources(id_to_remove);
|
||||||
});
|
});
|
||||||
|
@ -3059,11 +2895,21 @@ impl Project {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Formatter::Prettier => prettier_support::format_with_prettier(&project, buffer, cx)
|
Formatter::Prettier => {
|
||||||
|
let prettier = project.update(cx, |project, cx| {
|
||||||
|
project
|
||||||
|
.lsp_store
|
||||||
|
.read(cx)
|
||||||
|
.prettier_store()
|
||||||
|
.unwrap()
|
||||||
|
.downgrade()
|
||||||
|
})?;
|
||||||
|
prettier_store::format_with_prettier(&prettier, buffer, cx)
|
||||||
.await
|
.await
|
||||||
.transpose()
|
.transpose()
|
||||||
.ok()
|
.ok()
|
||||||
.flatten(),
|
.flatten()
|
||||||
|
}
|
||||||
Formatter::External { command, arguments } => {
|
Formatter::External { command, arguments } => {
|
||||||
let buffer_abs_path = buffer_abs_path.as_ref().map(|path| path.as_path());
|
let buffer_abs_path = buffer_abs_path.as_ref().map(|path| path.as_path());
|
||||||
Self::format_via_external_command(buffer, buffer_abs_path, command, arguments, cx)
|
Self::format_via_external_command(buffer, buffer_abs_path, command, arguments, cx)
|
||||||
|
|
|
@ -26,6 +26,7 @@ env_logger.workspace = true
|
||||||
fs.workspace = true
|
fs.workspace = true
|
||||||
futures.workspace = true
|
futures.workspace = true
|
||||||
gpui.workspace = true
|
gpui.workspace = true
|
||||||
|
node_runtime.workspace = true
|
||||||
log.workspace = true
|
log.workspace = true
|
||||||
project.workspace = true
|
project.workspace = true
|
||||||
remote.workspace = true
|
remote.workspace = true
|
||||||
|
|
|
@ -2,12 +2,13 @@ use anyhow::{anyhow, Result};
|
||||||
use fs::Fs;
|
use fs::Fs;
|
||||||
use gpui::{AppContext, AsyncAppContext, Context, Model, ModelContext};
|
use gpui::{AppContext, AsyncAppContext, Context, Model, ModelContext};
|
||||||
use language::{proto::serialize_operation, Buffer, BufferEvent, LanguageRegistry};
|
use language::{proto::serialize_operation, Buffer, BufferEvent, LanguageRegistry};
|
||||||
|
use node_runtime::DummyNodeRuntime;
|
||||||
use project::{
|
use project::{
|
||||||
buffer_store::{BufferStore, BufferStoreEvent},
|
buffer_store::{BufferStore, BufferStoreEvent},
|
||||||
project_settings::SettingsObserver,
|
project_settings::SettingsObserver,
|
||||||
search::SearchQuery,
|
search::SearchQuery,
|
||||||
worktree_store::WorktreeStore,
|
worktree_store::WorktreeStore,
|
||||||
LspStore, LspStoreEvent, ProjectPath, WorktreeId,
|
LspStore, LspStoreEvent, PrettierStore, ProjectPath, WorktreeId,
|
||||||
};
|
};
|
||||||
use remote::SshSession;
|
use remote::SshSession;
|
||||||
use rpc::{
|
use rpc::{
|
||||||
|
@ -54,6 +55,16 @@ impl HeadlessProject {
|
||||||
buffer_store.shared(SSH_PROJECT_ID, session.clone().into(), cx);
|
buffer_store.shared(SSH_PROJECT_ID, session.clone().into(), cx);
|
||||||
buffer_store
|
buffer_store
|
||||||
});
|
});
|
||||||
|
let prettier_store = cx.new_model(|cx| {
|
||||||
|
PrettierStore::new(
|
||||||
|
DummyNodeRuntime::new(),
|
||||||
|
fs.clone(),
|
||||||
|
languages.clone(),
|
||||||
|
worktree_store.clone(),
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
let settings_observer = cx.new_model(|cx| {
|
let settings_observer = cx.new_model(|cx| {
|
||||||
let mut observer = SettingsObserver::new_local(fs.clone(), worktree_store.clone(), cx);
|
let mut observer = SettingsObserver::new_local(fs.clone(), worktree_store.clone(), cx);
|
||||||
observer.shared(SSH_PROJECT_ID, session.clone().into(), cx);
|
observer.shared(SSH_PROJECT_ID, session.clone().into(), cx);
|
||||||
|
@ -64,6 +75,7 @@ impl HeadlessProject {
|
||||||
let mut lsp_store = LspStore::new_local(
|
let mut lsp_store = LspStore::new_local(
|
||||||
buffer_store.clone(),
|
buffer_store.clone(),
|
||||||
worktree_store.clone(),
|
worktree_store.clone(),
|
||||||
|
prettier_store.clone(),
|
||||||
environment,
|
environment,
|
||||||
languages.clone(),
|
languages.clone(),
|
||||||
None,
|
None,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue