Detailed changes
@@ -8,7 +8,7 @@ pub use dap_types::{StartDebuggingRequestArguments, StartDebuggingRequestArgumen
use futures::io::BufReader;
use gpui::{AsyncApp, SharedString};
pub use http_client::{HttpClient, github::latest_github_release};
-use language::LanguageToolchainStore;
+use language::{LanguageName, LanguageToolchainStore};
use node_runtime::NodeRuntime;
use serde::{Deserialize, Serialize};
use settings::WorktreeId;
@@ -418,6 +418,11 @@ pub trait DebugAdapter: 'static + Send + Sync {
user_installed_path: Option<PathBuf>,
cx: &mut AsyncApp,
) -> Result<DebugAdapterBinary>;
+
+ /// Returns the language name of an adapter if it only supports one language
+ fn adapter_language_name(&self) -> Option<LanguageName> {
+ None
+ }
}
#[cfg(any(test, feature = "test-support"))]
@@ -2,6 +2,7 @@ use anyhow::Result;
use async_trait::async_trait;
use collections::FxHashMap;
use gpui::{App, Global, SharedString};
+use language::LanguageName;
use parking_lot::RwLock;
use task::{DebugRequest, DebugScenario, SpawnInTerminal, TaskTemplate};
@@ -59,6 +60,11 @@ impl DapRegistry {
);
}
+ pub fn adapter_language(&self, adapter_name: &str) -> Option<LanguageName> {
+ self.adapter(adapter_name)
+ .and_then(|adapter| adapter.adapter_language_name())
+ }
+
pub fn add_locator(&self, locator: Arc<dyn DapLocator>) {
let _previous_value = self.0.write().locators.insert(locator.name(), locator);
debug_assert!(
@@ -1,5 +1,6 @@
use dap::{StartDebuggingRequestArguments, adapters::DebugTaskDefinition};
-use gpui::AsyncApp;
+use gpui::{AsyncApp, SharedString};
+use language::LanguageName;
use std::{collections::HashMap, ffi::OsStr, path::PathBuf};
use crate::*;
@@ -43,6 +44,10 @@ impl DebugAdapter for GoDebugAdapter {
DebugAdapterName(Self::ADAPTER_NAME.into())
}
+ fn adapter_language_name(&self) -> Option<LanguageName> {
+ Some(SharedString::new_static("Go").into())
+ }
+
async fn get_binary(
&self,
delegate: &dyn DapDelegate,
@@ -1,6 +1,7 @@
use adapters::latest_github_release;
use dap::adapters::{DebugTaskDefinition, TcpArguments};
-use gpui::AsyncApp;
+use gpui::{AsyncApp, SharedString};
+use language::LanguageName;
use std::{collections::HashMap, path::PathBuf, sync::OnceLock};
use util::ResultExt;
@@ -119,6 +120,10 @@ impl DebugAdapter for PhpDebugAdapter {
DebugAdapterName(Self::ADAPTER_NAME.into())
}
+ fn adapter_language_name(&self) -> Option<LanguageName> {
+ Some(SharedString::new_static("PHP").into())
+ }
+
async fn get_binary(
&self,
delegate: &dyn DapDelegate,
@@ -1,6 +1,7 @@
use crate::*;
use dap::{DebugRequest, StartDebuggingRequestArguments, adapters::DebugTaskDefinition};
-use gpui::AsyncApp;
+use gpui::{AsyncApp, SharedString};
+use language::LanguageName;
use std::{collections::HashMap, ffi::OsStr, path::PathBuf, sync::OnceLock};
use util::ResultExt;
@@ -165,6 +166,10 @@ impl DebugAdapter for PythonDebugAdapter {
DebugAdapterName(Self::ADAPTER_NAME.into())
}
+ fn adapter_language_name(&self) -> Option<LanguageName> {
+ Some(SharedString::new_static("Python").into())
+ }
+
async fn get_binary(
&self,
delegate: &dyn DapDelegate,
@@ -6,7 +6,8 @@ use dap::{
self, DapDelegate, DebugAdapter, DebugAdapterBinary, DebugAdapterName, DebugTaskDefinition,
},
};
-use gpui::AsyncApp;
+use gpui::{AsyncApp, SharedString};
+use language::LanguageName;
use std::path::PathBuf;
use util::command::new_smol_command;
@@ -25,6 +26,10 @@ impl DebugAdapter for RubyDebugAdapter {
DebugAdapterName(Self::ADAPTER_NAME.into())
}
+ fn adapter_language_name(&self) -> Option<LanguageName> {
+ Some(SharedString::new_static("Ruby").into())
+ }
+
async fn get_binary(
&self,
delegate: &dyn DapDelegate,
@@ -1,8 +1,10 @@
use collections::FxHashMap;
+use language::LanguageRegistry;
use std::{
borrow::Cow,
ops::Not,
path::{Path, PathBuf},
+ sync::Arc,
time::Duration,
usize,
};
@@ -81,6 +83,7 @@ impl NewSessionModal {
return;
};
let task_store = workspace.project().read(cx).task_store().clone();
+ let languages = workspace.app_state().languages.clone();
cx.spawn_in(window, async move |workspace, cx| {
workspace.update_in(cx, |workspace, window, cx| {
@@ -131,9 +134,12 @@ impl NewSessionModal {
}
this.launch_picker.update(cx, |picker, cx| {
- picker
- .delegate
- .task_contexts_loaded(task_contexts, window, cx);
+ picker.delegate.task_contexts_loaded(
+ task_contexts,
+ languages,
+ window,
+ cx,
+ );
picker.refresh(window, cx);
cx.notify();
});
@@ -944,9 +950,49 @@ impl DebugScenarioDelegate {
}
}
+ fn get_scenario_kind(
+ languages: &Arc<LanguageRegistry>,
+ dap_registry: &DapRegistry,
+ scenario: DebugScenario,
+ ) -> (Option<TaskSourceKind>, DebugScenario) {
+ let language_names = languages.language_names();
+ let language = dap_registry
+ .adapter_language(&scenario.adapter)
+ .map(|language| TaskSourceKind::Language {
+ name: language.into(),
+ });
+
+ let language = language.or_else(|| {
+ scenario
+ .request
+ .as_ref()
+ .and_then(|request| match request {
+ DebugRequest::Launch(launch) => launch
+ .program
+ .rsplit_once(".")
+ .and_then(|split| languages.language_name_for_extension(split.1))
+ .map(|name| TaskSourceKind::Language { name: name.into() }),
+ _ => None,
+ })
+ .or_else(|| {
+ scenario.label.split_whitespace().find_map(|word| {
+ language_names
+ .iter()
+ .find(|name| name.eq_ignore_ascii_case(word))
+ .map(|name| TaskSourceKind::Language {
+ name: name.to_owned().into(),
+ })
+ })
+ })
+ });
+
+ (language, scenario)
+ }
+
pub fn task_contexts_loaded(
&mut self,
task_contexts: TaskContexts,
+ languages: Arc<LanguageRegistry>,
_window: &mut Window,
cx: &mut Context<Picker<Self>>,
) {
@@ -967,14 +1013,16 @@ impl DebugScenarioDelegate {
self.last_used_candidate_index = Some(recent.len() - 1);
}
+ let dap_registry = cx.global::<DapRegistry>();
+
self.candidates = recent
.into_iter()
- .map(|scenario| (None, scenario))
- .chain(
- scenarios
- .into_iter()
- .map(|(kind, scenario)| (Some(kind), scenario)),
- )
+ .map(|scenario| Self::get_scenario_kind(&languages, &dap_registry, scenario))
+ .chain(scenarios.into_iter().map(|(kind, scenario)| {
+ let (language, scenario) =
+ Self::get_scenario_kind(&languages, &dap_registry, scenario);
+ (language.or(Some(kind)), scenario)
+ }))
.collect();
}
}
@@ -68,6 +68,12 @@ impl From<LanguageName> for SharedString {
}
}
+impl From<SharedString> for LanguageName {
+ fn from(value: SharedString) -> Self {
+ LanguageName(value)
+ }
+}
+
impl AsRef<str> for LanguageName {
fn as_ref(&self) -> &str {
self.0.as_ref()
@@ -627,6 +633,22 @@ impl LanguageRegistry {
async move { rx.await? }
}
+ pub fn language_name_for_extension(self: &Arc<Self>, extension: &str) -> Option<LanguageName> {
+ self.state.try_read().and_then(|state| {
+ state
+ .available_languages
+ .iter()
+ .find(|language| {
+ language
+ .matcher()
+ .path_suffixes
+ .iter()
+ .any(|suffix| *suffix == extension)
+ })
+ .map(|language| language.name.clone())
+ })
+ }
+
pub fn language_for_name_or_extension(
self: &Arc<Self>,
string: &str,