Add language toolchains (#19576)
This PR adds support for selecting toolchains for a given language (e.g. Rust toolchains or Python virtual environments) with support for SSH projects provided out of the box. For Python we piggy-back off of [PET](https://github.com/microsoft/python-environment-tools), a library maintained by Microsoft. Closes #16421 Closes #7646 Release Notes: - Added toolchain selector to the status bar (with initial support for Python virtual environments)
This commit is contained in:
@@ -7,6 +7,8 @@ use client::DevServerProjectId;
|
||||
use db::{define_connection, query, sqlez::connection::Connection, sqlez_macros::sql};
|
||||
use gpui::{point, size, Axis, Bounds, WindowBounds, WindowId};
|
||||
|
||||
use language::{LanguageName, Toolchain};
|
||||
use project::WorktreeId;
|
||||
use remote::ssh_session::SshProjectId;
|
||||
use sqlez::{
|
||||
bindable::{Bind, Column, StaticColumnCount},
|
||||
@@ -204,7 +206,8 @@ define_connection! {
|
||||
// preview: bool // Indicates if this item is a preview item
|
||||
// )
|
||||
pub static ref DB: WorkspaceDb<()> =
|
||||
&[sql!(
|
||||
&[
|
||||
sql!(
|
||||
CREATE TABLE workspaces(
|
||||
workspace_id INTEGER PRIMARY KEY,
|
||||
workspace_location BLOB UNIQUE,
|
||||
@@ -367,6 +370,16 @@ define_connection! {
|
||||
sql!(
|
||||
ALTER TABLE ssh_projects RENAME COLUMN path TO paths;
|
||||
),
|
||||
sql!(
|
||||
CREATE TABLE toolchains (
|
||||
workspace_id INTEGER,
|
||||
worktree_id INTEGER,
|
||||
language_name TEXT NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
path TEXT NOT NULL,
|
||||
PRIMARY KEY (workspace_id, worktree_id, language_name)
|
||||
);
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -528,6 +541,7 @@ impl WorkspaceDb {
|
||||
match workspace.location {
|
||||
SerializedWorkspaceLocation::Local(local_paths, local_paths_order) => {
|
||||
conn.exec_bound(sql!(
|
||||
DELETE FROM toolchains WHERE workspace_id = ?1;
|
||||
DELETE FROM workspaces WHERE local_paths = ? AND workspace_id != ?
|
||||
))?((&local_paths, workspace.id))
|
||||
.context("clearing out old locations")?;
|
||||
@@ -576,6 +590,7 @@ impl WorkspaceDb {
|
||||
}
|
||||
SerializedWorkspaceLocation::Ssh(ssh_project) => {
|
||||
conn.exec_bound(sql!(
|
||||
DELETE FROM toolchains WHERE workspace_id = ?1;
|
||||
DELETE FROM workspaces WHERE ssh_project_id = ? AND workspace_id != ?
|
||||
))?((ssh_project.id.0, workspace.id))
|
||||
.context("clearing out old locations")?;
|
||||
@@ -737,6 +752,7 @@ impl WorkspaceDb {
|
||||
|
||||
query! {
|
||||
pub async fn delete_workspace_by_id(id: WorkspaceId) -> Result<()> {
|
||||
DELETE FROM toolchains WHERE workspace_id = ?1;
|
||||
DELETE FROM workspaces
|
||||
WHERE workspace_id IS ?
|
||||
}
|
||||
@@ -751,6 +767,7 @@ impl WorkspaceDb {
|
||||
DELETE FROM dev_server_projects WHERE id = ?
|
||||
))?(id.0)?;
|
||||
conn.exec_bound(sql!(
|
||||
DELETE FROM toolchains WHERE workspace_id = ?1;
|
||||
DELETE FROM workspaces
|
||||
WHERE dev_server_project_id IS ?
|
||||
))?(id.0)
|
||||
@@ -1053,6 +1070,83 @@ impl WorkspaceDb {
|
||||
WHERE workspace_id = ?1
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn toolchain(
|
||||
&self,
|
||||
workspace_id: WorkspaceId,
|
||||
worktree_id: WorktreeId,
|
||||
language_name: LanguageName,
|
||||
) -> Result<Option<Toolchain>> {
|
||||
self.write(move |this| {
|
||||
let mut select = this
|
||||
.select_bound(sql!(
|
||||
SELECT name, path FROM toolchains WHERE workspace_id = ? AND language_name = ? AND worktree_id = ?
|
||||
))
|
||||
.context("Preparing insertion")?;
|
||||
|
||||
let toolchain: Vec<(String, String)> =
|
||||
select((workspace_id, language_name.0.to_owned(), worktree_id.to_usize()))?;
|
||||
|
||||
Ok(toolchain.into_iter().next().map(|(name, path)| Toolchain {
|
||||
name: name.into(),
|
||||
path: path.into(),
|
||||
language_name,
|
||||
}))
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
pub(crate) async fn toolchains(
|
||||
&self,
|
||||
workspace_id: WorkspaceId,
|
||||
) -> Result<Vec<(Toolchain, WorktreeId)>> {
|
||||
self.write(move |this| {
|
||||
let mut select = this
|
||||
.select_bound(sql!(
|
||||
SELECT name, path, worktree_id, language_name FROM toolchains WHERE workspace_id = ?
|
||||
))
|
||||
.context("Preparing insertion")?;
|
||||
|
||||
let toolchain: Vec<(String, String, u64, String)> =
|
||||
select(workspace_id)?;
|
||||
|
||||
Ok(toolchain.into_iter().map(|(name, path, worktree_id, language_name)| (Toolchain {
|
||||
name: name.into(),
|
||||
path: path.into(),
|
||||
language_name: LanguageName::new(&language_name),
|
||||
}, WorktreeId::from_proto(worktree_id))).collect())
|
||||
})
|
||||
.await
|
||||
}
|
||||
pub async fn set_toolchain(
|
||||
&self,
|
||||
workspace_id: WorkspaceId,
|
||||
worktree_id: WorktreeId,
|
||||
toolchain: Toolchain,
|
||||
) -> Result<()> {
|
||||
self.write(move |conn| {
|
||||
let mut insert = conn
|
||||
.exec_bound(sql!(
|
||||
INSERT INTO toolchains(workspace_id, worktree_id, language_name, name, path) VALUES (?, ?, ?, ?, ?)
|
||||
ON CONFLICT DO
|
||||
UPDATE SET
|
||||
name = ?4,
|
||||
path = ?5
|
||||
|
||||
))
|
||||
.context("Preparing insertion")?;
|
||||
|
||||
insert((
|
||||
workspace_id,
|
||||
worktree_id.to_usize(),
|
||||
toolchain.language_name.0.as_ref(),
|
||||
toolchain.name.as_ref(),
|
||||
toolchain.path.as_ref(),
|
||||
))?;
|
||||
|
||||
Ok(())
|
||||
}).await
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -1153,6 +1153,14 @@ impl Workspace {
|
||||
DB.next_id().await.unwrap_or_else(|_| Default::default())
|
||||
};
|
||||
|
||||
let toolchains = DB.toolchains(workspace_id).await?;
|
||||
for (toolchain, worktree_id) in toolchains {
|
||||
project_handle
|
||||
.update(&mut cx, |this, cx| {
|
||||
this.activate_toolchain(worktree_id, toolchain, cx)
|
||||
})?
|
||||
.await;
|
||||
}
|
||||
let window = if let Some(window) = requesting_window {
|
||||
cx.update_window(window.into(), |_, cx| {
|
||||
cx.replace_root_view(|cx| {
|
||||
@@ -5522,6 +5530,14 @@ pub fn open_ssh_project(
|
||||
)
|
||||
})?;
|
||||
|
||||
let toolchains = DB.toolchains(workspace_id).await?;
|
||||
for (toolchain, worktree_id) in toolchains {
|
||||
project
|
||||
.update(&mut cx, |this, cx| {
|
||||
this.activate_toolchain(worktree_id, toolchain, cx)
|
||||
})?
|
||||
.await;
|
||||
}
|
||||
let mut project_paths_to_open = vec![];
|
||||
let mut project_path_errors = vec![];
|
||||
|
||||
|
||||
Reference in New Issue
Block a user