Skip to content

Commit 5d0e220

Browse files
committed
Improve go to relevant file performance
By doing a walk over the tree of directories in the workpsace we improve the dir Glob time because it only checks for the closest test directory folder, instead of searching in all the files of the workspace.
1 parent 8cbd8f8 commit 5d0e220

File tree

2 files changed

+65
-4
lines changed

2 files changed

+65
-4
lines changed

lib/ruby_lsp/requests/go_to_relevant_file.rb

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,53 @@ def perform
3535

3636
#: -> Array[String]
3737
def find_relevant_paths
38-
candidate_paths = Dir.glob(File.join("**", relevant_filename_pattern))
38+
pattern = File.join(search_root, "**", relevant_filename_pattern)
39+
candidate_paths = Dir.glob(pattern)
40+
.uniq
41+
.map { |path| path.delete_prefix(@workspace_path).delete_prefix("/") }
42+
3943
return [] if candidate_paths.empty?
4044

4145
find_most_similar_with_jaccard(candidate_paths).map { File.join(@workspace_path, _1) }
4246
end
4347

48+
# Determine the search roots based on the closest test directories.
49+
# This scopes the search to reduce the number of files that need to be checked.
50+
#: -> String
51+
def search_root
52+
current_path = File.join(@workspace_path, @path)
53+
54+
current_dir = File.dirname(current_path)
55+
while current_dir != @workspace_path
56+
dir_basename = File.basename(current_dir)
57+
58+
# If current directory is a test directory, return its parent as search root
59+
if TEST_KEYWORDS.include?(dir_basename)
60+
return File.dirname(current_dir)
61+
end
62+
63+
# Search the test directories by walking up the directory tree
64+
begin
65+
contains_test_dir = Dir
66+
.entries(current_dir)
67+
.filter { |entry| TEST_KEYWORDS.include?(entry) }
68+
.any? { |entry| File.directory?(File.join(current_dir, entry)) }
69+
70+
return current_dir if contains_test_dir
71+
rescue Errno::EACCES, Errno::ENOENT
72+
# Skip directories we can't read
73+
end
74+
75+
# Move up one level
76+
parent_dir = File.dirname(current_dir)
77+
break if parent_dir == current_dir
78+
79+
current_dir = parent_dir
80+
end
81+
82+
@workspace_path
83+
end
84+
4485
#: -> String
4586
def relevant_filename_pattern
4687
input_basename = File.basename(@path, File.extname(@path))

test/requests/go_to_relevant_file_test.rb

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
class GoToRelevantFileTest < Minitest::Test
77
def test_when_input_is_test_file_returns_array_of_implementation_file_locations
8+
stub_directory_structure("/workspace/test/requests", has_test_dir: false)
89
stub_glob_pattern("**/go_to_relevant_file.rb", ["lib/ruby_lsp/requests/go_to_relevant_file.rb"])
910

1011
test_file_path = "/workspace/test/requests/go_to_relevant_file_test.rb"
@@ -15,8 +16,12 @@ def test_when_input_is_test_file_returns_array_of_implementation_file_locations
1516
end
1617

1718
def test_when_input_is_implementation_file_returns_array_of_test_file_locations
18-
pattern =
19-
"**/{{test_,spec_,integration_test_}go_to_relevant_file,go_to_relevant_file{_test,_spec,_integration_test}}.rb"
19+
stub_directory_structure("/workspace/lib/ruby_lsp/requests", has_test_dir: false)
20+
stub_directory_structure("/workspace/lib/ruby_lsp", has_test_dir: false)
21+
stub_directory_structure("/workspace/lib", has_test_dir: false)
22+
stub_directory_structure("/workspace", has_test_dir: true)
23+
24+
pattern = "**/{{test_,spec_,integration_test_}go_to_relevant_file,go_to_relevant_file{_test,_spec,_integration_test}}.rb"
2025
stub_glob_pattern(pattern, ["test/requests/go_to_relevant_file_test.rb"])
2126

2227
impl_path = "/workspace/lib/ruby_lsp/requests/go_to_relevant_file.rb"
@@ -149,6 +154,21 @@ def test_it_finds_integration_tests_for_implementation
149154
private
150155

151156
def stub_glob_pattern(pattern, matches)
152-
Dir.stubs(:glob).with(pattern).returns(matches)
157+
absolute_pattern = pattern.start_with?("/") ? pattern : "/workspace/#{pattern}"
158+
absolute_matches = matches.map { |match| match.start_with?("/") ? match : "/workspace/#{match}" }
159+
Dir.stubs(:glob).with(absolute_pattern).returns(absolute_matches)
160+
end
161+
162+
def stub_directory_structure(dir_path, has_test_dir:)
163+
File.stubs(:directory?).with(File.join(dir_path, "other_dir")).returns(true)
164+
165+
if has_test_dir
166+
Dir.stubs(:entries).with(dir_path).returns([".", "..", "test", "lib", "other_dir"])
167+
File.stubs(:directory?).with(File.join(dir_path, "test")).returns(true)
168+
File.stubs(:directory?).with(File.join(dir_path, "lib")).returns(true)
169+
else
170+
Dir.stubs(:entries).with(dir_path).returns([".", "..", "some_file.rb", "other_dir"])
171+
File.stubs(:directory?).with(File.join(dir_path, "some_file.rb")).returns(false)
172+
end
153173
end
154174
end

0 commit comments

Comments
 (0)