From 25632b979b4b4af076101e87568bb1f413caeb03 Mon Sep 17 00:00:00 2001 From: Finn Evers Date: Thu, 23 Jul 2026 11:22:43 +0000 Subject: [PATCH] language: Refactor `available_languages` into its own struct (#61388) This adds a dedicated `AvailableLanguages` struct in preparation for a more cabable language matching based on a given language config. No functional changes, just shuffling some code around for this round. Also made the LanguageMatcher non-cloneable in favor of wrapping it in an Arc, since cloning is rather expensive for this and having a reference is sufficient in all cases right now. Release Notes: - N/A --------- Co-authored-by: Ben Brandt --- crates/agent/src/tools/write_file_tool.rs | 5 +- crates/agent_ui/src/message_editor.rs | 5 +- .../tests/integration/integration_tests.rs | 20 +- .../random_project_collaboration_tests.rs | 5 +- .../remote_editing_collaboration_tests.rs | 5 +- crates/debugger_ui/src/tests/inline_values.rs | 25 +- crates/editor/src/code_lens.rs | 5 +- crates/editor/src/display_map.rs | 15 +- crates/editor/src/editor_tests.rs | 75 +-- .../editor/src/highlight_matching_bracket.rs | 5 +- crates/editor/src/inlays/inlay_hints.rs | 10 +- crates/editor/src/semantic_tokens.rs | 20 +- .../src/test/editor_lsp_test_context.rs | 13 +- crates/extension/src/extension_host_proxy.rs | 4 +- crates/extension_host/src/extension_host.rs | 2 +- .../src/extension_store_test.rs | 12 +- crates/git_ui/src/commit_view.rs | 4 +- crates/language/src/available_languages.rs | 367 +++++++++++++++ crates/language/src/buffer_tests.rs | 102 ++-- crates/language/src/language.rs | 20 +- crates/language/src/language_registry.rs | 443 ++++-------------- crates/language/src/runnable.rs | 5 +- .../src/syntax_map/syntax_map_tests.rs | 30 +- crates/language_core/src/language_config.rs | 6 +- .../src/language_extension.rs | 2 +- .../src/language_selector.rs | 5 +- .../language_tools/src/lsp_log_view_tests.rs | 5 +- crates/languages/src/lib.rs | 5 +- crates/markdown/src/markdown.rs | 5 +- crates/project/src/lsp_store.rs | 17 +- .../tests/integration/project_tests.rs | 25 +- crates/project_symbols/src/project_symbols.rs | 10 +- .../remote_server/src/remote_editing_tests.rs | 42 +- crates/repl/src/repl_sessions_ui.rs | 5 +- crates/tasks_ui/src/modal.rs | 15 +- 35 files changed, 763 insertions(+), 576 deletions(-) create mode 100644 crates/language/src/available_languages.rs diff --git a/crates/agent/src/tools/write_file_tool.rs b/crates/agent/src/tools/write_file_tool.rs index 7c0c789273..5956155694 100644 --- a/crates/agent/src/tools/write_file_tool.rs +++ b/crates/agent/src/tools/write_file_tool.rs @@ -537,10 +537,11 @@ mod tests { let rust_language = Arc::new(language::Language::new( language::LanguageConfig { name: "Rust".into(), - matcher: language::LanguageMatcher { + matcher: (language::LanguageMatcher { path_suffixes: vec!["rs".to_string()], ..Default::default() - }, + }) + .into(), ..Default::default() }, None, diff --git a/crates/agent_ui/src/message_editor.rs b/crates/agent_ui/src/message_editor.rs index e80c827459..f98625df4b 100644 --- a/crates/agent_ui/src/message_editor.rs +++ b/crates/agent_ui/src/message_editor.rs @@ -3468,10 +3468,11 @@ mod tests { let plain_text_language = Arc::new(language::Language::new( language::LanguageConfig { name: "Plain Text".into(), - matcher: language::LanguageMatcher { + matcher: (language::LanguageMatcher { path_suffixes: vec!["txt".to_string()], ..Default::default() - }, + }) + .into(), ..Default::default() }, None, diff --git a/crates/collab/tests/integration/integration_tests.rs b/crates/collab/tests/integration/integration_tests.rs index 4dcd4bb3e5..e6c377e3d4 100644 --- a/crates/collab/tests/integration/integration_tests.rs +++ b/crates/collab/tests/integration/integration_tests.rs @@ -2307,10 +2307,11 @@ async fn test_propagate_saves_and_fs_changes( let rust = Arc::new(Language::new( LanguageConfig { name: "Rust".into(), - matcher: LanguageMatcher { + matcher: (LanguageMatcher { path_suffixes: vec!["rs".to_string()], ..Default::default() - }, + }) + .into(), ..Default::default() }, Some(tree_sitter_rust::LANGUAGE.into()), @@ -2318,10 +2319,11 @@ async fn test_propagate_saves_and_fs_changes( let javascript = Arc::new(Language::new( LanguageConfig { name: "JavaScript".into(), - matcher: LanguageMatcher { + matcher: (LanguageMatcher { path_suffixes: vec!["js".to_string()], ..Default::default() - }, + }) + .into(), ..Default::default() }, Some(tree_sitter_rust::LANGUAGE.into()), @@ -4130,10 +4132,11 @@ async fn test_collaborating_with_diagnostics( client_a.language_registry().add(Arc::new(Language::new( LanguageConfig { name: "Rust".into(), - matcher: LanguageMatcher { + matcher: (LanguageMatcher { path_suffixes: vec!["rs".to_string()], ..Default::default() - }, + }) + .into(), ..Default::default() }, Some(tree_sitter_rust::LANGUAGE.into()), @@ -4846,10 +4849,11 @@ async fn test_prettier_formatting_buffer( client_a.language_registry().add(Arc::new(Language::new( LanguageConfig { name: "TypeScript".into(), - matcher: LanguageMatcher { + matcher: (LanguageMatcher { path_suffixes: vec!["ts".to_string()], ..Default::default() - }, + }) + .into(), ..Default::default() }, Some(tree_sitter_typescript::LANGUAGE_TYPESCRIPT.into()), diff --git a/crates/collab/tests/integration/random_project_collaboration_tests.rs b/crates/collab/tests/integration/random_project_collaboration_tests.rs index 391cef208d..d8e66e7a5e 100644 --- a/crates/collab/tests/integration/random_project_collaboration_tests.rs +++ b/crates/collab/tests/integration/random_project_collaboration_tests.rs @@ -1047,10 +1047,11 @@ impl RandomizedTest for ProjectCollaborationTest { client.language_registry().add(Arc::new(Language::new( LanguageConfig { name: "Rust".into(), - matcher: LanguageMatcher { + matcher: (LanguageMatcher { path_suffixes: vec!["rs".to_string()], ..Default::default() - }, + }) + .into(), ..Default::default() }, None, diff --git a/crates/collab/tests/integration/remote_editing_collaboration_tests.rs b/crates/collab/tests/integration/remote_editing_collaboration_tests.rs index 3da8fbe650..d039bce3b3 100644 --- a/crates/collab/tests/integration/remote_editing_collaboration_tests.rs +++ b/crates/collab/tests/integration/remote_editing_collaboration_tests.rs @@ -686,10 +686,11 @@ async fn test_ssh_collaboration_formatting_with_prettier( let ts_lang = Arc::new(Language::new( LanguageConfig { name: "TypeScript".into(), - matcher: LanguageMatcher { + matcher: (LanguageMatcher { path_suffixes: vec!["ts".to_string()], ..LanguageMatcher::default() - }, + }) + .into(), ..LanguageConfig::default() }, Some(tree_sitter_typescript::LANGUAGE_TYPESCRIPT.into()), diff --git a/crates/debugger_ui/src/tests/inline_values.rs b/crates/debugger_ui/src/tests/inline_values.rs index c82276d824..713d2930ef 100644 --- a/crates/debugger_ui/src/tests/inline_values.rs +++ b/crates/debugger_ui/src/tests/inline_values.rs @@ -1831,10 +1831,11 @@ fn python_lang() -> Language { Language::new( LanguageConfig { name: "Python".into(), - matcher: LanguageMatcher { + matcher: (LanguageMatcher { path_suffixes: vec!["py".to_string()], ..Default::default() - }, + }) + .into(), ..Default::default() }, Some(tree_sitter_python::LANGUAGE.into()), @@ -1849,10 +1850,11 @@ fn go_lang() -> Arc { Language::new( LanguageConfig { name: "Go".into(), - matcher: LanguageMatcher { + matcher: (LanguageMatcher { path_suffixes: vec!["go".to_string()], ..Default::default() - }, + }) + .into(), ..Default::default() }, Some(tree_sitter_go::LANGUAGE.into()), @@ -2268,10 +2270,11 @@ fn javascript_lang() -> Arc { Language::new( LanguageConfig { name: "JavaScript".into(), - matcher: LanguageMatcher { + matcher: (LanguageMatcher { path_suffixes: vec!["js".to_string()], ..Default::default() - }, + }) + .into(), ..Default::default() }, Some(tree_sitter_typescript::LANGUAGE_TYPESCRIPT.into()), @@ -2287,10 +2290,11 @@ fn typescript_lang() -> Arc { Language::new( LanguageConfig { name: "TypeScript".into(), - matcher: LanguageMatcher { + matcher: (LanguageMatcher { path_suffixes: vec!["ts".to_string()], ..Default::default() - }, + }) + .into(), ..Default::default() }, Some(tree_sitter_typescript::LANGUAGE_TYPESCRIPT.into()), @@ -2306,10 +2310,11 @@ fn tsx_lang() -> Arc { Language::new( LanguageConfig { name: "TSX".into(), - matcher: LanguageMatcher { + matcher: (LanguageMatcher { path_suffixes: vec!["tsx".to_string()], ..Default::default() - }, + }) + .into(), ..Default::default() }, Some(tree_sitter_typescript::LANGUAGE_TSX.into()), diff --git a/crates/editor/src/code_lens.rs b/crates/editor/src/code_lens.rs index 7e03e39255..d8bd285e15 100644 --- a/crates/editor/src/code_lens.rs +++ b/crates/editor/src/code_lens.rs @@ -1709,10 +1709,11 @@ mod tests { language_registry.add(Arc::new(language::Language::new( language::LanguageConfig { name: "TypeScript".into(), - matcher: language::LanguageMatcher { + matcher: (language::LanguageMatcher { path_suffixes: vec!["ts".to_string()], ..language::LanguageMatcher::default() - }, + }) + .into(), ..language::LanguageConfig::default() }, Some(tree_sitter_typescript::LANGUAGE_TYPESCRIPT.into()), diff --git a/crates/editor/src/display_map.rs b/crates/editor/src/display_map.rs index ecc41ae29b..6a38ac4d33 100644 --- a/crates/editor/src/display_map.rs +++ b/crates/editor/src/display_map.rs @@ -3269,10 +3269,11 @@ pub mod tests { Language::new( LanguageConfig { name: "Test".into(), - matcher: LanguageMatcher { + matcher: (LanguageMatcher { path_suffixes: vec![".test".to_string()], ..Default::default() - }, + }) + .into(), ..Default::default() }, Some(tree_sitter_rust::LANGUAGE.into()), @@ -3717,10 +3718,11 @@ pub mod tests { Language::new( LanguageConfig { name: "Test".into(), - matcher: LanguageMatcher { + matcher: (LanguageMatcher { path_suffixes: vec![".test".to_string()], ..Default::default() - }, + }) + .into(), ..Default::default() }, Some(tree_sitter_rust::LANGUAGE.into()), @@ -3804,10 +3806,11 @@ pub mod tests { Language::new( LanguageConfig { name: "Test".into(), - matcher: LanguageMatcher { + matcher: (LanguageMatcher { path_suffixes: vec![".test".to_string()], ..Default::default() - }, + }) + .into(), ..Default::default() }, Some(tree_sitter_rust::LANGUAGE.into()), diff --git a/crates/editor/src/editor_tests.rs b/crates/editor/src/editor_tests.rs index 3a6d2436e2..b81634785a 100644 --- a/crates/editor/src/editor_tests.rs +++ b/crates/editor/src/editor_tests.rs @@ -17239,10 +17239,11 @@ async fn test_document_format_manual_trigger(cx: &mut TestAppContext) { language_registry.add(Arc::new(Language::new( LanguageConfig { name: "Rust".into(), - matcher: LanguageMatcher { + matcher: (LanguageMatcher { path_suffixes: vec!["rs".to_string()], ..Default::default() - }, + }) + .into(), ..LanguageConfig::default() }, Some(tree_sitter_rust::LANGUAGE.into()), @@ -17690,10 +17691,11 @@ async fn test_organize_imports_manual_trigger(cx: &mut TestAppContext) { language_registry.add(Arc::new(Language::new( LanguageConfig { name: "TypeScript".into(), - matcher: LanguageMatcher { + matcher: (LanguageMatcher { path_suffixes: vec!["ts".to_string()], ..Default::default() - }, + }) + .into(), ..LanguageConfig::default() }, Some(tree_sitter_typescript::LANGUAGE_TYPESCRIPT.into()), @@ -21133,10 +21135,11 @@ async fn test_multiline_completion(cx: &mut TestAppContext) { let typescript_language = Arc::new(Language::new( LanguageConfig { name: "TypeScript".into(), - matcher: LanguageMatcher { + matcher: (LanguageMatcher { path_suffixes: vec!["ts".to_string()], ..LanguageMatcher::default() - }, + }) + .into(), line_comments: vec!["// ".into()], ..LanguageConfig::default() }, @@ -23944,10 +23947,11 @@ async fn test_on_type_formatting_not_triggered(cx: &mut TestAppContext) { language_registry.add(Arc::new(Language::new( LanguageConfig { name: "Rust".into(), - matcher: LanguageMatcher { + matcher: (LanguageMatcher { path_suffixes: vec!["rs".to_string()], ..Default::default() - }, + }) + .into(), brackets: BracketPairConfig { pairs: vec![BracketPair { start: "{".to_string(), @@ -24119,10 +24123,11 @@ async fn test_language_server_restart_due_to_settings_change(cx: &mut TestAppCon language_registry.add(Arc::new(Language::new( LanguageConfig { name: language_name.clone(), - matcher: LanguageMatcher { + matcher: (LanguageMatcher { path_suffixes: vec!["rs".to_string()], ..Default::default() - }, + }) + .into(), ..Default::default() }, Some(tree_sitter_rust::LANGUAGE.into()), @@ -25308,10 +25313,11 @@ async fn test_completions_in_languages_with_extra_word_characters(cx: &mut TestA let mut cx = EditorLspTestContext::new( Language::new( LanguageConfig { - matcher: LanguageMatcher { + matcher: (LanguageMatcher { path_suffixes: vec!["jsx".into()], ..Default::default() - }, + }) + .into(), overrides: [( "element".into(), LanguageConfigOverride { @@ -25423,10 +25429,11 @@ async fn test_document_format_with_prettier(cx: &mut TestAppContext) { language_registry.add(Arc::new(Language::new( LanguageConfig { name: "TypeScript".into(), - matcher: LanguageMatcher { + matcher: (LanguageMatcher { path_suffixes: vec!["ts".to_string()], ..Default::default() - }, + }) + .into(), ..Default::default() }, Some(tree_sitter_typescript::LANGUAGE_TYPESCRIPT.into()), @@ -25513,10 +25520,11 @@ async fn test_document_format_with_prettier_explicit_language(cx: &mut TestAppCo let ts_lang = Arc::new(Language::new( LanguageConfig { name: "TypeScript".into(), - matcher: LanguageMatcher { + matcher: (LanguageMatcher { path_suffixes: vec!["ts".to_string()], ..LanguageMatcher::default() - }, + }) + .into(), prettier_parser_name: Some("typescript".to_string()), ..LanguageConfig::default() }, @@ -25615,10 +25623,11 @@ async fn test_range_format_with_prettier(cx: &mut TestAppContext) { language_registry.add(Arc::new(Language::new( LanguageConfig { name: "TypeScript".into(), - matcher: LanguageMatcher { + matcher: (LanguageMatcher { path_suffixes: vec!["ts".to_string()], ..Default::default() - }, + }) + .into(), ..Default::default() }, Some(tree_sitter_typescript::LANGUAGE_TYPESCRIPT.into()), @@ -25691,10 +25700,11 @@ async fn test_range_format_with_prettier_explicit_language(cx: &mut TestAppConte let ts_lang = Arc::new(Language::new( LanguageConfig { name: "TypeScript".into(), - matcher: LanguageMatcher { + matcher: (LanguageMatcher { path_suffixes: vec!["ts".to_string()], ..LanguageMatcher::default() - }, + }) + .into(), prettier_parser_name: Some("typescript".to_string()), ..LanguageConfig::default() }, @@ -32802,10 +32812,11 @@ async fn test_apply_code_lens_actions_with_commands(cx: &mut gpui::TestAppContex language_registry.add(Arc::new(Language::new( LanguageConfig { name: "TypeScript".into(), - matcher: LanguageMatcher { + matcher: (LanguageMatcher { path_suffixes: vec!["ts".to_string()], ..Default::default() - }, + }) + .into(), ..Default::default() }, Some(tree_sitter_typescript::LANGUAGE_TYPESCRIPT.into()), @@ -33566,10 +33577,11 @@ async fn test_html_linked_edits_on_completion(cx: &mut TestAppContext) { let html_language = Arc::new(Language::new( LanguageConfig { name: "HTML".into(), - matcher: LanguageMatcher { + matcher: (LanguageMatcher { path_suffixes: vec!["html".to_string()], ..LanguageMatcher::default() - }, + }) + .into(), brackets: BracketPairConfig { pairs: vec![BracketPair { start: "<".into(), @@ -33689,10 +33701,11 @@ async fn test_linked_edits_on_typing_punctuation(cx: &mut TestAppContext) { let language = Arc::new(Language::new( LanguageConfig { name: "TSX".into(), - matcher: LanguageMatcher { + matcher: (LanguageMatcher { path_suffixes: vec!["tsx".to_string()], ..LanguageMatcher::default() - }, + }) + .into(), brackets: BracketPairConfig { pairs: vec![BracketPair { start: "<".into(), @@ -33760,10 +33773,11 @@ async fn test_linked_edits_on_typing_dot_without_language_override(cx: &mut Test let language = Arc::new(Language::new( LanguageConfig { name: "HTML".into(), - matcher: LanguageMatcher { + matcher: (LanguageMatcher { path_suffixes: vec!["html".to_string()], ..LanguageMatcher::default() - }, + }) + .into(), brackets: BracketPairConfig { pairs: vec![BracketPair { start: "<".into(), @@ -41519,10 +41533,11 @@ async fn test_tsx_nested_jsx_member_expression_highlights(cx: &mut TestAppContex Language::new( LanguageConfig { name: "TSX".into(), - matcher: LanguageMatcher { + matcher: (LanguageMatcher { path_suffixes: vec!["tsx".to_string()], ..LanguageMatcher::default() - }, + }) + .into(), ..LanguageConfig::default() }, Some(tree_sitter_typescript::LANGUAGE_TSX.into()), diff --git a/crates/editor/src/highlight_matching_bracket.rs b/crates/editor/src/highlight_matching_bracket.rs index 15db878791..a0b0ee37b9 100644 --- a/crates/editor/src/highlight_matching_bracket.rs +++ b/crates/editor/src/highlight_matching_bracket.rs @@ -99,10 +99,11 @@ mod tests { Language::new( LanguageConfig { name: "Rust".into(), - matcher: LanguageMatcher { + matcher: (LanguageMatcher { path_suffixes: vec!["rs".to_string()], ..Default::default() - }, + }) + .into(), brackets: BracketPairConfig { pairs: vec![ BracketPair { diff --git a/crates/editor/src/inlays/inlay_hints.rs b/crates/editor/src/inlays/inlay_hints.rs index de634f467f..de657c4aa6 100644 --- a/crates/editor/src/inlays/inlay_hints.rs +++ b/crates/editor/src/inlays/inlay_hints.rs @@ -1402,10 +1402,11 @@ pub mod tests { language_registry.add(Arc::new(Language::new( LanguageConfig { name: name.into(), - matcher: LanguageMatcher { + matcher: (LanguageMatcher { path_suffixes: vec![path_suffix.to_string()], ..Default::default() - }, + }) + .into(), ..Default::default() }, Some(tree_sitter_rust::LANGUAGE.into()), @@ -4636,10 +4637,11 @@ let c = 3;"# language_registry.add(Arc::new(Language::new( LanguageConfig { name: name.into(), - matcher: LanguageMatcher { + matcher: (LanguageMatcher { path_suffixes: vec![path_suffix.to_string()], ..Default::default() - }, + }) + .into(), ..Default::default() }, Some(tree_sitter_rust::LANGUAGE.into()), diff --git a/crates/editor/src/semantic_tokens.rs b/crates/editor/src/semantic_tokens.rs index 0790712f5e..0d8006aad2 100644 --- a/crates/editor/src/semantic_tokens.rs +++ b/crates/editor/src/semantic_tokens.rs @@ -859,10 +859,11 @@ mod tests { let toml_language = Arc::new(Language::new( LanguageConfig { name: "TOML".into(), - matcher: LanguageMatcher { + matcher: (LanguageMatcher { path_suffixes: vec!["toml".into()], ..LanguageMatcher::default() - }, + }) + .into(), ..LanguageConfig::default() }, None, @@ -1086,10 +1087,11 @@ mod tests { let toml_language = Arc::new(Language::new( LanguageConfig { name: "TOML".into(), - matcher: LanguageMatcher { + matcher: (LanguageMatcher { path_suffixes: vec!["toml".into()], ..LanguageMatcher::default() - }, + }) + .into(), ..LanguageConfig::default() }, None, @@ -1097,10 +1099,11 @@ mod tests { let rust_language = Arc::new(Language::new( LanguageConfig { name: "Rust".into(), - matcher: LanguageMatcher { + matcher: (LanguageMatcher { path_suffixes: vec!["rs".into()], ..LanguageMatcher::default() - }, + }) + .into(), ..LanguageConfig::default() }, None, @@ -1375,10 +1378,11 @@ mod tests { let rust_language = Arc::new(Language::new( LanguageConfig { name: "Rust".into(), - matcher: LanguageMatcher { + matcher: (LanguageMatcher { path_suffixes: vec!["rs".into()], ..LanguageMatcher::default() - }, + }) + .into(), ..LanguageConfig::default() }, None, diff --git a/crates/editor/src/test/editor_lsp_test_context.rs b/crates/editor/src/test/editor_lsp_test_context.rs index 854a800d71..b248c090e1 100644 --- a/crates/editor/src/test/editor_lsp_test_context.rs +++ b/crates/editor/src/test/editor_lsp_test_context.rs @@ -177,10 +177,10 @@ impl EditorLspTestContext { let language = Language::new( LanguageConfig { name: "Typescript".into(), - matcher: LanguageMatcher { + matcher: (LanguageMatcher { path_suffixes: vec!["ts".to_string()], ..Default::default() - }, + }).into(), brackets: language::BracketPairConfig { pairs: vec![language::BracketPair { start: "{".to_string(), @@ -282,10 +282,10 @@ impl EditorLspTestContext { let language = Language::new( LanguageConfig { name: "TSX".into(), - matcher: LanguageMatcher { + matcher: (LanguageMatcher { path_suffixes: vec!["tsx".to_string()], ..Default::default() - }, + }).into(), brackets: language::BracketPairConfig { pairs: vec![language::BracketPair { start: "{".to_string(), @@ -390,10 +390,11 @@ impl EditorLspTestContext { let language = Language::new( LanguageConfig { name: "HTML".into(), - matcher: LanguageMatcher { + matcher: (LanguageMatcher { path_suffixes: vec!["html".into()], ..Default::default() - }, + }) + .into(), block_comment: Some(BlockCommentConfig { start: "