From ca9cc34a258cd34f9666f8a108fd35f76fa4cfd9 Mon Sep 17 00:00:00 2001 From: Yeongseok Lim Date: Wed, 25 Mar 2026 11:27:26 -0500 Subject: [PATCH] Prefer non-init workspace symbol results --- pyrefly/lib/lsp/non_wasm/workspace_symbols.rs | 2 + .../__init__.py | 6 ++ .../implementation.py | 8 +++ .../lsp/lsp_interaction/workspace_symbol.rs | 60 +++++++++++++++++++ 4 files changed, 76 insertions(+) create mode 100644 pyrefly/lib/test/lsp/lsp_interaction/test_files/tests_requiring_config/workspace_symbol_prefer_non_init/__init__.py create mode 100644 pyrefly/lib/test/lsp/lsp_interaction/test_files/tests_requiring_config/workspace_symbol_prefer_non_init/implementation.py diff --git a/pyrefly/lib/lsp/non_wasm/workspace_symbols.rs b/pyrefly/lib/lsp/non_wasm/workspace_symbols.rs index 34f88befe0..4f8b15fbe5 100644 --- a/pyrefly/lib/lsp/non_wasm/workspace_symbols.rs +++ b/pyrefly/lib/lsp/non_wasm/workspace_symbols.rs @@ -37,6 +37,8 @@ impl Transaction<'_> { result.push((name, kind, location)); } } + // Keep shared fuzzy ordering intact while preferring non-`__init__.py` matches here. + result.sort_by_key(|(_, _, location)| location.module.path().is_init()); Some(result) } } diff --git a/pyrefly/lib/test/lsp/lsp_interaction/test_files/tests_requiring_config/workspace_symbol_prefer_non_init/__init__.py b/pyrefly/lib/test/lsp/lsp_interaction/test_files/tests_requiring_config/workspace_symbol_prefer_non_init/__init__.py new file mode 100644 index 0000000000..8f47501eec --- /dev/null +++ b/pyrefly/lib/test/lsp/lsp_interaction/test_files/tests_requiring_config/workspace_symbol_prefer_non_init/__init__.py @@ -0,0 +1,6 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from .implementation import workspace_symbol_prefers_non_init_over_init_reexport diff --git a/pyrefly/lib/test/lsp/lsp_interaction/test_files/tests_requiring_config/workspace_symbol_prefer_non_init/implementation.py b/pyrefly/lib/test/lsp/lsp_interaction/test_files/tests_requiring_config/workspace_symbol_prefer_non_init/implementation.py new file mode 100644 index 0000000000..2ca32784c0 --- /dev/null +++ b/pyrefly/lib/test/lsp/lsp_interaction/test_files/tests_requiring_config/workspace_symbol_prefer_non_init/implementation.py @@ -0,0 +1,8 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + + +def workspace_symbol_prefers_non_init_over_init_reexport() -> None: + return diff --git a/pyrefly/lib/test/lsp/lsp_interaction/workspace_symbol.rs b/pyrefly/lib/test/lsp/lsp_interaction/workspace_symbol.rs index c07d913247..5721aa5361 100644 --- a/pyrefly/lib/test/lsp/lsp_interaction/workspace_symbol.rs +++ b/pyrefly/lib/test/lsp/lsp_interaction/workspace_symbol.rs @@ -6,6 +6,7 @@ */ use lsp_types::Url; +use lsp_types::WorkspaceSymbolResponse; use lsp_types::request::WorkspaceSymbolRequest; use serde_json::json; @@ -54,3 +55,62 @@ fn test_workspace_symbol() { interaction.shutdown().unwrap(); } + +#[test] +fn test_workspace_symbol_prefers_non_init_result() { + let root = get_test_files_root(); + let root_path = root.path().join("tests_requiring_config"); + let scope_uri = Url::from_file_path(root_path.clone()).unwrap(); + let mut interaction = LspInteraction::new(); + interaction.set_root(root_path.clone()); + interaction + .initialize(InitializeSettings { + workspace_folders: Some(vec![("test".to_owned(), scope_uri)]), + configuration: Some(Some(json!([{ "indexing_mode": "lazy_blocking"}]))), + ..Default::default() + }) + .unwrap(); + + interaction + .client + .did_open("workspace_symbol_prefer_non_init/implementation.py"); + interaction + .client + .did_open("workspace_symbol_prefer_non_init/__init__.py"); + + let implementation_uri = + Url::from_file_path(root_path.join("workspace_symbol_prefer_non_init/implementation.py")) + .unwrap(); + let init_uri = + Url::from_file_path(root_path.join("workspace_symbol_prefer_non_init/__init__.py")) + .unwrap(); + let symbol_name = "workspace_symbol_prefers_non_init_over_init_reexport"; + + interaction + .client + .send_request::(json!({ "query": symbol_name })) + .expect_response_with(|result| { + let Some(WorkspaceSymbolResponse::Flat(symbols)) = result else { + panic!("Unexpected workspace symbol response: {result:?}"); + }; + assert!(symbols.iter().all(|symbol| symbol.name == symbol_name)); + assert!(symbols.iter().all(|symbol| { + symbol.location.uri == implementation_uri || symbol.location.uri == init_uri + })); + + let first_init_index = symbols + .iter() + .position(|symbol| symbol.location.uri == init_uri) + .expect("expected at least one __init__.py result"); + let last_non_init_index = symbols + .iter() + .rposition(|symbol| symbol.location.uri == implementation_uri) + .expect("expected at least one non-__init__.py result"); + + assert!(last_non_init_index < first_init_index); + true + }) + .unwrap(); + + interaction.shutdown().unwrap(); +}