Improve TypeScript task detection (#31711)
Parses project's package.json to better detect Jasmine, Jest, Vitest and Mocha and `test`, `build` scripts presence. Also tries to detect `pnpm` and `npx` as test runners, falls back to `npm`. https://github.com/user-attachments/assets/112d3d8b-8daa-4ba5-8cb5-2f483036bd98 Release Notes: - Improved TypeScript task detection
This commit is contained in:
parent
a23ee61a4b
commit
2abc5893c1
12 changed files with 469 additions and 43 deletions
|
@ -14,7 +14,7 @@ use dap::DapRegistry;
|
|||
use gpui::{App, AppContext as _, Entity, SharedString, Task};
|
||||
use itertools::Itertools;
|
||||
use language::{
|
||||
Buffer, ContextProvider, File, Language, LanguageToolchainStore, Location,
|
||||
Buffer, ContextLocation, ContextProvider, File, Language, LanguageToolchainStore, Location,
|
||||
language_settings::language_settings,
|
||||
};
|
||||
use lsp::{LanguageServerId, LanguageServerName};
|
||||
|
@ -791,11 +791,12 @@ impl ContextProvider for BasicContextProvider {
|
|||
fn build_context(
|
||||
&self,
|
||||
_: &TaskVariables,
|
||||
location: &Location,
|
||||
location: ContextLocation<'_>,
|
||||
_: Option<HashMap<String, String>>,
|
||||
_: Arc<dyn LanguageToolchainStore>,
|
||||
cx: &mut App,
|
||||
) -> Task<Result<TaskVariables>> {
|
||||
let location = location.file_location;
|
||||
let buffer = location.buffer.read(cx);
|
||||
let buffer_snapshot = buffer.snapshot();
|
||||
let symbols = buffer_snapshot.symbols_containing(location.range.start, None);
|
||||
|
|
|
@ -5,9 +5,10 @@ use std::{
|
|||
|
||||
use anyhow::Context as _;
|
||||
use collections::HashMap;
|
||||
use fs::Fs;
|
||||
use gpui::{App, AsyncApp, Context, Entity, EventEmitter, Task, WeakEntity};
|
||||
use language::{
|
||||
ContextProvider as _, LanguageToolchainStore, Location,
|
||||
ContextLocation, ContextProvider as _, LanguageToolchainStore, Location,
|
||||
proto::{deserialize_anchor, serialize_anchor},
|
||||
};
|
||||
use rpc::{AnyProtoClient, TypedEnvelope, proto};
|
||||
|
@ -311,6 +312,7 @@ fn local_task_context_for_location(
|
|||
let worktree_abs_path = worktree_id
|
||||
.and_then(|worktree_id| worktree_store.read(cx).worktree_for_id(worktree_id, cx))
|
||||
.and_then(|worktree| worktree.read(cx).root_dir());
|
||||
let fs = worktree_store.read(cx).fs();
|
||||
|
||||
cx.spawn(async move |cx| {
|
||||
let project_env = environment
|
||||
|
@ -324,6 +326,8 @@ fn local_task_context_for_location(
|
|||
.update(|cx| {
|
||||
combine_task_variables(
|
||||
captured_variables,
|
||||
fs,
|
||||
worktree_store.clone(),
|
||||
location,
|
||||
project_env.clone(),
|
||||
BasicContextProvider::new(worktree_store),
|
||||
|
@ -358,9 +362,15 @@ fn remote_task_context_for_location(
|
|||
// We need to gather a client context, as the headless one may lack certain information (e.g. tree-sitter parsing is disabled there, so symbols are not available).
|
||||
let mut remote_context = cx
|
||||
.update(|cx| {
|
||||
let worktree_root = worktree_root(&worktree_store, &location, cx);
|
||||
|
||||
BasicContextProvider::new(worktree_store).build_context(
|
||||
&TaskVariables::default(),
|
||||
&location,
|
||||
ContextLocation {
|
||||
fs: None,
|
||||
worktree_root,
|
||||
file_location: &location,
|
||||
},
|
||||
None,
|
||||
toolchain_store,
|
||||
cx,
|
||||
|
@ -408,8 +418,34 @@ fn remote_task_context_for_location(
|
|||
})
|
||||
}
|
||||
|
||||
fn worktree_root(
|
||||
worktree_store: &Entity<WorktreeStore>,
|
||||
location: &Location,
|
||||
cx: &mut App,
|
||||
) -> Option<PathBuf> {
|
||||
location
|
||||
.buffer
|
||||
.read(cx)
|
||||
.file()
|
||||
.map(|f| f.worktree_id(cx))
|
||||
.and_then(|worktree_id| worktree_store.read(cx).worktree_for_id(worktree_id, cx))
|
||||
.and_then(|worktree| {
|
||||
let worktree = worktree.read(cx);
|
||||
if !worktree.is_visible() {
|
||||
return None;
|
||||
}
|
||||
let root_entry = worktree.root_entry()?;
|
||||
if !root_entry.is_dir() {
|
||||
return None;
|
||||
}
|
||||
worktree.absolutize(&root_entry.path).ok()
|
||||
})
|
||||
}
|
||||
|
||||
fn combine_task_variables(
|
||||
mut captured_variables: TaskVariables,
|
||||
fs: Option<Arc<dyn Fs>>,
|
||||
worktree_store: Entity<WorktreeStore>,
|
||||
location: Location,
|
||||
project_env: Option<HashMap<String, String>>,
|
||||
baseline: BasicContextProvider,
|
||||
|
@ -424,9 +460,14 @@ fn combine_task_variables(
|
|||
cx.spawn(async move |cx| {
|
||||
let baseline = cx
|
||||
.update(|cx| {
|
||||
let worktree_root = worktree_root(&worktree_store, &location, cx);
|
||||
baseline.build_context(
|
||||
&captured_variables,
|
||||
&location,
|
||||
ContextLocation {
|
||||
fs: fs.clone(),
|
||||
worktree_root,
|
||||
file_location: &location,
|
||||
},
|
||||
project_env.clone(),
|
||||
toolchain_store.clone(),
|
||||
cx,
|
||||
|
@ -438,9 +479,14 @@ fn combine_task_variables(
|
|||
if let Some(provider) = language_context_provider {
|
||||
captured_variables.extend(
|
||||
cx.update(|cx| {
|
||||
let worktree_root = worktree_root(&worktree_store, &location, cx);
|
||||
provider.build_context(
|
||||
&captured_variables,
|
||||
&location,
|
||||
ContextLocation {
|
||||
fs,
|
||||
worktree_root,
|
||||
file_location: &location,
|
||||
},
|
||||
project_env,
|
||||
toolchain_store,
|
||||
cx,
|
||||
|
|
|
@ -967,6 +967,13 @@ impl WorktreeStore {
|
|||
.context("invalid request")?;
|
||||
Worktree::handle_expand_all_for_entry(worktree, envelope.payload, cx).await
|
||||
}
|
||||
|
||||
pub fn fs(&self) -> Option<Arc<dyn Fs>> {
|
||||
match &self.state {
|
||||
WorktreeStoreState::Local { fs } => Some(fs.clone()),
|
||||
WorktreeStoreState::Remote { .. } => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue