languages: Remove a eager conversion from LanguageName to String (#35667)

This PR changes the signature of `language_names` from

```rust
pub fn language_names(&self) -> Vec<String>
// Into
pub fn language_names(&self) -> Vec<LanguageName>
```

The function previously eagerly converted `LanguageName`'s to
`String`'s, which requires the reallocation of all of the elements. The
functions get called in many places in the code base, but only one of
which actually requires the conversion to a `String`. In one case it
would do a `SharedString` -> `String` -> `SharedString` conversion,
which is now totally bypassed.

Release Notes:

- N/A
This commit is contained in:
tidely 2025-08-05 23:46:57 +03:00 committed by GitHub
parent a508a9536f
commit c595ed19d6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 44 additions and 28 deletions

View file

@ -1015,15 +1015,13 @@ impl DebugDelegate {
let language_names = languages.language_names();
let language = dap_registry
.adapter_language(&scenario.adapter)
.map(|language| TaskSourceKind::Language {
name: language.into(),
});
.map(|language| TaskSourceKind::Language { name: language.0 });
let language = language.or_else(|| {
scenario.label.split_whitespace().find_map(|word| {
language_names
.iter()
.find(|name| name.eq_ignore_ascii_case(word))
.find(|name| name.as_ref().eq_ignore_ascii_case(word))
.map(|name| TaskSourceKind::Language {
name: name.to_owned().into(),
})

View file

@ -10,7 +10,7 @@ use fs::{FakeFs, Fs, RealFs};
use futures::{AsyncReadExt, StreamExt, io::BufReader};
use gpui::{AppContext as _, SemanticVersion, TestAppContext};
use http_client::{FakeHttpClient, Response};
use language::{BinaryStatus, LanguageMatcher, LanguageRegistry};
use language::{BinaryStatus, LanguageMatcher, LanguageName, LanguageRegistry};
use language_extension::LspAccess;
use lsp::LanguageServerName;
use node_runtime::NodeRuntime;
@ -306,7 +306,11 @@ async fn test_extension_store(cx: &mut TestAppContext) {
assert_eq!(
language_registry.language_names(),
["ERB", "Plain Text", "Ruby"]
[
LanguageName::new("ERB"),
LanguageName::new("Plain Text"),
LanguageName::new("Ruby"),
]
);
assert_eq!(
theme_registry.list_names(),
@ -458,7 +462,11 @@ async fn test_extension_store(cx: &mut TestAppContext) {
assert_eq!(
language_registry.language_names(),
["ERB", "Plain Text", "Ruby"]
[
LanguageName::new("ERB"),
LanguageName::new("Plain Text"),
LanguageName::new("Ruby"),
]
);
assert_eq!(
language_registry.grammar_names(),
@ -513,7 +521,10 @@ async fn test_extension_store(cx: &mut TestAppContext) {
assert_eq!(actual_language.hidden, expected_language.hidden);
}
assert_eq!(language_registry.language_names(), ["Plain Text"]);
assert_eq!(
language_registry.language_names(),
[LanguageName::new("Plain Text")]
);
assert_eq!(language_registry.grammar_names(), []);
});
}

View file

@ -2353,9 +2353,9 @@ mod tests {
assert_eq!(
languages.language_names(),
&[
"JSON".to_string(),
"Plain Text".to_string(),
"Rust".to_string(),
LanguageName::new("JSON"),
LanguageName::new("Plain Text"),
LanguageName::new("Rust"),
]
);
@ -2366,9 +2366,9 @@ mod tests {
assert_eq!(
languages.language_names(),
&[
"JSON".to_string(),
"Plain Text".to_string(),
"Rust".to_string(),
LanguageName::new("JSON"),
LanguageName::new("Plain Text"),
LanguageName::new("Rust"),
]
);
@ -2379,9 +2379,9 @@ mod tests {
assert_eq!(
languages.language_names(),
&[
"JSON".to_string(),
"Plain Text".to_string(),
"Rust".to_string(),
LanguageName::new("JSON"),
LanguageName::new("Plain Text"),
LanguageName::new("Rust"),
]
);

View file

@ -547,15 +547,15 @@ impl LanguageRegistry {
self.state.read().language_settings.clone()
}
pub fn language_names(&self) -> Vec<String> {
pub fn language_names(&self) -> Vec<LanguageName> {
let state = self.state.read();
let mut result = state
.available_languages
.iter()
.filter_map(|l| l.loaded.not().then_some(l.name.to_string()))
.chain(state.languages.iter().map(|l| l.config.name.to_string()))
.filter_map(|l| l.loaded.not().then_some(l.name.clone()))
.chain(state.languages.iter().map(|l| l.config.name.clone()))
.collect::<Vec<_>>();
result.sort_unstable_by_key(|language_name| language_name.to_lowercase());
result.sort_unstable_by_key(|language_name| language_name.as_ref().to_lowercase());
result
}

View file

@ -121,13 +121,13 @@ impl LanguageSelectorDelegate {
.into_iter()
.filter_map(|name| {
language_registry
.available_language_for_name(&name)?
.available_language_for_name(name.as_ref())?
.hidden()
.not()
.then_some(name)
})
.enumerate()
.map(|(candidate_id, name)| StringMatchCandidate::new(candidate_id, &name))
.map(|(candidate_id, name)| StringMatchCandidate::new(candidate_id, name.as_ref()))
.collect::<Vec<_>>();
Self {

View file

@ -269,7 +269,15 @@ impl JsonLspAdapter {
.await;
let config = cx.update(|cx| {
Self::get_workspace_config(self.languages.language_names().clone(), adapter_schemas, cx)
Self::get_workspace_config(
self.languages
.language_names()
.into_iter()
.map(|name| name.to_string())
.collect(),
adapter_schemas,
cx,
)
})?;
writer.replace(config.clone());
return Ok(config);

View file

@ -149,13 +149,12 @@ impl ScopeSelectorDelegate {
scope_selector: WeakEntity<ScopeSelector>,
language_registry: Arc<LanguageRegistry>,
) -> Self {
let candidates = Vec::from([GLOBAL_SCOPE_NAME.to_string()]).into_iter();
let languages = language_registry.language_names().into_iter();
let candidates = candidates
let candidates = std::iter::once(LanguageName::new(GLOBAL_SCOPE_NAME))
.chain(languages)
.enumerate()
.map(|(candidate_id, name)| StringMatchCandidate::new(candidate_id, &name))
.map(|(candidate_id, name)| StringMatchCandidate::new(candidate_id, name.as_ref()))
.collect::<Vec<_>>();
let mut existing_scopes = HashSet::new();

View file

@ -4439,7 +4439,7 @@ mod tests {
});
for name in languages.language_names() {
languages
.language_for_name(&name)
.language_for_name(name.as_ref())
.await
.with_context(|| format!("language name {name}"))
.unwrap();