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:
parent
03bd95405b
commit
cdddb4d360
33 changed files with 2221 additions and 133 deletions
|
@ -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)]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue