search_text: Remove obsolete option allow_multiline_match

The obsolete option was only used in tests, where adjusting the `multiline` parameter
restored the tested functionality.
This commit is contained in:
Dominik Jain authored and Dominik Jain committed 2026-07-01 14:57:52 +02:00
1 parent 6e518b5f7c
commit f39906728d
2 files changed
+32 -61

No files matched your search

+24 -52
View File
@@ -141,7 +141,6 @@ def search_text(
pattern: str,
content: str | None = None,
source_file_path: str | None = None,
allow_multiline_match: bool = False,
context_lines_before: int = 0,
context_lines_after: int = 0,
is_glob: bool = False,
@@ -154,8 +153,6 @@ def search_text(
:param content: The text content to search. May be None if source_file_path is provided.
:param source_file_path: Optional path to the source file. If content is None,
this has to be passed and the file will be read.
:param allow_multiline_match: Whether to search across multiple lines. Currently, the default
option (False) is very inefficient, so it is recommended to set this to True.
:param context_lines_before: Number of context lines to include before matches
:param context_lines_after: Number of context lines to include after matches
:param is_glob: If True, pattern is treated as a glob-like pattern (e.g., "*.py", "test_??.py")
@@ -178,60 +175,36 @@ def search_text(
# Convert pattern to a compiled regex if it's a string
if is_glob:
pattern = glob_to_regex(pattern)
if allow_multiline_match:
# For multiline matches, optionally use DOTALL so '.' matches newlines
flags = (re.MULTILINE | re.DOTALL) if multiline else 0
compiled_pattern = re.compile(pattern, flags)
# Search across the entire content as a single string
for match in compiled_pattern.finditer(content):
start_pos = match.start()
end_pos = match.end()
# Find the line numbers for the start and end positions
start_line_num = content[:start_pos].count("\n")
end_line_num = content[:end_pos].count("\n")
# For multiline matches, optionally use DOTALL so '.' matches newlines
flags = (re.MULTILINE | re.DOTALL) if multiline else 0
compiled_pattern = re.compile(pattern, flags)
# Search across the entire content as a single string
for match in compiled_pattern.finditer(content):
start_pos = match.start()
end_pos = match.end()
# Calculate the range of lines to include in the context
context_start = max(0, start_line_num - context_lines_before)
context_end = min(total_lines - 1, end_line_num + context_lines_after)
# Find the line numbers for the start and end positions
start_line_num = content[:start_pos].count("\n")
end_line_num = content[:end_pos].count("\n")
# Create TextLine objects for the context
context_lines = []
for line_num in range(context_start, context_end + 1):
if context_start <= line_num < start_line_num:
match_type = LineType.BEFORE_MATCH
elif end_line_num < line_num <= context_end:
match_type = LineType.AFTER_MATCH
else:
match_type = LineType.MATCH
# Calculate the range of lines to include in the context
context_start = max(0, start_line_num - context_lines_before)
context_end = min(total_lines - 1, end_line_num + context_lines_after)
context_lines.append(TextLine(line_number=line_num, line_content=lines[line_num], match_type=match_type))
# Create TextLine objects for the context
context_lines = []
for line_num in range(context_start, context_end + 1):
if context_start <= line_num < start_line_num:
match_type = LineType.BEFORE_MATCH
elif end_line_num < line_num <= context_end:
match_type = LineType.AFTER_MATCH
else:
match_type = LineType.MATCH
matches.append(MatchedConsecutiveLines(lines=context_lines, source_file_path=source_file_path))
else:
# TODO: extremely inefficient! Since we currently don't use this option in SerenaAgent or LanguageServer,
# it is not urgent to fix, but should be either improved or the option should be removed.
# Search line by line, normal compile without DOTALL
compiled_pattern = re.compile(pattern)
for i, line in enumerate(lines):
if compiled_pattern.search(line):
# Calculate the range of lines to include in the context
context_start = max(0, i - context_lines_before)
context_end = min(total_lines - 1, i + context_lines_after)
context_lines.append(TextLine(line_number=line_num, line_content=lines[line_num], match_type=match_type))
# Create TextLine objects for the context
context_lines = []
for j in range(context_start, context_end + 1):
if j < i:
match_type = LineType.BEFORE_MATCH
elif j > i:
match_type = LineType.AFTER_MATCH
else:
match_type = LineType.MATCH
context_lines.append(TextLine(line_number=j, line_content=lines[j], match_type=match_type))
matches.append(MatchedConsecutiveLines(lines=context_lines, source_file_path=source_file_path))
matches.append(MatchedConsecutiveLines(lines=context_lines, source_file_path=source_file_path))
return matches
@@ -354,7 +327,6 @@ def search_files(
pattern,
content=file_content,
source_file_path=relative_path,
allow_multiline_match=True,
context_lines_before=context_lines_before,
context_lines_after=context_lines_after,
multiline=multiline,
+8 -9
View File
@@ -1,4 +1,3 @@
import re
from collections.abc import Callable
import pytest
@@ -49,7 +48,7 @@ class TestSearchText:
assert "def process" in matches[1].lines[0].line_content
assert "def filter" in matches[2].lines[0].line_content
def test_search_text_with_compiled_regex(self):
def test_search_text_with_regex_pattern2(self):
"""Test searching with a pre-compiled regex pattern."""
content = """
import os
@@ -66,8 +65,8 @@ class TestSearchText:
"""
# Search for variable assignments with a compiled regex
pattern = re.compile(r"^\s*[A-Z_]+ = .+$")
matches = search_text(pattern, content=content)
pattern = r"^\s*[A-Z_]+ = .*?$"
matches = search_text(pattern, content=content, multiline=True)
assert len(matches) == 2
assert "DEBUG = True" in matches[0].lines[0].line_content
@@ -117,7 +116,7 @@ class TestSearchText:
# Search for a pattern that spans multiple lines (if-else block)
pattern = r"if.*?else.*?return"
matches = search_text(pattern, content=content, allow_multiline_match=True)
matches = search_text(pattern, content=content)
assert len(matches) == 1
multiline_match = matches[0]
@@ -145,7 +144,7 @@ class TestSearchText:
"""
# Search with a glob pattern for all user methods
matches = search_text("*_user*", content=content, is_glob=True)
matches = search_text("*_user*", content=content, is_glob=True, multiline=False)
assert len(matches) == 3
assert "get_user" in matches[0].lines[0].line_content
@@ -170,7 +169,7 @@ class TestSearchText:
"""
# Search with a simplified glob pattern to find all isinstance occurrences
matches = search_text("*isinstance*", content=content, is_glob=True)
matches = search_text("*isinstance*", content=content, is_glob=True, multiline=False)
# Should match lines with isinstance(item, dict) and isinstance(item, list)
assert len(matches) >= 2
@@ -194,11 +193,11 @@ class TestSearchText:
print("value{bar}")
"""
matches_square = search_text(r"*\[42\]*", content=content, is_glob=True)
matches_square = search_text(r"*\[42\]*", content=content, is_glob=True, multiline=False)
assert len(matches_square) == 1
assert "[42]" in matches_square[0].lines[0].line_content
matches_curly = search_text("*{bar}*", content=content, is_glob=True)
matches_curly = search_text("*{bar}*", content=content, is_glob=True, multiline=False)
assert len(matches_curly) == 1
assert "{bar}" in matches_curly[0].lines[0].line_content