debugger: Show language icons in debug scenario picker (#30662)
We attempt to resolve the language name in this order 1. Based on debug adapter if they're for a singular language e.g. Delve 2. File extension if it exists 3. If a language name exists within a debug scenario's label In the future I want to use locators to also determine the language as well and refresh scenario list when a new scenario has been saved Release Notes: - N/A
This commit is contained in:
parent
9826b7b5c1
commit
f1fe505649
8 changed files with 115 additions and 14 deletions
|
@ -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,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue