From 654b949bde7627acdf4a67f362af3daa1c32d954 Mon Sep 17 00:00:00 2001 From: Dominik Jain Date: Sun, 22 Jun 2025 19:36:04 +0200 Subject: [PATCH 01/14] Simplify insertion logic for InsertBefore|AfterSymbolTool (LLM provides full indentation; ensure suitable whitespace before/after) --- src/serena/agent.py | 15 +++++++-------- src/serena/resources/config/modes/editing.yml | 3 +-- src/serena/symbol.py | 19 ++++++++++++------- 3 files changed, 20 insertions(+), 17 deletions(-) diff --git a/src/serena/agent.py b/src/serena/agent.py index ef6e2264..f2c740d5 100644 --- a/src/serena/agent.py +++ b/src/serena/agent.py @@ -1744,16 +1744,16 @@ class InsertAfterSymbolTool(Tool, ToolMarkerCanEdit): Inserts the given body/content after the end of the definition of the given symbol (via the symbol's location). A typical use case is to insert a new class, function, method, field or variable assignment. - :param name_path: for finding the symbol to insert after, same logic as in the `find_symbol` tool. + :param name_path: name path of the symbol after which to insert content (definitions in the `find_symbol` tool apply) :param relative_path: the relative path to the file containing the symbol - :param body: the body/content to be inserted. Important: the inserted code will automatically have the - same indentation as the symbol's body, so you do not need to provide any additional indentation. + :param body: the body/content to be inserted. The inserted code shall begin with the next line after + the symbol. """ self.symbol_manager.insert_after_symbol( name_path, relative_file_path=relative_path, body=body, - use_same_indentation=True, + use_same_indentation=False, ) return SUCCESS_RESULT @@ -1774,16 +1774,15 @@ class InsertBeforeSymbolTool(Tool, ToolMarkerCanEdit): A typical use case is to insert a new class, function, method, field or variable assignment. It also can be used to insert a new import statement before the first symbol in the file. - :param name_path: for finding the symbol to insert before, same logic as in the `find_symbol` tool. + :param name_path: name path of the symbol before which to insert content (definitions in the `find_symbol` tool apply) :param relative_path: the relative path to the file containing the symbol - :param body: the body/content to be inserted. Important: the inserted code will automatically have the - same indentation as the symbol's body, so you do not need to provide any additional indentation. + :param body: the body/content to be inserted before the line in which the referenced symbol is defined """ self.symbol_manager.insert_before_symbol( name_path, relative_file_path=relative_path, body=body, - use_same_indentation=True, + use_same_indentation=False, ) return SUCCESS_RESULT diff --git a/src/serena/resources/config/modes/editing.yml b/src/serena/resources/config/modes/editing.yml index b50d3a53..a0ba5f7a 100644 --- a/src/serena/resources/config/modes/editing.yml +++ b/src/serena/resources/config/modes/editing.yml @@ -23,8 +23,7 @@ prompt: | use `find_symbol` with the name path `Foo/__init__` and `include_body=True`. If you don't know yet which methods in `Foo` you need to read or edit, you can use `find_symbol` with the name path `Foo`, `include_body=False` and `depth=1` to get all (top-level) methods of `Foo` before proceeding to read the desired methods with `include_body=True`. - Note that you never need to add additional indentation, as all symbol editing tools will automatically add the indentation of the symbol that - you are replacing or inserting above or below. In particular, keep in mind the description of the `replace_symbol_body` tool. If you want to add some new code at the end of the file, you should + In particular, keep in mind the description of the `replace_symbol_body` tool. If you want to add some new code at the end of the file, you should use the `insert_after_symbol` tool with the last top-level symbol in the file. If you want to add an import, often a good strategy is to use `insert_before_symbol` with the first top-level symbol in the file. You can understand relationships between symbols by using the `find_referencing_symbols` tool. If not explicitly requested otherwise by a user, diff --git a/src/serena/symbol.py b/src/serena/symbol.py index f7cb194c..66df7aaa 100644 --- a/src/serena/symbol.py +++ b/src/serena/symbol.py @@ -751,11 +751,16 @@ class SymbolManager: raise ValueError(f"Symbol at {location} does not have a defined end position.") line, col = pos["line"], pos["character"] + if at_new_line: - line += 1 + # start at beginning of next line col = 0 - if not body.startswith("\n"): - body = "\n" + body + line += 1 + # make sure there is one empty line before the new symbol + body = "\n" + body.lstrip("\n") + # make sure the one line break succeeding the original symbol, which we repurposed as prefix, is replaced + body = body.rstrip("\n") + "\n" + if use_same_indentation: symbol_start_pos = symbol.body_start_position assert symbol_start_pos is not None, f"Symbol at {location=} does not have a defined start position." @@ -822,16 +827,16 @@ class SymbolManager: raise ValueError(f"Symbol at {location} does not have a defined start position.") line = symbol_start_pos["line"] col = symbol_start_pos["character"] + if use_same_indentation: indent = " " * (col) body = "\n".join(indent + line for line in body.splitlines()) - # similar problems as in insert_after_symbol_at_location, see comment there if at_new_line: col = 0 - line -= 1 - if not body.endswith("\n"): - body += "\n" + # ensure two newlines after inserted body (eol + empty line) + body = body.rstrip() + "\n\n" + assert location.relative_path is not None self._lang_server.insert_text_at_position(location.relative_path, line=line, column=col, text_to_be_inserted=body) From 6b8b103deda86cd9f6b5c993fc3e02fbf07a28fa Mon Sep 17 00:00:00 2001 From: Dominik Jain Date: Sun, 22 Jun 2025 19:50:36 +0200 Subject: [PATCH 02/14] TextUtils: Allow insertion in new line after full text, adding missing newline at end of file --- src/multilspy/multilspy_utils.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/multilspy/multilspy_utils.py b/src/multilspy/multilspy_utils.py index 20959c4e..8c54cd69 100644 --- a/src/multilspy/multilspy_utils.py +++ b/src/multilspy/multilspy_utils.py @@ -20,6 +20,10 @@ from multilspy.multilspy_logger import MultilspyLogger from multilspy.multilspy_types import UnifiedSymbolInformation +class InvalidTextLocationError(Exception): + pass + + class TextUtils: """ Utilities for text operations. @@ -49,7 +53,8 @@ class TextUtils: """ idx = 0 while line > 0: - assert idx < len(text), (idx, len(text), text) + if idx >= len(text): + raise InvalidTextLocationError() if text[idx] == "\n": line -= 1 idx += 1 @@ -88,7 +93,17 @@ class TextUtils: Inserts the given text at the given line and column. Returns the modified text and the new line and column. """ - change_index = TextUtils.get_index_from_line_col(text, line, col) + try: + change_index = TextUtils.get_index_from_line_col(text, line, col) + except InvalidTextLocationError as e: + num_lines_in_text = text.count("\n") + 1 + max_line = num_lines_in_text - 1 + if line == max_line + 1 and col == 0: # trying to insert at new line after full text + # insert at end, adding missing newline + change_index = len(text) + text_to_be_inserted = "\n" + text_to_be_inserted + else: + raise new_text = text[:change_index] + text_to_be_inserted + text[change_index:] new_l, new_c = TextUtils._get_updated_position_from_line_and_column_and_edit(line, col, text_to_be_inserted) return new_text, new_l, new_c From 122e99e8c336ffea0af06ce57f22f8686f001a54 Mon Sep 17 00:00:00 2001 From: Dominik Jain Date: Sun, 22 Jun 2025 20:08:36 +0200 Subject: [PATCH 03/14] Simplify ReplaceSymbolBodyTool, making the LLM provide the indentation, and fix the tool inserting additional line breaks (there should be no whitespace changes whatsoever before/after the inserted content) --- src/serena/agent.py | 17 +++-------------- src/serena/symbol.py | 8 +++++--- 2 files changed, 8 insertions(+), 17 deletions(-) diff --git a/src/serena/agent.py b/src/serena/agent.py index f2c740d5..b51285eb 100644 --- a/src/serena/agent.py +++ b/src/serena/agent.py @@ -1704,27 +1704,16 @@ class ReplaceSymbolBodyTool(Tool, ToolMarkerCanEdit): r""" Replaces the body of the symbol with the given `name_path`. - Important: - You don't need to provide an adjusted indentation, - as the tool will automatically add the indentation of the original symbol to each line. For example, - for replacing a method in python, you can just write (using the standard python indentation): - body="def my_method_replacement(self, ...):\n first_line\n second_line...". So each line after the first line only has - an indentation of 4 (the indentation relative to the first character), - since the additional indentation will be added by the tool. Same for more deeply nested - cases. You always only need to write the relative indentation to the first character of the first line, and that - in turn should not have any indentation. - ALWAYS REMEMBER TO USE THE CORRECT INDENTATION IN THE BODY! - :param name_path: for finding the symbol to replace, same logic as in the `find_symbol` tool. :param relative_path: the relative path to the file containing the symbol - :param body: the new symbol body. - + :param body: the new symbol body. Important: Begin directly with the symbol definition and provide no + leading indentation for the first line (but do indent the rest of the body according to the context). """ self.symbol_manager.replace_body( name_path, relative_file_path=relative_path, body=body, - use_same_indentation=True, + use_same_indentation=False, ) return SUCCESS_RESULT diff --git a/src/serena/symbol.py b/src/serena/symbol.py index 66df7aaa..af1810de 100644 --- a/src/serena/symbol.py +++ b/src/serena/symbol.py @@ -689,14 +689,16 @@ class SymbolManager: if start_pos is None or end_pos is None: raise ValueError(f"Symbol at {location} does not have a defined body range.") start_line, start_col = start_pos["line"], start_pos["character"] + if use_same_indentation: indent = " " * start_col body_lines = body.splitlines() body = body_lines[0] + "\n" + "\n".join(indent + line for line in body_lines[1:]) - # make sure body always ends with at least one newline - if not body.endswith("\n"): - body += "\n" + # make sure the replacement adds no additional newlines (before or after) - all newlines + # and whitespace before/after should remain the same, so we strip it entirely + body = body.strip() + self._lang_server.delete_text_between_positions(location.relative_path, start_pos, end_pos) self._lang_server.insert_text_at_position(location.relative_path, start_line, start_col, body) From 8837635f55242a89132cddb2d01ac42382061edf Mon Sep 17 00:00:00 2001 From: Dominik Jain Date: Sun, 22 Jun 2025 23:16:43 +0200 Subject: [PATCH 04/14] Make syrupy diffs render correctly in IntelliJ/PyCharm --- pytest.ini | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 pytest.ini diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 00000000..22e867b9 --- /dev/null +++ b/pytest.ini @@ -0,0 +1,2 @@ +[pytest] +addopts = --snapshot-patch-pycharm-diff From 4a50c6ec61951228b03c0a60e9a18dea82c2d551 Mon Sep 17 00:00:00 2001 From: Dominik Jain Date: Sun, 22 Jun 2025 23:35:58 +0200 Subject: [PATCH 05/14] Further improve InsertBefore|AfterSymbolTool by handling empty lines depending on the symbol type --- src/serena/symbol.py | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/serena/symbol.py b/src/serena/symbol.py index af1810de..35d73b81 100644 --- a/src/serena/symbol.py +++ b/src/serena/symbol.py @@ -256,6 +256,13 @@ class Symbol(ToStringMixin): def symbol_kind(self) -> SymbolKind: return self.symbol_root["kind"] + def is_neighbouring_definition_separated_by_empty_line(self) -> bool: + """ + :return: whether a symbol definition of this symbol's kind is usually separated from the + previous/next definition by at least one empty line. + """ + return self.symbol_kind in (SymbolKind.Function, SymbolKind.Method, SymbolKind.Class, SymbolKind.Interface, SymbolKind.Struct) + @property def relative_path(self) -> str | None: location = self.symbol_root.get("location") @@ -758,10 +765,12 @@ class SymbolManager: # start at beginning of next line col = 0 line += 1 - # make sure there is one empty line before the new symbol - body = "\n" + body.lstrip("\n") + # strip preceding newlines, re-adding an empty line before the new symbol if appropriate + body = body.lstrip("\r\n") + if symbol.is_neighbouring_definition_separated_by_empty_line(): + body = "\n" + body # make sure the one line break succeeding the original symbol, which we repurposed as prefix, is replaced - body = body.rstrip("\n") + "\n" + body = body.rstrip("\r\n") + "\n" if use_same_indentation: symbol_start_pos = symbol.body_start_position @@ -836,8 +845,11 @@ class SymbolManager: if at_new_line: col = 0 - # ensure two newlines after inserted body (eol + empty line) - body = body.rstrip() + "\n\n" + # ensure eol is present at end + body = body.rstrip() + "\n" + # add empty line if appropriate + if symbol.is_neighbouring_definition_separated_by_empty_line(): + body += "\n" assert location.relative_path is not None From 3726408a6f8a99260b9a26d8d623a26460f27431 Mon Sep 17 00:00:00 2001 From: Dominik Jain Date: Sun, 22 Jun 2025 23:39:13 +0200 Subject: [PATCH 06/14] Update editing tests --- test/serena/test_symbol_editing.py | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/test/serena/test_symbol_editing.py b/test/serena/test_symbol_editing.py index 12be047e..b034d7c8 100644 --- a/test/serena/test_symbol_editing.py +++ b/test/serena/test_symbol_editing.py @@ -159,9 +159,9 @@ class InsertInRelToSymbolTest(EditingTest): def _apply_edit(self, symbol_manager: SymbolManager) -> None: assert self.mode is not None if self.mode == "before": - symbol_manager.insert_before_symbol(self.symbol_name, self.rel_path, self.new_content) + symbol_manager.insert_before_symbol(self.symbol_name, self.rel_path, self.new_content, use_same_indentation=False) elif self.mode == "after": - symbol_manager.insert_after_symbol(self.symbol_name, self.rel_path, self.new_content) + symbol_manager.insert_after_symbol(self.symbol_name, self.rel_path, self.new_content, use_same_indentation=False) @pytest.mark.parametrize("mode", ["before", "after"]) @@ -211,18 +211,16 @@ def test_insert_in_rel_to_symbol(test_case: InsertInRelToSymbolTest, mode: Liter test_case.run_test(content_after_ground_truth=snapshot) -PYTHON_REPLACED_BODY = """ -def modify_instance_var(self): - # This body has been replaced - self.instance_var = "Replaced!" - self.reassignable_instance_var = 999 +PYTHON_REPLACED_BODY = """def modify_instance_var(self): + # This body has been replaced + self.instance_var = "Replaced!" + self.reassignable_instance_var = 999 """ -TYPESCRIPT_REPLACED_BODY = """ -function printValue() { - // This body has been replaced - console.warn("New value: " + this.value); -} +TYPESCRIPT_REPLACED_BODY = """function printValue() { + // This body has been replaced + console.warn("New value: " + this.value); + } """ @@ -233,7 +231,7 @@ class ReplaceBodyTest(EditingTest): self.new_body = new_body def _apply_edit(self, symbol_manager: SymbolManager) -> None: - symbol_manager.replace_body(self.symbol_name, self.rel_path, self.new_body) + symbol_manager.replace_body(self.symbol_name, self.rel_path, self.new_body, use_same_indentation=False) @pytest.mark.parametrize( From 07ea1370dc5e4e3f965b6106487e4ed98d2aaa9c Mon Sep 17 00:00:00 2001 From: Dominik Jain Date: Mon, 23 Jun 2025 00:31:07 +0200 Subject: [PATCH 07/14] Add tests for adding a class with 'LLM-provided' leading/trailing newlines --- .../__snapshots__/test_symbol_editing.ambr | 208 ++++++++++++++++++ test/serena/test_symbol_editing.py | 40 +++- 2 files changed, 246 insertions(+), 2 deletions(-) diff --git a/test/serena/__snapshots__/test_symbol_editing.ambr b/test/serena/__snapshots__/test_symbol_editing.ambr index 2b698a22..b1f12e97 100644 --- a/test/serena/__snapshots__/test_symbol_editing.ambr +++ b/test/serena/__snapshots__/test_symbol_editing.ambr @@ -584,6 +584,214 @@ ''' # --- +# name: test_insert_python_class_after + ''' + """ + Test module for variable declarations and usage. + + This module tests various types of variable declarations and usages including: + - Module-level variables + - Class-level variables + - Instance variables + - Variable reassignments + """ + + from dataclasses import dataclass, field + + # Module-level variables + module_var = "Initial module value" + + reassignable_module_var = 10 + reassignable_module_var = 20 # Reassigned + + # Module-level variable with type annotation + typed_module_var: int = 42 + + + # Regular class with class and instance variables + class VariableContainer: + """Class that contains various variables.""" + + # Class-level variables + class_var = "Initial class value" + + reassignable_class_var = True + reassignable_class_var = False # Reassigned #noqa: PIE794 + + # Class-level variable with type annotation + typed_class_var: str = "typed value" + + def __init__(self): + # Instance variables + self.instance_var = "Initial instance value" + self.reassignable_instance_var = 100 + + # Instance variable with type annotation + self.typed_instance_var: list[str] = ["item1", "item2"] + + def modify_instance_var(self): + # Reassign instance variable + self.instance_var = "Modified instance value" + self.reassignable_instance_var = 200 # Reassigned + + def use_module_var(self): + # Use module-level variables + result = module_var + " used in method" + other_result = reassignable_module_var + 5 + return result, other_result + + def use_class_var(self): + # Use class-level variables + result = VariableContainer.class_var + " used in method" + other_result = VariableContainer.reassignable_class_var + return result, other_result + + + # Dataclass with variables + @dataclass + class VariableDataclass: + """Dataclass that contains various fields.""" + + # Field variables with type annotations + id: int + name: str + items: list[str] = field(default_factory=list) + metadata: dict[str, str] = field(default_factory=dict) + optional_value: float | None = None + + # This will be reassigned in various places + status: str = "pending" + + class NewInsertedClass: + pass + + + # Function that uses the module variables + def use_module_variables(): + """Function that uses module-level variables.""" + result = module_var + " used in function" + other_result = reassignable_module_var * 2 + return result, other_result + + + # Create instances and use variables + dataclass_instance = VariableDataclass(id=1, name="Test") + dataclass_instance.status = "active" # Reassign dataclass field + + # Use variables at module level + module_result = module_var + " used at module level" + other_module_result = reassignable_module_var + 30 + + # Create a second dataclass instance with different status + second_dataclass = VariableDataclass(id=2, name="Another Test") + second_dataclass.status = "completed" # Another reassignment of status + + ''' +# --- +# name: test_insert_python_class_before + ''' + """ + Test module for variable declarations and usage. + + This module tests various types of variable declarations and usages including: + - Module-level variables + - Class-level variables + - Instance variables + - Variable reassignments + """ + + from dataclasses import dataclass, field + + # Module-level variables + module_var = "Initial module value" + + reassignable_module_var = 10 + reassignable_module_var = 20 # Reassigned + + # Module-level variable with type annotation + typed_module_var: int = 42 + + + # Regular class with class and instance variables + class VariableContainer: + """Class that contains various variables.""" + + # Class-level variables + class_var = "Initial class value" + + reassignable_class_var = True + reassignable_class_var = False # Reassigned #noqa: PIE794 + + # Class-level variable with type annotation + typed_class_var: str = "typed value" + + def __init__(self): + # Instance variables + self.instance_var = "Initial instance value" + self.reassignable_instance_var = 100 + + # Instance variable with type annotation + self.typed_instance_var: list[str] = ["item1", "item2"] + + def modify_instance_var(self): + # Reassign instance variable + self.instance_var = "Modified instance value" + self.reassignable_instance_var = 200 # Reassigned + + def use_module_var(self): + # Use module-level variables + result = module_var + " used in method" + other_result = reassignable_module_var + 5 + return result, other_result + + def use_class_var(self): + # Use class-level variables + result = VariableContainer.class_var + " used in method" + other_result = VariableContainer.reassignable_class_var + return result, other_result + + + # Dataclass with variables + class NewInsertedClass: + pass + + @dataclass + class VariableDataclass: + """Dataclass that contains various fields.""" + + # Field variables with type annotations + id: int + name: str + items: list[str] = field(default_factory=list) + metadata: dict[str, str] = field(default_factory=dict) + optional_value: float | None = None + + # This will be reassigned in various places + status: str = "pending" + + + # Function that uses the module variables + def use_module_variables(): + """Function that uses module-level variables.""" + result = module_var + " used in function" + other_result = reassignable_module_var * 2 + return result, other_result + + + # Create instances and use variables + dataclass_instance = VariableDataclass(id=1, name="Test") + dataclass_instance.status = "active" # Reassign dataclass field + + # Use variables at module level + module_result = module_var + " used at module level" + other_module_result = reassignable_module_var + 30 + + # Create a second dataclass instance with different status + second_dataclass = VariableDataclass(id=2, name="Another Test") + second_dataclass.status = "completed" # Another reassignment of status + + ''' +# --- # name: test_replace_body[test_case0] ''' """ diff --git a/test/serena/test_symbol_editing.py b/test/serena/test_symbol_editing.py index b034d7c8..29976a51 100644 --- a/test/serena/test_symbol_editing.py +++ b/test/serena/test_symbol_editing.py @@ -134,6 +134,18 @@ def test_delete_symbol(test_case, snapshot): NEW_PYTHON_FUNCTION = """def new_inserted_function(): print("This is a new function inserted before another.")""" +NEW_PYTHON_CLASS_WITH_LEADING_NEWLINES = """ + +class NewInsertedClass: + pass +""" + +NEW_PYTHON_CLASS_WITH_TRAILING_NEWLINES = """class NewInsertedClass: + pass + + +""" + NEW_TYPESCRIPT_FUNCTION = """function newInsertedFunction(): void { console.log("This is a new function inserted before another."); }""" @@ -147,11 +159,13 @@ NEW_TYPESCRIPT_FUNCTION_AFTER = """function newFunctionAfterClass(): void { class InsertInRelToSymbolTest(EditingTest): - def __init__(self, language: Language, rel_path: str, symbol_name: str, new_content: str): + def __init__( + self, language: Language, rel_path: str, symbol_name: str, new_content: str, mode: Literal["before", "after"] | None = None + ): super().__init__(language, rel_path) self.symbol_name = symbol_name self.new_content = new_content - self.mode: Literal["before", "after"] | None = None + self.mode: Literal["before", "after"] | None = mode def set_mode(self, mode: Literal["before", "after"]): self.mode = mode @@ -211,6 +225,28 @@ def test_insert_in_rel_to_symbol(test_case: InsertInRelToSymbolTest, mode: Liter test_case.run_test(content_after_ground_truth=snapshot) +@pytest.mark.python +def test_insert_python_class_before(snapshot): + InsertInRelToSymbolTest( + Language.PYTHON, + PYTHON_TEST_REL_FILE_PATH, + "VariableDataclass", + NEW_PYTHON_CLASS_WITH_TRAILING_NEWLINES, + mode="before", + ).run_test(snapshot) + + +@pytest.mark.python +def test_insert_python_class_after(snapshot): + InsertInRelToSymbolTest( + Language.PYTHON, + PYTHON_TEST_REL_FILE_PATH, + "VariableDataclass", + NEW_PYTHON_CLASS_WITH_LEADING_NEWLINES, + mode="after", + ).run_test(snapshot) + + PYTHON_REPLACED_BODY = """def modify_instance_var(self): # This body has been replaced self.instance_var = "Replaced!" From 0586f4cd62492c1429afb2374952beb9da0fdb71 Mon Sep 17 00:00:00 2001 From: Dominik Jain Date: Mon, 23 Jun 2025 00:42:47 +0200 Subject: [PATCH 08/14] InsertBefore|AfterSymbolTool: Retain leading/trailing empty lines that are provided by the caller (if empty lines are appropriate for the symbol type) --- src/serena/symbol.py | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/src/serena/symbol.py b/src/serena/symbol.py index 35d73b81..3e342fbb 100644 --- a/src/serena/symbol.py +++ b/src/serena/symbol.py @@ -5,7 +5,7 @@ from collections.abc import Iterator, Sequence from contextlib import contextmanager from dataclasses import asdict, dataclass, field from difflib import SequenceMatcher -from typing import TYPE_CHECKING, Any, Literal, NamedTuple, Self, Union +from typing import TYPE_CHECKING, Any, Literal, NamedTuple, Self, Union, Iterable, Reversible from sensai.util.string import ToStringMixin @@ -709,6 +709,22 @@ class SymbolManager: self._lang_server.delete_text_between_positions(location.relative_path, start_pos, end_pos) self._lang_server.insert_text_at_position(location.relative_path, start_line, start_col, body) + @staticmethod + def _count_leading_newlines(text: Iterable) -> int: + cnt = 0 + for c in text: + if c == "\n": + cnt += 1 + elif c == "\r": + continue + else: + break + return cnt + + @classmethod + def _count_trailing_newlines(cls, text: Reversible) -> int: + return cls._count_leading_newlines(reversed(text)) + def insert_after_symbol( self, name_path: str, @@ -765,10 +781,12 @@ class SymbolManager: # start at beginning of next line col = 0 line += 1 - # strip preceding newlines, re-adding an empty line before the new symbol if appropriate + # strip preceding newlines, re-adding one or more empty lines before the new symbol if appropriate + original_leading_newlines = self._count_leading_newlines(body) body = body.lstrip("\r\n") if symbol.is_neighbouring_definition_separated_by_empty_line(): - body = "\n" + body + num_leading_newlines = max(1, original_leading_newlines) + body = ("\n" * num_leading_newlines) + body # make sure the one line break succeeding the original symbol, which we repurposed as prefix, is replaced body = body.rstrip("\r\n") + "\n" @@ -845,11 +863,13 @@ class SymbolManager: if at_new_line: col = 0 + original_trailing_empty_lines = self._count_trailing_newlines(body) - 1 # ensure eol is present at end body = body.rstrip() + "\n" - # add empty line if appropriate + # add one or more empty lines if appropriate if symbol.is_neighbouring_definition_separated_by_empty_line(): - body += "\n" + num_trailing_newlines = max(1, original_trailing_empty_lines) + body += "\n" * num_trailing_newlines assert location.relative_path is not None From 48296943e93aaaeae2a57b11f31e361d5fc647a5 Mon Sep 17 00:00:00 2001 From: Dominik Jain Date: Mon, 23 Jun 2025 14:03:35 +0200 Subject: [PATCH 09/14] Improve empty line handling in InsertBefore|AfterSymbolTool: Always respect the original caller's number of empty lines, but add a minimum number of empty lines depending on symbol kind --- src/serena/symbol.py | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/src/serena/symbol.py b/src/serena/symbol.py index 3e342fbb..44663221 100644 --- a/src/serena/symbol.py +++ b/src/serena/symbol.py @@ -1,11 +1,11 @@ import json import logging import os -from collections.abc import Iterator, Sequence +from collections.abc import Iterable, Iterator, Reversible, Sequence from contextlib import contextmanager from dataclasses import asdict, dataclass, field from difflib import SequenceMatcher -from typing import TYPE_CHECKING, Any, Literal, NamedTuple, Self, Union, Iterable, Reversible +from typing import TYPE_CHECKING, Any, Literal, NamedTuple, Self, Union from sensai.util.string import ToStringMixin @@ -781,13 +781,18 @@ class SymbolManager: # start at beginning of next line col = 0 line += 1 - # strip preceding newlines, re-adding one or more empty lines before the new symbol if appropriate + # make sure a suitable number of leading empty lines is used (at least 0/1 depending on the symbol type, + # otherweise as many as the caller wanted to insert) original_leading_newlines = self._count_leading_newlines(body) body = body.lstrip("\r\n") + min_empty_lines = 0 if symbol.is_neighbouring_definition_separated_by_empty_line(): - num_leading_newlines = max(1, original_leading_newlines) - body = ("\n" * num_leading_newlines) + body - # make sure the one line break succeeding the original symbol, which we repurposed as prefix, is replaced + min_empty_lines = 1 + num_leading_empty_lines = max(min_empty_lines, original_leading_newlines) + if num_leading_empty_lines: + body = ("\n" * num_leading_empty_lines) + body + # make sure the one line break succeeding the original symbol, which we repurposed as prefix via + # `line += 1`, is replaced body = body.rstrip("\r\n") + "\n" if use_same_indentation: @@ -866,10 +871,13 @@ class SymbolManager: original_trailing_empty_lines = self._count_trailing_newlines(body) - 1 # ensure eol is present at end body = body.rstrip() + "\n" - # add one or more empty lines if appropriate + # add suitable number of trailing empty lines after the body (at least 0/1 depending on the symbol type, + # otherwise as many as the caller wanted to insert) + min_trailing_empty_lines = 0 if symbol.is_neighbouring_definition_separated_by_empty_line(): - num_trailing_newlines = max(1, original_trailing_empty_lines) - body += "\n" * num_trailing_newlines + min_trailing_empty_lines = 1 + num_trailing_newlines = max(min_trailing_empty_lines, original_trailing_empty_lines) + body += "\n" * num_trailing_newlines assert location.relative_path is not None From 0c11ebebcc63bca1afbb9263b2230438a32274ce Mon Sep 17 00:00:00 2001 From: Dominik Jain Date: Mon, 23 Jun 2025 14:11:41 +0200 Subject: [PATCH 10/14] Remove obsolete flag at_new_line --- src/serena/agent.py | 14 +----- src/serena/symbol.py | 102 +++++++++++++++++-------------------------- 2 files changed, 41 insertions(+), 75 deletions(-) diff --git a/src/serena/agent.py b/src/serena/agent.py index b51285eb..b8cde47c 100644 --- a/src/serena/agent.py +++ b/src/serena/agent.py @@ -1738,12 +1738,7 @@ class InsertAfterSymbolTool(Tool, ToolMarkerCanEdit): :param body: the body/content to be inserted. The inserted code shall begin with the next line after the symbol. """ - self.symbol_manager.insert_after_symbol( - name_path, - relative_file_path=relative_path, - body=body, - use_same_indentation=False, - ) + self.symbol_manager.insert_after_symbol(name_path, relative_file_path=relative_path, body=body, use_same_indentation=False) return SUCCESS_RESULT @@ -1767,12 +1762,7 @@ class InsertBeforeSymbolTool(Tool, ToolMarkerCanEdit): :param relative_path: the relative path to the file containing the symbol :param body: the body/content to be inserted before the line in which the referenced symbol is defined """ - self.symbol_manager.insert_before_symbol( - name_path, - relative_file_path=relative_path, - body=body, - use_same_indentation=False, - ) + self.symbol_manager.insert_before_symbol(name_path, relative_file_path=relative_path, body=body, use_same_indentation=False) return SUCCESS_RESULT diff --git a/src/serena/symbol.py b/src/serena/symbol.py index 44663221..e92ffdf8 100644 --- a/src/serena/symbol.py +++ b/src/serena/symbol.py @@ -725,15 +725,7 @@ class SymbolManager: def _count_trailing_newlines(cls, text: Reversible) -> int: return cls._count_leading_newlines(reversed(text)) - def insert_after_symbol( - self, - name_path: str, - relative_file_path: str, - body: str, - *, - use_same_indentation: bool = True, - at_new_line: bool = True, - ) -> None: + def insert_after_symbol(self, name_path: str, relative_file_path: str, body: str, *, use_same_indentation: bool = True) -> None: """ Inserts content after the symbol with the given name in the given file. """ @@ -747,13 +739,9 @@ class SymbolManager: f"Found symbols at locations: \n" + json.dumps([s.location.to_dict() for s in symbol_candidates], indent=2) ) symbol = symbol_candidates[-1] - return self.insert_after_symbol_at_location( - symbol.location, body, at_new_line=at_new_line, use_same_indentation=use_same_indentation - ) + return self.insert_after_symbol_at_location(symbol.location, body, use_same_indentation=use_same_indentation) - def insert_after_symbol_at_location( - self, location: SymbolLocation, body: str, *, at_new_line: bool = True, use_same_indentation: bool = True - ) -> None: + def insert_after_symbol_at_location(self, location: SymbolLocation, body: str, *, use_same_indentation: bool = True) -> None: """ Appends content after the given symbol @@ -775,25 +763,22 @@ class SymbolManager: if pos is None: raise ValueError(f"Symbol at {location} does not have a defined end position.") - line, col = pos["line"], pos["character"] - - if at_new_line: - # start at beginning of next line - col = 0 - line += 1 - # make sure a suitable number of leading empty lines is used (at least 0/1 depending on the symbol type, - # otherweise as many as the caller wanted to insert) - original_leading_newlines = self._count_leading_newlines(body) - body = body.lstrip("\r\n") - min_empty_lines = 0 - if symbol.is_neighbouring_definition_separated_by_empty_line(): - min_empty_lines = 1 - num_leading_empty_lines = max(min_empty_lines, original_leading_newlines) - if num_leading_empty_lines: - body = ("\n" * num_leading_empty_lines) + body - # make sure the one line break succeeding the original symbol, which we repurposed as prefix via - # `line += 1`, is replaced - body = body.rstrip("\r\n") + "\n" + # start at the beginning of the next line + col = 0 + line = pos["line"] + 1 + # make sure a suitable number of leading empty lines is used (at least 0/1 depending on the symbol type, + # otherweise as many as the caller wanted to insert) + original_leading_newlines = self._count_leading_newlines(body) + body = body.lstrip("\r\n") + min_empty_lines = 0 + if symbol.is_neighbouring_definition_separated_by_empty_line(): + min_empty_lines = 1 + num_leading_empty_lines = max(min_empty_lines, original_leading_newlines) + if num_leading_empty_lines: + body = ("\n" * num_leading_empty_lines) + body + # make sure the one line break succeeding the original symbol, which we repurposed as prefix via + # `line += 1`, is replaced + body = body.rstrip("\r\n") + "\n" if use_same_indentation: symbol_start_pos = symbol.body_start_position @@ -817,20 +802,11 @@ class SymbolManager: # > test test # > second line # > dataclass_instance.status = "active" # Reassign dataclass field - col = 0 with self._edited_symbol_location(location): self._lang_server.insert_text_at_position(location.relative_path, line=line, column=col, text_to_be_inserted=body) - def insert_before_symbol( - self, - name_path: str, - relative_file_path: str, - body: str, - *, - at_new_line: bool = True, - use_same_indentation: bool = True, - ) -> None: + def insert_before_symbol(self, name_path: str, relative_file_path: str, body: str, *, use_same_indentation: bool = True) -> None: """ Inserts content before the symbol with the given name in the given file. """ @@ -844,11 +820,9 @@ class SymbolManager: f"Found symbols at locations: \n" + json.dumps([s.location.to_dict() for s in symbol_candidates], indent=2) ) symbol = symbol_candidates[0] - self.insert_before_symbol_at_location(symbol.location, body, at_new_line=at_new_line, use_same_indentation=use_same_indentation) + self.insert_before_symbol_at_location(symbol.location, body, use_same_indentation=use_same_indentation) - def insert_before_symbol_at_location( - self, location: SymbolLocation, body: str, *, at_new_line: bool = True, use_same_indentation: bool = True - ) -> None: + def insert_before_symbol_at_location(self, location: SymbolLocation, body: str, *, use_same_indentation: bool = True) -> None: """ Inserts content before the given symbol @@ -859,25 +833,27 @@ class SymbolManager: symbol_start_pos = symbol.body_start_position if symbol_start_pos is None: raise ValueError(f"Symbol at {location} does not have a defined start position.") - line = symbol_start_pos["line"] - col = symbol_start_pos["character"] if use_same_indentation: - indent = " " * (col) + indent = " " * (symbol_start_pos["character"]) body = "\n".join(indent + line for line in body.splitlines()) - if at_new_line: - col = 0 - original_trailing_empty_lines = self._count_trailing_newlines(body) - 1 - # ensure eol is present at end - body = body.rstrip() + "\n" - # add suitable number of trailing empty lines after the body (at least 0/1 depending on the symbol type, - # otherwise as many as the caller wanted to insert) - min_trailing_empty_lines = 0 - if symbol.is_neighbouring_definition_separated_by_empty_line(): - min_trailing_empty_lines = 1 - num_trailing_newlines = max(min_trailing_empty_lines, original_trailing_empty_lines) - body += "\n" * num_trailing_newlines + # insert position is the start of line where the symbol is defined + line = symbol_start_pos["line"] + col = 0 + + original_trailing_empty_lines = self._count_trailing_newlines(body) - 1 + + # ensure eol is present at end + body = body.rstrip() + "\n" + + # add suitable number of trailing empty lines after the body (at least 0/1 depending on the symbol type, + # otherwise as many as the caller wanted to insert) + min_trailing_empty_lines = 0 + if symbol.is_neighbouring_definition_separated_by_empty_line(): + min_trailing_empty_lines = 1 + num_trailing_newlines = max(min_trailing_empty_lines, original_trailing_empty_lines) + body += "\n" * num_trailing_newlines assert location.relative_path is not None From b5d94888839d6fb3bf8282023ed3b7788f6647dc Mon Sep 17 00:00:00 2001 From: Dominik Jain Date: Mon, 23 Jun 2025 14:43:43 +0200 Subject: [PATCH 11/14] Update test snapshots --- .../__snapshots__/test_symbol_editing.ambr | 1846 +++++++++-------- 1 file changed, 925 insertions(+), 921 deletions(-) diff --git a/test/serena/__snapshots__/test_symbol_editing.ambr b/test/serena/__snapshots__/test_symbol_editing.ambr index b1f12e97..327a5efd 100644 --- a/test/serena/__snapshots__/test_symbol_editing.ambr +++ b/test/serena/__snapshots__/test_symbol_editing.ambr @@ -1,921 +1,925 @@ -# serializer version: 1 -# name: test_delete_symbol[test_case0] - ''' - """ - Test module for variable declarations and usage. - - This module tests various types of variable declarations and usages including: - - Module-level variables - - Class-level variables - - Instance variables - - Variable reassignments - """ - - from dataclasses import dataclass, field - - # Module-level variables - module_var = "Initial module value" - - reassignable_module_var = 10 - reassignable_module_var = 20 # Reassigned - - # Module-level variable with type annotation - typed_module_var: int = 42 - - - # Regular class with class and instance variables - - - - # Dataclass with variables - @dataclass - class VariableDataclass: - """Dataclass that contains various fields.""" - - # Field variables with type annotations - id: int - name: str - items: list[str] = field(default_factory=list) - metadata: dict[str, str] = field(default_factory=dict) - optional_value: float | None = None - - # This will be reassigned in various places - status: str = "pending" - - - # Function that uses the module variables - def use_module_variables(): - """Function that uses module-level variables.""" - result = module_var + " used in function" - other_result = reassignable_module_var * 2 - return result, other_result - - - # Create instances and use variables - dataclass_instance = VariableDataclass(id=1, name="Test") - dataclass_instance.status = "active" # Reassign dataclass field - - # Use variables at module level - module_result = module_var + " used at module level" - other_module_result = reassignable_module_var + 30 - - # Create a second dataclass instance with different status - second_dataclass = VariableDataclass(id=2, name="Another Test") - second_dataclass.status = "completed" # Another reassignment of status - - ''' -# --- -# name: test_delete_symbol[test_case1] - ''' - - - export function helperFunction() { - const demo = new DemoClass(42); - demo.printValue(); - } - - helperFunction(); - - ''' -# --- -# name: test_insert_in_rel_to_symbol[test_case0-after] - ''' - """ - Test module for variable declarations and usage. - - This module tests various types of variable declarations and usages including: - - Module-level variables - - Class-level variables - - Instance variables - - Variable reassignments - """ - - from dataclasses import dataclass, field - - # Module-level variables - module_var = "Initial module value" - - reassignable_module_var = 10 - reassignable_module_var = 20 # Reassigned - - # Module-level variable with type annotation - typed_module_var: int = 42 - - new_module_var = "Inserted after typed_module_var" - - # Regular class with class and instance variables - class VariableContainer: - """Class that contains various variables.""" - - # Class-level variables - class_var = "Initial class value" - - reassignable_class_var = True - reassignable_class_var = False # Reassigned #noqa: PIE794 - - # Class-level variable with type annotation - typed_class_var: str = "typed value" - - def __init__(self): - # Instance variables - self.instance_var = "Initial instance value" - self.reassignable_instance_var = 100 - - # Instance variable with type annotation - self.typed_instance_var: list[str] = ["item1", "item2"] - - def modify_instance_var(self): - # Reassign instance variable - self.instance_var = "Modified instance value" - self.reassignable_instance_var = 200 # Reassigned - - def use_module_var(self): - # Use module-level variables - result = module_var + " used in method" - other_result = reassignable_module_var + 5 - return result, other_result - - def use_class_var(self): - # Use class-level variables - result = VariableContainer.class_var + " used in method" - other_result = VariableContainer.reassignable_class_var - return result, other_result - - - # Dataclass with variables - @dataclass - class VariableDataclass: - """Dataclass that contains various fields.""" - - # Field variables with type annotations - id: int - name: str - items: list[str] = field(default_factory=list) - metadata: dict[str, str] = field(default_factory=dict) - optional_value: float | None = None - - # This will be reassigned in various places - status: str = "pending" - - - # Function that uses the module variables - def use_module_variables(): - """Function that uses module-level variables.""" - result = module_var + " used in function" - other_result = reassignable_module_var * 2 - return result, other_result - - - # Create instances and use variables - dataclass_instance = VariableDataclass(id=1, name="Test") - dataclass_instance.status = "active" # Reassign dataclass field - - # Use variables at module level - module_result = module_var + " used at module level" - other_module_result = reassignable_module_var + 30 - - # Create a second dataclass instance with different status - second_dataclass = VariableDataclass(id=2, name="Another Test") - second_dataclass.status = "completed" # Another reassignment of status - - ''' -# --- -# name: test_insert_in_rel_to_symbol[test_case0-before] - ''' - """ - Test module for variable declarations and usage. - - This module tests various types of variable declarations and usages including: - - Module-level variables - - Class-level variables - - Instance variables - - Variable reassignments - """ - - from dataclasses import dataclass, field - - # Module-level variables - module_var = "Initial module value" - - reassignable_module_var = 10 - reassignable_module_var = 20 # Reassigned - - new_module_var = "Inserted after typed_module_var" - # Module-level variable with type annotation - typed_module_var: int = 42 - - - # Regular class with class and instance variables - class VariableContainer: - """Class that contains various variables.""" - - # Class-level variables - class_var = "Initial class value" - - reassignable_class_var = True - reassignable_class_var = False # Reassigned #noqa: PIE794 - - # Class-level variable with type annotation - typed_class_var: str = "typed value" - - def __init__(self): - # Instance variables - self.instance_var = "Initial instance value" - self.reassignable_instance_var = 100 - - # Instance variable with type annotation - self.typed_instance_var: list[str] = ["item1", "item2"] - - def modify_instance_var(self): - # Reassign instance variable - self.instance_var = "Modified instance value" - self.reassignable_instance_var = 200 # Reassigned - - def use_module_var(self): - # Use module-level variables - result = module_var + " used in method" - other_result = reassignable_module_var + 5 - return result, other_result - - def use_class_var(self): - # Use class-level variables - result = VariableContainer.class_var + " used in method" - other_result = VariableContainer.reassignable_class_var - return result, other_result - - - # Dataclass with variables - @dataclass - class VariableDataclass: - """Dataclass that contains various fields.""" - - # Field variables with type annotations - id: int - name: str - items: list[str] = field(default_factory=list) - metadata: dict[str, str] = field(default_factory=dict) - optional_value: float | None = None - - # This will be reassigned in various places - status: str = "pending" - - - # Function that uses the module variables - def use_module_variables(): - """Function that uses module-level variables.""" - result = module_var + " used in function" - other_result = reassignable_module_var * 2 - return result, other_result - - - # Create instances and use variables - dataclass_instance = VariableDataclass(id=1, name="Test") - dataclass_instance.status = "active" # Reassign dataclass field - - # Use variables at module level - module_result = module_var + " used at module level" - other_module_result = reassignable_module_var + 30 - - # Create a second dataclass instance with different status - second_dataclass = VariableDataclass(id=2, name="Another Test") - second_dataclass.status = "completed" # Another reassignment of status - - ''' -# --- -# name: test_insert_in_rel_to_symbol[test_case1-after] - ''' - """ - Test module for variable declarations and usage. - - This module tests various types of variable declarations and usages including: - - Module-level variables - - Class-level variables - - Instance variables - - Variable reassignments - """ - - from dataclasses import dataclass, field - - # Module-level variables - module_var = "Initial module value" - - reassignable_module_var = 10 - reassignable_module_var = 20 # Reassigned - - # Module-level variable with type annotation - typed_module_var: int = 42 - - - # Regular class with class and instance variables - class VariableContainer: - """Class that contains various variables.""" - - # Class-level variables - class_var = "Initial class value" - - reassignable_class_var = True - reassignable_class_var = False # Reassigned #noqa: PIE794 - - # Class-level variable with type annotation - typed_class_var: str = "typed value" - - def __init__(self): - # Instance variables - self.instance_var = "Initial instance value" - self.reassignable_instance_var = 100 - - # Instance variable with type annotation - self.typed_instance_var: list[str] = ["item1", "item2"] - - def modify_instance_var(self): - # Reassign instance variable - self.instance_var = "Modified instance value" - self.reassignable_instance_var = 200 # Reassigned - - def use_module_var(self): - # Use module-level variables - result = module_var + " used in method" - other_result = reassignable_module_var + 5 - return result, other_result - - def use_class_var(self): - # Use class-level variables - result = VariableContainer.class_var + " used in method" - other_result = VariableContainer.reassignable_class_var - return result, other_result - - - # Dataclass with variables - @dataclass - class VariableDataclass: - """Dataclass that contains various fields.""" - - # Field variables with type annotations - id: int - name: str - items: list[str] = field(default_factory=list) - metadata: dict[str, str] = field(default_factory=dict) - optional_value: float | None = None - - # This will be reassigned in various places - status: str = "pending" - - - # Function that uses the module variables - def use_module_variables(): - """Function that uses module-level variables.""" - result = module_var + " used in function" - other_result = reassignable_module_var * 2 - return result, other_result - - def new_inserted_function(): - print("This is a new function inserted before another.") - - # Create instances and use variables - dataclass_instance = VariableDataclass(id=1, name="Test") - dataclass_instance.status = "active" # Reassign dataclass field - - # Use variables at module level - module_result = module_var + " used at module level" - other_module_result = reassignable_module_var + 30 - - # Create a second dataclass instance with different status - second_dataclass = VariableDataclass(id=2, name="Another Test") - second_dataclass.status = "completed" # Another reassignment of status - - ''' -# --- -# name: test_insert_in_rel_to_symbol[test_case1-before] - ''' - """ - Test module for variable declarations and usage. - - This module tests various types of variable declarations and usages including: - - Module-level variables - - Class-level variables - - Instance variables - - Variable reassignments - """ - - from dataclasses import dataclass, field - - # Module-level variables - module_var = "Initial module value" - - reassignable_module_var = 10 - reassignable_module_var = 20 # Reassigned - - # Module-level variable with type annotation - typed_module_var: int = 42 - - - # Regular class with class and instance variables - class VariableContainer: - """Class that contains various variables.""" - - # Class-level variables - class_var = "Initial class value" - - reassignable_class_var = True - reassignable_class_var = False # Reassigned #noqa: PIE794 - - # Class-level variable with type annotation - typed_class_var: str = "typed value" - - def __init__(self): - # Instance variables - self.instance_var = "Initial instance value" - self.reassignable_instance_var = 100 - - # Instance variable with type annotation - self.typed_instance_var: list[str] = ["item1", "item2"] - - def modify_instance_var(self): - # Reassign instance variable - self.instance_var = "Modified instance value" - self.reassignable_instance_var = 200 # Reassigned - - def use_module_var(self): - # Use module-level variables - result = module_var + " used in method" - other_result = reassignable_module_var + 5 - return result, other_result - - def use_class_var(self): - # Use class-level variables - result = VariableContainer.class_var + " used in method" - other_result = VariableContainer.reassignable_class_var - return result, other_result - - - # Dataclass with variables - @dataclass - class VariableDataclass: - """Dataclass that contains various fields.""" - - # Field variables with type annotations - id: int - name: str - items: list[str] = field(default_factory=list) - metadata: dict[str, str] = field(default_factory=dict) - optional_value: float | None = None - - # This will be reassigned in various places - status: str = "pending" - - - def new_inserted_function(): - print("This is a new function inserted before another.") - # Function that uses the module variables - def use_module_variables(): - """Function that uses module-level variables.""" - result = module_var + " used in function" - other_result = reassignable_module_var * 2 - return result, other_result - - - # Create instances and use variables - dataclass_instance = VariableDataclass(id=1, name="Test") - dataclass_instance.status = "active" # Reassign dataclass field - - # Use variables at module level - module_result = module_var + " used at module level" - other_module_result = reassignable_module_var + 30 - - # Create a second dataclass instance with different status - second_dataclass = VariableDataclass(id=2, name="Another Test") - second_dataclass.status = "completed" # Another reassignment of status - - ''' -# --- -# name: test_insert_in_rel_to_symbol[test_case2-after] - ''' - export class DemoClass { - value: number; - constructor(value: number) { - this.value = value; - } - printValue() { - console.log(this.value); - } - } - - function newFunctionAfterClass(): void { - console.log("This function is after DemoClass."); - } - export function helperFunction() { - const demo = new DemoClass(42); - demo.printValue(); - } - - helperFunction(); - - ''' -# --- -# name: test_insert_in_rel_to_symbol[test_case2-before] - ''' - function newFunctionAfterClass(): void { - console.log("This function is after DemoClass."); - } - export class DemoClass { - value: number; - constructor(value: number) { - this.value = value; - } - printValue() { - console.log(this.value); - } - } - - export function helperFunction() { - const demo = new DemoClass(42); - demo.printValue(); - } - - helperFunction(); - - ''' -# --- -# name: test_insert_in_rel_to_symbol[test_case3-after] - ''' - export class DemoClass { - value: number; - constructor(value: number) { - this.value = value; - } - printValue() { - console.log(this.value); - } - } - - export function helperFunction() { - const demo = new DemoClass(42); - demo.printValue(); - } - - function newInsertedFunction(): void { - console.log("This is a new function inserted before another."); - } - helperFunction(); - - ''' -# --- -# name: test_insert_in_rel_to_symbol[test_case3-before] - ''' - export class DemoClass { - value: number; - constructor(value: number) { - this.value = value; - } - printValue() { - console.log(this.value); - } - } - function newInsertedFunction(): void { - console.log("This is a new function inserted before another."); - } - - export function helperFunction() { - const demo = new DemoClass(42); - demo.printValue(); - } - - helperFunction(); - - ''' -# --- -# name: test_insert_python_class_after - ''' - """ - Test module for variable declarations and usage. - - This module tests various types of variable declarations and usages including: - - Module-level variables - - Class-level variables - - Instance variables - - Variable reassignments - """ - - from dataclasses import dataclass, field - - # Module-level variables - module_var = "Initial module value" - - reassignable_module_var = 10 - reassignable_module_var = 20 # Reassigned - - # Module-level variable with type annotation - typed_module_var: int = 42 - - - # Regular class with class and instance variables - class VariableContainer: - """Class that contains various variables.""" - - # Class-level variables - class_var = "Initial class value" - - reassignable_class_var = True - reassignable_class_var = False # Reassigned #noqa: PIE794 - - # Class-level variable with type annotation - typed_class_var: str = "typed value" - - def __init__(self): - # Instance variables - self.instance_var = "Initial instance value" - self.reassignable_instance_var = 100 - - # Instance variable with type annotation - self.typed_instance_var: list[str] = ["item1", "item2"] - - def modify_instance_var(self): - # Reassign instance variable - self.instance_var = "Modified instance value" - self.reassignable_instance_var = 200 # Reassigned - - def use_module_var(self): - # Use module-level variables - result = module_var + " used in method" - other_result = reassignable_module_var + 5 - return result, other_result - - def use_class_var(self): - # Use class-level variables - result = VariableContainer.class_var + " used in method" - other_result = VariableContainer.reassignable_class_var - return result, other_result - - - # Dataclass with variables - @dataclass - class VariableDataclass: - """Dataclass that contains various fields.""" - - # Field variables with type annotations - id: int - name: str - items: list[str] = field(default_factory=list) - metadata: dict[str, str] = field(default_factory=dict) - optional_value: float | None = None - - # This will be reassigned in various places - status: str = "pending" - - class NewInsertedClass: - pass - - - # Function that uses the module variables - def use_module_variables(): - """Function that uses module-level variables.""" - result = module_var + " used in function" - other_result = reassignable_module_var * 2 - return result, other_result - - - # Create instances and use variables - dataclass_instance = VariableDataclass(id=1, name="Test") - dataclass_instance.status = "active" # Reassign dataclass field - - # Use variables at module level - module_result = module_var + " used at module level" - other_module_result = reassignable_module_var + 30 - - # Create a second dataclass instance with different status - second_dataclass = VariableDataclass(id=2, name="Another Test") - second_dataclass.status = "completed" # Another reassignment of status - - ''' -# --- -# name: test_insert_python_class_before - ''' - """ - Test module for variable declarations and usage. - - This module tests various types of variable declarations and usages including: - - Module-level variables - - Class-level variables - - Instance variables - - Variable reassignments - """ - - from dataclasses import dataclass, field - - # Module-level variables - module_var = "Initial module value" - - reassignable_module_var = 10 - reassignable_module_var = 20 # Reassigned - - # Module-level variable with type annotation - typed_module_var: int = 42 - - - # Regular class with class and instance variables - class VariableContainer: - """Class that contains various variables.""" - - # Class-level variables - class_var = "Initial class value" - - reassignable_class_var = True - reassignable_class_var = False # Reassigned #noqa: PIE794 - - # Class-level variable with type annotation - typed_class_var: str = "typed value" - - def __init__(self): - # Instance variables - self.instance_var = "Initial instance value" - self.reassignable_instance_var = 100 - - # Instance variable with type annotation - self.typed_instance_var: list[str] = ["item1", "item2"] - - def modify_instance_var(self): - # Reassign instance variable - self.instance_var = "Modified instance value" - self.reassignable_instance_var = 200 # Reassigned - - def use_module_var(self): - # Use module-level variables - result = module_var + " used in method" - other_result = reassignable_module_var + 5 - return result, other_result - - def use_class_var(self): - # Use class-level variables - result = VariableContainer.class_var + " used in method" - other_result = VariableContainer.reassignable_class_var - return result, other_result - - - # Dataclass with variables - class NewInsertedClass: - pass - - @dataclass - class VariableDataclass: - """Dataclass that contains various fields.""" - - # Field variables with type annotations - id: int - name: str - items: list[str] = field(default_factory=list) - metadata: dict[str, str] = field(default_factory=dict) - optional_value: float | None = None - - # This will be reassigned in various places - status: str = "pending" - - - # Function that uses the module variables - def use_module_variables(): - """Function that uses module-level variables.""" - result = module_var + " used in function" - other_result = reassignable_module_var * 2 - return result, other_result - - - # Create instances and use variables - dataclass_instance = VariableDataclass(id=1, name="Test") - dataclass_instance.status = "active" # Reassign dataclass field - - # Use variables at module level - module_result = module_var + " used at module level" - other_module_result = reassignable_module_var + 30 - - # Create a second dataclass instance with different status - second_dataclass = VariableDataclass(id=2, name="Another Test") - second_dataclass.status = "completed" # Another reassignment of status - - ''' -# --- -# name: test_replace_body[test_case0] - ''' - """ - Test module for variable declarations and usage. - - This module tests various types of variable declarations and usages including: - - Module-level variables - - Class-level variables - - Instance variables - - Variable reassignments - """ - - from dataclasses import dataclass, field - - # Module-level variables - module_var = "Initial module value" - - reassignable_module_var = 10 - reassignable_module_var = 20 # Reassigned - - # Module-level variable with type annotation - typed_module_var: int = 42 - - - # Regular class with class and instance variables - class VariableContainer: - """Class that contains various variables.""" - - # Class-level variables - class_var = "Initial class value" - - reassignable_class_var = True - reassignable_class_var = False # Reassigned #noqa: PIE794 - - # Class-level variable with type annotation - typed_class_var: str = "typed value" - - def __init__(self): - # Instance variables - self.instance_var = "Initial instance value" - self.reassignable_instance_var = 100 - - # Instance variable with type annotation - self.typed_instance_var: list[str] = ["item1", "item2"] - - - def modify_instance_var(self): - # This body has been replaced - self.instance_var = "Replaced!" - self.reassignable_instance_var = 999 - # Reassigned - - def use_module_var(self): - # Use module-level variables - result = module_var + " used in method" - other_result = reassignable_module_var + 5 - return result, other_result - - def use_class_var(self): - # Use class-level variables - result = VariableContainer.class_var + " used in method" - other_result = VariableContainer.reassignable_class_var - return result, other_result - - - # Dataclass with variables - @dataclass - class VariableDataclass: - """Dataclass that contains various fields.""" - - # Field variables with type annotations - id: int - name: str - items: list[str] = field(default_factory=list) - metadata: dict[str, str] = field(default_factory=dict) - optional_value: float | None = None - - # This will be reassigned in various places - status: str = "pending" - - - # Function that uses the module variables - def use_module_variables(): - """Function that uses module-level variables.""" - result = module_var + " used in function" - other_result = reassignable_module_var * 2 - return result, other_result - - - # Create instances and use variables - dataclass_instance = VariableDataclass(id=1, name="Test") - dataclass_instance.status = "active" # Reassign dataclass field - - # Use variables at module level - module_result = module_var + " used at module level" - other_module_result = reassignable_module_var + 30 - - # Create a second dataclass instance with different status - second_dataclass = VariableDataclass(id=2, name="Another Test") - second_dataclass.status = "completed" # Another reassignment of status - - ''' -# --- -# name: test_replace_body[test_case1] - ''' - export class DemoClass { - value: number; - constructor(value: number) { - this.value = value; - } - - function printValue() { - // This body has been replaced - console.warn("New value: " + this.value); - } - - } - - export function helperFunction() { - const demo = new DemoClass(42); - demo.printValue(); - } - - helperFunction(); - - ''' -# --- +# serializer version: 1 +# name: test_delete_symbol[test_case0] + ''' + """ + Test module for variable declarations and usage. + + This module tests various types of variable declarations and usages including: + - Module-level variables + - Class-level variables + - Instance variables + - Variable reassignments + """ + + from dataclasses import dataclass, field + + # Module-level variables + module_var = "Initial module value" + + reassignable_module_var = 10 + reassignable_module_var = 20 # Reassigned + + # Module-level variable with type annotation + typed_module_var: int = 42 + + + # Regular class with class and instance variables + + + + # Dataclass with variables + @dataclass + class VariableDataclass: + """Dataclass that contains various fields.""" + + # Field variables with type annotations + id: int + name: str + items: list[str] = field(default_factory=list) + metadata: dict[str, str] = field(default_factory=dict) + optional_value: float | None = None + + # This will be reassigned in various places + status: str = "pending" + + + # Function that uses the module variables + def use_module_variables(): + """Function that uses module-level variables.""" + result = module_var + " used in function" + other_result = reassignable_module_var * 2 + return result, other_result + + + # Create instances and use variables + dataclass_instance = VariableDataclass(id=1, name="Test") + dataclass_instance.status = "active" # Reassign dataclass field + + # Use variables at module level + module_result = module_var + " used at module level" + other_module_result = reassignable_module_var + 30 + + # Create a second dataclass instance with different status + second_dataclass = VariableDataclass(id=2, name="Another Test") + second_dataclass.status = "completed" # Another reassignment of status + + ''' +# --- +# name: test_delete_symbol[test_case1] + ''' + + + export function helperFunction() { + const demo = new DemoClass(42); + demo.printValue(); + } + + helperFunction(); + + ''' +# --- +# name: test_insert_in_rel_to_symbol[test_case0-after] + ''' + """ + Test module for variable declarations and usage. + + This module tests various types of variable declarations and usages including: + - Module-level variables + - Class-level variables + - Instance variables + - Variable reassignments + """ + + from dataclasses import dataclass, field + + # Module-level variables + module_var = "Initial module value" + + reassignable_module_var = 10 + reassignable_module_var = 20 # Reassigned + + # Module-level variable with type annotation + typed_module_var: int = 42 + new_module_var = "Inserted after typed_module_var" + + + # Regular class with class and instance variables + class VariableContainer: + """Class that contains various variables.""" + + # Class-level variables + class_var = "Initial class value" + + reassignable_class_var = True + reassignable_class_var = False # Reassigned #noqa: PIE794 + + # Class-level variable with type annotation + typed_class_var: str = "typed value" + + def __init__(self): + # Instance variables + self.instance_var = "Initial instance value" + self.reassignable_instance_var = 100 + + # Instance variable with type annotation + self.typed_instance_var: list[str] = ["item1", "item2"] + + def modify_instance_var(self): + # Reassign instance variable + self.instance_var = "Modified instance value" + self.reassignable_instance_var = 200 # Reassigned + + def use_module_var(self): + # Use module-level variables + result = module_var + " used in method" + other_result = reassignable_module_var + 5 + return result, other_result + + def use_class_var(self): + # Use class-level variables + result = VariableContainer.class_var + " used in method" + other_result = VariableContainer.reassignable_class_var + return result, other_result + + + # Dataclass with variables + @dataclass + class VariableDataclass: + """Dataclass that contains various fields.""" + + # Field variables with type annotations + id: int + name: str + items: list[str] = field(default_factory=list) + metadata: dict[str, str] = field(default_factory=dict) + optional_value: float | None = None + + # This will be reassigned in various places + status: str = "pending" + + + # Function that uses the module variables + def use_module_variables(): + """Function that uses module-level variables.""" + result = module_var + " used in function" + other_result = reassignable_module_var * 2 + return result, other_result + + + # Create instances and use variables + dataclass_instance = VariableDataclass(id=1, name="Test") + dataclass_instance.status = "active" # Reassign dataclass field + + # Use variables at module level + module_result = module_var + " used at module level" + other_module_result = reassignable_module_var + 30 + + # Create a second dataclass instance with different status + second_dataclass = VariableDataclass(id=2, name="Another Test") + second_dataclass.status = "completed" # Another reassignment of status + + ''' +# --- +# name: test_insert_in_rel_to_symbol[test_case0-before] + ''' + """ + Test module for variable declarations and usage. + + This module tests various types of variable declarations and usages including: + - Module-level variables + - Class-level variables + - Instance variables + - Variable reassignments + """ + + from dataclasses import dataclass, field + + # Module-level variables + module_var = "Initial module value" + + reassignable_module_var = 10 + reassignable_module_var = 20 # Reassigned + + # Module-level variable with type annotation + new_module_var = "Inserted after typed_module_var" + typed_module_var: int = 42 + + + # Regular class with class and instance variables + class VariableContainer: + """Class that contains various variables.""" + + # Class-level variables + class_var = "Initial class value" + + reassignable_class_var = True + reassignable_class_var = False # Reassigned #noqa: PIE794 + + # Class-level variable with type annotation + typed_class_var: str = "typed value" + + def __init__(self): + # Instance variables + self.instance_var = "Initial instance value" + self.reassignable_instance_var = 100 + + # Instance variable with type annotation + self.typed_instance_var: list[str] = ["item1", "item2"] + + def modify_instance_var(self): + # Reassign instance variable + self.instance_var = "Modified instance value" + self.reassignable_instance_var = 200 # Reassigned + + def use_module_var(self): + # Use module-level variables + result = module_var + " used in method" + other_result = reassignable_module_var + 5 + return result, other_result + + def use_class_var(self): + # Use class-level variables + result = VariableContainer.class_var + " used in method" + other_result = VariableContainer.reassignable_class_var + return result, other_result + + + # Dataclass with variables + @dataclass + class VariableDataclass: + """Dataclass that contains various fields.""" + + # Field variables with type annotations + id: int + name: str + items: list[str] = field(default_factory=list) + metadata: dict[str, str] = field(default_factory=dict) + optional_value: float | None = None + + # This will be reassigned in various places + status: str = "pending" + + + # Function that uses the module variables + def use_module_variables(): + """Function that uses module-level variables.""" + result = module_var + " used in function" + other_result = reassignable_module_var * 2 + return result, other_result + + + # Create instances and use variables + dataclass_instance = VariableDataclass(id=1, name="Test") + dataclass_instance.status = "active" # Reassign dataclass field + + # Use variables at module level + module_result = module_var + " used at module level" + other_module_result = reassignable_module_var + 30 + + # Create a second dataclass instance with different status + second_dataclass = VariableDataclass(id=2, name="Another Test") + second_dataclass.status = "completed" # Another reassignment of status + + ''' +# --- +# name: test_insert_in_rel_to_symbol[test_case1-after] + ''' + """ + Test module for variable declarations and usage. + + This module tests various types of variable declarations and usages including: + - Module-level variables + - Class-level variables + - Instance variables + - Variable reassignments + """ + + from dataclasses import dataclass, field + + # Module-level variables + module_var = "Initial module value" + + reassignable_module_var = 10 + reassignable_module_var = 20 # Reassigned + + # Module-level variable with type annotation + typed_module_var: int = 42 + + + # Regular class with class and instance variables + class VariableContainer: + """Class that contains various variables.""" + + # Class-level variables + class_var = "Initial class value" + + reassignable_class_var = True + reassignable_class_var = False # Reassigned #noqa: PIE794 + + # Class-level variable with type annotation + typed_class_var: str = "typed value" + + def __init__(self): + # Instance variables + self.instance_var = "Initial instance value" + self.reassignable_instance_var = 100 + + # Instance variable with type annotation + self.typed_instance_var: list[str] = ["item1", "item2"] + + def modify_instance_var(self): + # Reassign instance variable + self.instance_var = "Modified instance value" + self.reassignable_instance_var = 200 # Reassigned + + def use_module_var(self): + # Use module-level variables + result = module_var + " used in method" + other_result = reassignable_module_var + 5 + return result, other_result + + def use_class_var(self): + # Use class-level variables + result = VariableContainer.class_var + " used in method" + other_result = VariableContainer.reassignable_class_var + return result, other_result + + + # Dataclass with variables + @dataclass + class VariableDataclass: + """Dataclass that contains various fields.""" + + # Field variables with type annotations + id: int + name: str + items: list[str] = field(default_factory=list) + metadata: dict[str, str] = field(default_factory=dict) + optional_value: float | None = None + + # This will be reassigned in various places + status: str = "pending" + + + # Function that uses the module variables + def use_module_variables(): + """Function that uses module-level variables.""" + result = module_var + " used in function" + other_result = reassignable_module_var * 2 + return result, other_result + + def new_inserted_function(): + print("This is a new function inserted before another.") + + + # Create instances and use variables + dataclass_instance = VariableDataclass(id=1, name="Test") + dataclass_instance.status = "active" # Reassign dataclass field + + # Use variables at module level + module_result = module_var + " used at module level" + other_module_result = reassignable_module_var + 30 + + # Create a second dataclass instance with different status + second_dataclass = VariableDataclass(id=2, name="Another Test") + second_dataclass.status = "completed" # Another reassignment of status + + ''' +# --- +# name: test_insert_in_rel_to_symbol[test_case1-before] + ''' + """ + Test module for variable declarations and usage. + + This module tests various types of variable declarations and usages including: + - Module-level variables + - Class-level variables + - Instance variables + - Variable reassignments + """ + + from dataclasses import dataclass, field + + # Module-level variables + module_var = "Initial module value" + + reassignable_module_var = 10 + reassignable_module_var = 20 # Reassigned + + # Module-level variable with type annotation + typed_module_var: int = 42 + + + # Regular class with class and instance variables + class VariableContainer: + """Class that contains various variables.""" + + # Class-level variables + class_var = "Initial class value" + + reassignable_class_var = True + reassignable_class_var = False # Reassigned #noqa: PIE794 + + # Class-level variable with type annotation + typed_class_var: str = "typed value" + + def __init__(self): + # Instance variables + self.instance_var = "Initial instance value" + self.reassignable_instance_var = 100 + + # Instance variable with type annotation + self.typed_instance_var: list[str] = ["item1", "item2"] + + def modify_instance_var(self): + # Reassign instance variable + self.instance_var = "Modified instance value" + self.reassignable_instance_var = 200 # Reassigned + + def use_module_var(self): + # Use module-level variables + result = module_var + " used in method" + other_result = reassignable_module_var + 5 + return result, other_result + + def use_class_var(self): + # Use class-level variables + result = VariableContainer.class_var + " used in method" + other_result = VariableContainer.reassignable_class_var + return result, other_result + + + # Dataclass with variables + @dataclass + class VariableDataclass: + """Dataclass that contains various fields.""" + + # Field variables with type annotations + id: int + name: str + items: list[str] = field(default_factory=list) + metadata: dict[str, str] = field(default_factory=dict) + optional_value: float | None = None + + # This will be reassigned in various places + status: str = "pending" + + + # Function that uses the module variables + def new_inserted_function(): + print("This is a new function inserted before another.") + + def use_module_variables(): + """Function that uses module-level variables.""" + result = module_var + " used in function" + other_result = reassignable_module_var * 2 + return result, other_result + + + # Create instances and use variables + dataclass_instance = VariableDataclass(id=1, name="Test") + dataclass_instance.status = "active" # Reassign dataclass field + + # Use variables at module level + module_result = module_var + " used at module level" + other_module_result = reassignable_module_var + 30 + + # Create a second dataclass instance with different status + second_dataclass = VariableDataclass(id=2, name="Another Test") + second_dataclass.status = "completed" # Another reassignment of status + + ''' +# --- +# name: test_insert_in_rel_to_symbol[test_case2-after] + ''' + export class DemoClass { + value: number; + constructor(value: number) { + this.value = value; + } + printValue() { + console.log(this.value); + } + } + + function newFunctionAfterClass(): void { + console.log("This function is after DemoClass."); + } + + export function helperFunction() { + const demo = new DemoClass(42); + demo.printValue(); + } + + helperFunction(); + + ''' +# --- +# name: test_insert_in_rel_to_symbol[test_case2-before] + ''' + function newFunctionAfterClass(): void { + console.log("This function is after DemoClass."); + } + + export class DemoClass { + value: number; + constructor(value: number) { + this.value = value; + } + printValue() { + console.log(this.value); + } + } + + export function helperFunction() { + const demo = new DemoClass(42); + demo.printValue(); + } + + helperFunction(); + + ''' +# --- +# name: test_insert_in_rel_to_symbol[test_case3-after] + ''' + export class DemoClass { + value: number; + constructor(value: number) { + this.value = value; + } + printValue() { + console.log(this.value); + } + } + + export function helperFunction() { + const demo = new DemoClass(42); + demo.printValue(); + } + + function newInsertedFunction(): void { + console.log("This is a new function inserted before another."); + } + + helperFunction(); + + ''' +# --- +# name: test_insert_in_rel_to_symbol[test_case3-before] + ''' + export class DemoClass { + value: number; + constructor(value: number) { + this.value = value; + } + printValue() { + console.log(this.value); + } + } + + function newInsertedFunction(): void { + console.log("This is a new function inserted before another."); + } + + export function helperFunction() { + const demo = new DemoClass(42); + demo.printValue(); + } + + helperFunction(); + + ''' +# --- +# name: test_insert_python_class_after + ''' + """ + Test module for variable declarations and usage. + + This module tests various types of variable declarations and usages including: + - Module-level variables + - Class-level variables + - Instance variables + - Variable reassignments + """ + + from dataclasses import dataclass, field + + # Module-level variables + module_var = "Initial module value" + + reassignable_module_var = 10 + reassignable_module_var = 20 # Reassigned + + # Module-level variable with type annotation + typed_module_var: int = 42 + + + # Regular class with class and instance variables + class VariableContainer: + """Class that contains various variables.""" + + # Class-level variables + class_var = "Initial class value" + + reassignable_class_var = True + reassignable_class_var = False # Reassigned #noqa: PIE794 + + # Class-level variable with type annotation + typed_class_var: str = "typed value" + + def __init__(self): + # Instance variables + self.instance_var = "Initial instance value" + self.reassignable_instance_var = 100 + + # Instance variable with type annotation + self.typed_instance_var: list[str] = ["item1", "item2"] + + def modify_instance_var(self): + # Reassign instance variable + self.instance_var = "Modified instance value" + self.reassignable_instance_var = 200 # Reassigned + + def use_module_var(self): + # Use module-level variables + result = module_var + " used in method" + other_result = reassignable_module_var + 5 + return result, other_result + + def use_class_var(self): + # Use class-level variables + result = VariableContainer.class_var + " used in method" + other_result = VariableContainer.reassignable_class_var + return result, other_result + + + # Dataclass with variables + @dataclass + class VariableDataclass: + """Dataclass that contains various fields.""" + + # Field variables with type annotations + id: int + name: str + items: list[str] = field(default_factory=list) + metadata: dict[str, str] = field(default_factory=dict) + optional_value: float | None = None + + # This will be reassigned in various places + status: str = "pending" + + + class NewInsertedClass: + pass + + + # Function that uses the module variables + def use_module_variables(): + """Function that uses module-level variables.""" + result = module_var + " used in function" + other_result = reassignable_module_var * 2 + return result, other_result + + + # Create instances and use variables + dataclass_instance = VariableDataclass(id=1, name="Test") + dataclass_instance.status = "active" # Reassign dataclass field + + # Use variables at module level + module_result = module_var + " used at module level" + other_module_result = reassignable_module_var + 30 + + # Create a second dataclass instance with different status + second_dataclass = VariableDataclass(id=2, name="Another Test") + second_dataclass.status = "completed" # Another reassignment of status + + ''' +# --- +# name: test_insert_python_class_before + ''' + """ + Test module for variable declarations and usage. + + This module tests various types of variable declarations and usages including: + - Module-level variables + - Class-level variables + - Instance variables + - Variable reassignments + """ + + from dataclasses import dataclass, field + + # Module-level variables + module_var = "Initial module value" + + reassignable_module_var = 10 + reassignable_module_var = 20 # Reassigned + + # Module-level variable with type annotation + typed_module_var: int = 42 + + + # Regular class with class and instance variables + class VariableContainer: + """Class that contains various variables.""" + + # Class-level variables + class_var = "Initial class value" + + reassignable_class_var = True + reassignable_class_var = False # Reassigned #noqa: PIE794 + + # Class-level variable with type annotation + typed_class_var: str = "typed value" + + def __init__(self): + # Instance variables + self.instance_var = "Initial instance value" + self.reassignable_instance_var = 100 + + # Instance variable with type annotation + self.typed_instance_var: list[str] = ["item1", "item2"] + + def modify_instance_var(self): + # Reassign instance variable + self.instance_var = "Modified instance value" + self.reassignable_instance_var = 200 # Reassigned + + def use_module_var(self): + # Use module-level variables + result = module_var + " used in method" + other_result = reassignable_module_var + 5 + return result, other_result + + def use_class_var(self): + # Use class-level variables + result = VariableContainer.class_var + " used in method" + other_result = VariableContainer.reassignable_class_var + return result, other_result + + + # Dataclass with variables + class NewInsertedClass: + pass + + + @dataclass + class VariableDataclass: + """Dataclass that contains various fields.""" + + # Field variables with type annotations + id: int + name: str + items: list[str] = field(default_factory=list) + metadata: dict[str, str] = field(default_factory=dict) + optional_value: float | None = None + + # This will be reassigned in various places + status: str = "pending" + + + # Function that uses the module variables + def use_module_variables(): + """Function that uses module-level variables.""" + result = module_var + " used in function" + other_result = reassignable_module_var * 2 + return result, other_result + + + # Create instances and use variables + dataclass_instance = VariableDataclass(id=1, name="Test") + dataclass_instance.status = "active" # Reassign dataclass field + + # Use variables at module level + module_result = module_var + " used at module level" + other_module_result = reassignable_module_var + 30 + + # Create a second dataclass instance with different status + second_dataclass = VariableDataclass(id=2, name="Another Test") + second_dataclass.status = "completed" # Another reassignment of status + + ''' +# --- +# name: test_replace_body[test_case0] + ''' + """ + Test module for variable declarations and usage. + + This module tests various types of variable declarations and usages including: + - Module-level variables + - Class-level variables + - Instance variables + - Variable reassignments + """ + + from dataclasses import dataclass, field + + # Module-level variables + module_var = "Initial module value" + + reassignable_module_var = 10 + reassignable_module_var = 20 # Reassigned + + # Module-level variable with type annotation + typed_module_var: int = 42 + + + # Regular class with class and instance variables + class VariableContainer: + """Class that contains various variables.""" + + # Class-level variables + class_var = "Initial class value" + + reassignable_class_var = True + reassignable_class_var = False # Reassigned #noqa: PIE794 + + # Class-level variable with type annotation + typed_class_var: str = "typed value" + + def __init__(self): + # Instance variables + self.instance_var = "Initial instance value" + self.reassignable_instance_var = 100 + + # Instance variable with type annotation + self.typed_instance_var: list[str] = ["item1", "item2"] + + def modify_instance_var(self): + # This body has been replaced + self.instance_var = "Replaced!" + self.reassignable_instance_var = 999 # Reassigned + + def use_module_var(self): + # Use module-level variables + result = module_var + " used in method" + other_result = reassignable_module_var + 5 + return result, other_result + + def use_class_var(self): + # Use class-level variables + result = VariableContainer.class_var + " used in method" + other_result = VariableContainer.reassignable_class_var + return result, other_result + + + # Dataclass with variables + @dataclass + class VariableDataclass: + """Dataclass that contains various fields.""" + + # Field variables with type annotations + id: int + name: str + items: list[str] = field(default_factory=list) + metadata: dict[str, str] = field(default_factory=dict) + optional_value: float | None = None + + # This will be reassigned in various places + status: str = "pending" + + + # Function that uses the module variables + def use_module_variables(): + """Function that uses module-level variables.""" + result = module_var + " used in function" + other_result = reassignable_module_var * 2 + return result, other_result + + + # Create instances and use variables + dataclass_instance = VariableDataclass(id=1, name="Test") + dataclass_instance.status = "active" # Reassign dataclass field + + # Use variables at module level + module_result = module_var + " used at module level" + other_module_result = reassignable_module_var + 30 + + # Create a second dataclass instance with different status + second_dataclass = VariableDataclass(id=2, name="Another Test") + second_dataclass.status = "completed" # Another reassignment of status + + ''' +# --- +# name: test_replace_body[test_case1] + ''' + export class DemoClass { + value: number; + constructor(value: number) { + this.value = value; + } + function printValue() { + // This body has been replaced + console.warn("New value: " + this.value); + } + } + + export function helperFunction() { + const demo = new DemoClass(42); + demo.printValue(); + } + + helperFunction(); + + ''' +# --- From 4e6ad37e26fd2f6087d28807914a2f28bdafadc5 Mon Sep 17 00:00:00 2001 From: Michael Panchenko Date: Mon, 23 Jun 2025 20:33:04 +0200 Subject: [PATCH 12/14] Changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f2eabb38..575952dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,8 @@ Status of the `main` branch. Changes prior to the next official version change w Fixes: * Fix `ExecuteShellCommandTool` and `GetCurrentConfigTool` hanging on Windows * Fix project activation by name via `--project` not working (was broken in previous release) +* Improve handling of indentation and newlines in symbolic editing tools +* Fix that `insert_after_symbol` was failing for insertions at the end of a file that did not end with a newline # 2025-06-20 From b951331764808d47a3d5993e8364b19100e8ec7e Mon Sep 17 00:00:00 2001 From: Michael Panchenko Date: Mon, 23 Jun 2025 20:40:52 +0200 Subject: [PATCH 13/14] Formatting, removing mentions of multilspy in pyproject --- pyproject.toml | 6 +++--- .../clangd_language_server.py | 4 ++-- .../dart_language_server.py | 2 +- .../eclipse_jdtls/eclipse_jdtls.py | 6 +++--- src/solidlsp/language_servers/gopls/gopls.py | 4 ++-- .../intelephense/intelephense.py | 4 ++-- .../jedi_language_server/jedi_server.py | 4 ++-- .../kotlin_language_server.py | 4 ++-- .../language_servers/omnisharp/omnisharp.py | 4 ++-- .../pyright_language_server/pyright_server.py | 4 ++-- .../rust_analyzer/rust_analyzer.py | 4 ++-- .../language_servers/solargraph/solargraph.py | 4 ++-- .../typescript_language_server.py | 4 ++-- src/solidlsp/ls.py | 20 +++++++------------ src/solidlsp/ls_handler.py | 4 ++-- src/solidlsp/ls_utils.py | 4 ++-- src/solidlsp/lsp_protocol_handler/server.py | 8 -------- 17 files changed, 38 insertions(+), 52 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index d3ba68a9..4ac950b3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -73,7 +73,7 @@ google = [ Homepage = "https://github.com/oraios/serena" [tool.hatch.build.targets.wheel] -packages = ["src/serena", "src/multilspy", "src/interprompt", "src/solidlsp"] +packages = ["src/serena", "src/interprompt", "src/solidlsp"] [tool.black] line-length = 140 @@ -82,7 +82,7 @@ target-version = [ ] exclude = ''' /( - src/multilspy + src/solidlsp/language_servers/.*/static, )/ ''' @@ -138,7 +138,7 @@ type-check = [ target-version = "py311" line-length = 140 exclude = [ - "src/multilspy", + "src/solidlsp/language_servers/**/static", ] [tool.ruff.format] diff --git a/src/solidlsp/language_servers/clangd_language_server/clangd_language_server.py b/src/solidlsp/language_servers/clangd_language_server/clangd_language_server.py index 4572de90..893c5cc7 100644 --- a/src/solidlsp/language_servers/clangd_language_server/clangd_language_server.py +++ b/src/solidlsp/language_servers/clangd_language_server/clangd_language_server.py @@ -10,11 +10,11 @@ import stat import threading from solidlsp.ls import SolidLanguageServer -from solidlsp.lsp_protocol_handler.lsp_types import InitializeParams -from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo from solidlsp.ls_config import LanguageServerConfig from solidlsp.ls_logger import LanguageServerLogger from solidlsp.ls_utils import FileUtils, PlatformUtils +from solidlsp.lsp_protocol_handler.lsp_types import InitializeParams +from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo class ClangdLanguageServer(SolidLanguageServer): diff --git a/src/solidlsp/language_servers/dart_language_server/dart_language_server.py b/src/solidlsp/language_servers/dart_language_server/dart_language_server.py index 59575581..58d71014 100644 --- a/src/solidlsp/language_servers/dart_language_server/dart_language_server.py +++ b/src/solidlsp/language_servers/dart_language_server/dart_language_server.py @@ -5,9 +5,9 @@ import pathlib import stat from solidlsp.ls import SolidLanguageServer -from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo from solidlsp.ls_logger import LanguageServerLogger from solidlsp.ls_utils import FileUtils, PlatformUtils +from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo class DartLanguageServer(SolidLanguageServer): diff --git a/src/solidlsp/language_servers/eclipse_jdtls/eclipse_jdtls.py b/src/solidlsp/language_servers/eclipse_jdtls/eclipse_jdtls.py index a2453fae..7453bf15 100644 --- a/src/solidlsp/language_servers/eclipse_jdtls/eclipse_jdtls.py +++ b/src/solidlsp/language_servers/eclipse_jdtls/eclipse_jdtls.py @@ -16,12 +16,12 @@ from pathlib import PurePath from overrides import override from solidlsp.ls import SolidLanguageServer -from solidlsp.lsp_protocol_handler.lsp_types import InitializeParams -from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo from solidlsp.ls_config import LanguageServerConfig from solidlsp.ls_logger import LanguageServerLogger -from solidlsp.settings import SolidLSPSettings from solidlsp.ls_utils import FileUtils, PlatformUtils +from solidlsp.lsp_protocol_handler.lsp_types import InitializeParams +from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo +from solidlsp.settings import SolidLSPSettings @dataclasses.dataclass diff --git a/src/solidlsp/language_servers/gopls/gopls.py b/src/solidlsp/language_servers/gopls/gopls.py index 32ae5e5c..c3fadd71 100644 --- a/src/solidlsp/language_servers/gopls/gopls.py +++ b/src/solidlsp/language_servers/gopls/gopls.py @@ -8,10 +8,10 @@ import threading from overrides import override from solidlsp.ls import SolidLanguageServer -from solidlsp.lsp_protocol_handler.lsp_types import InitializeParams -from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo from solidlsp.ls_config import LanguageServerConfig from solidlsp.ls_logger import LanguageServerLogger +from solidlsp.lsp_protocol_handler.lsp_types import InitializeParams +from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo class Gopls(SolidLanguageServer): diff --git a/src/solidlsp/language_servers/intelephense/intelephense.py b/src/solidlsp/language_servers/intelephense/intelephense.py index a02f9d18..19eaa8b1 100644 --- a/src/solidlsp/language_servers/intelephense/intelephense.py +++ b/src/solidlsp/language_servers/intelephense/intelephense.py @@ -13,11 +13,11 @@ from time import sleep from overrides import override from solidlsp.ls import SolidLanguageServer -from solidlsp.lsp_protocol_handler.lsp_types import DefinitionParams, InitializeParams -from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo from solidlsp.ls_config import LanguageServerConfig from solidlsp.ls_logger import LanguageServerLogger from solidlsp.ls_utils import PlatformId, PlatformUtils +from solidlsp.lsp_protocol_handler.lsp_types import DefinitionParams, InitializeParams +from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo class Intelephense(SolidLanguageServer): diff --git a/src/solidlsp/language_servers/jedi_language_server/jedi_server.py b/src/solidlsp/language_servers/jedi_language_server/jedi_server.py index a0ea2030..467d3cab 100644 --- a/src/solidlsp/language_servers/jedi_language_server/jedi_server.py +++ b/src/solidlsp/language_servers/jedi_language_server/jedi_server.py @@ -10,10 +10,10 @@ import pathlib from overrides import override from solidlsp.ls import SolidLanguageServer -from solidlsp.lsp_protocol_handler.lsp_types import InitializeParams -from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo from solidlsp.ls_config import LanguageServerConfig from solidlsp.ls_logger import LanguageServerLogger +from solidlsp.lsp_protocol_handler.lsp_types import InitializeParams +from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo class JediServer(SolidLanguageServer): diff --git a/src/solidlsp/language_servers/kotlin_language_server/kotlin_language_server.py b/src/solidlsp/language_servers/kotlin_language_server/kotlin_language_server.py index 30315357..6ddab2c7 100644 --- a/src/solidlsp/language_servers/kotlin_language_server/kotlin_language_server.py +++ b/src/solidlsp/language_servers/kotlin_language_server/kotlin_language_server.py @@ -10,11 +10,11 @@ import pathlib import stat from solidlsp.ls import SolidLanguageServer -from solidlsp.lsp_protocol_handler.lsp_types import InitializeParams -from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo from solidlsp.ls_config import LanguageServerConfig from solidlsp.ls_logger import LanguageServerLogger from solidlsp.ls_utils import FileUtils, PlatformUtils +from solidlsp.lsp_protocol_handler.lsp_types import InitializeParams +from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo @dataclasses.dataclass diff --git a/src/solidlsp/language_servers/omnisharp/omnisharp.py b/src/solidlsp/language_servers/omnisharp/omnisharp.py index 0a0216cd..e66540ca 100644 --- a/src/solidlsp/language_servers/omnisharp/omnisharp.py +++ b/src/solidlsp/language_servers/omnisharp/omnisharp.py @@ -13,12 +13,12 @@ from collections.abc import Iterable from overrides import override from solidlsp.ls import SolidLanguageServer -from solidlsp.lsp_protocol_handler.lsp_types import InitializeParams -from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo from solidlsp.ls_config import LanguageServerConfig from solidlsp.ls_exceptions import LanguageServerException from solidlsp.ls_logger import LanguageServerLogger from solidlsp.ls_utils import DotnetVersion, FileUtils, PlatformId, PlatformUtils +from solidlsp.lsp_protocol_handler.lsp_types import InitializeParams +from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo def breadth_first_file_scan(root) -> Iterable[str]: diff --git a/src/solidlsp/language_servers/pyright_language_server/pyright_server.py b/src/solidlsp/language_servers/pyright_language_server/pyright_server.py index 64dbd574..893db94e 100644 --- a/src/solidlsp/language_servers/pyright_language_server/pyright_server.py +++ b/src/solidlsp/language_servers/pyright_language_server/pyright_server.py @@ -11,10 +11,10 @@ import threading from overrides import override from solidlsp.ls import SolidLanguageServer -from solidlsp.lsp_protocol_handler.lsp_types import InitializeParams -from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo from solidlsp.ls_config import LanguageServerConfig from solidlsp.ls_logger import LanguageServerLogger +from solidlsp.lsp_protocol_handler.lsp_types import InitializeParams +from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo class PyrightServer(SolidLanguageServer): diff --git a/src/solidlsp/language_servers/rust_analyzer/rust_analyzer.py b/src/solidlsp/language_servers/rust_analyzer/rust_analyzer.py index a21768ef..1f951e5c 100644 --- a/src/solidlsp/language_servers/rust_analyzer/rust_analyzer.py +++ b/src/solidlsp/language_servers/rust_analyzer/rust_analyzer.py @@ -12,11 +12,11 @@ import threading from overrides import override from solidlsp.ls import SolidLanguageServer -from solidlsp.lsp_protocol_handler.lsp_types import InitializeParams -from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo from solidlsp.ls_config import LanguageServerConfig from solidlsp.ls_logger import LanguageServerLogger from solidlsp.ls_utils import FileUtils, PlatformUtils +from solidlsp.lsp_protocol_handler.lsp_types import InitializeParams +from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo class RustAnalyzer(SolidLanguageServer): diff --git a/src/solidlsp/language_servers/solargraph/solargraph.py b/src/solidlsp/language_servers/solargraph/solargraph.py index 07cc1b38..116e04b0 100644 --- a/src/solidlsp/language_servers/solargraph/solargraph.py +++ b/src/solidlsp/language_servers/solargraph/solargraph.py @@ -13,10 +13,10 @@ import threading from typing import override from solidlsp.ls import SolidLanguageServer -from solidlsp.lsp_protocol_handler.lsp_types import InitializeParams -from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo from solidlsp.ls_config import LanguageServerConfig from solidlsp.ls_logger import LanguageServerLogger +from solidlsp.lsp_protocol_handler.lsp_types import InitializeParams +from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo class Solargraph(SolidLanguageServer): diff --git a/src/solidlsp/language_servers/typescript_language_server/typescript_language_server.py b/src/solidlsp/language_servers/typescript_language_server/typescript_language_server.py index dd1d230a..f2204065 100644 --- a/src/solidlsp/language_servers/typescript_language_server/typescript_language_server.py +++ b/src/solidlsp/language_servers/typescript_language_server/typescript_language_server.py @@ -14,11 +14,11 @@ from time import sleep from overrides import override from solidlsp.ls import SolidLanguageServer -from solidlsp.lsp_protocol_handler.lsp_types import InitializeParams -from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo from solidlsp.ls_config import LanguageServerConfig from solidlsp.ls_logger import LanguageServerLogger from solidlsp.ls_utils import PlatformId, PlatformUtils +from solidlsp.lsp_protocol_handler.lsp_types import InitializeParams +from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo # Platform-specific imports if os.name != "nt": # Unix-like systems diff --git a/src/solidlsp/ls.py b/src/solidlsp/ls.py index 426d471e..0d4dcaa8 100644 --- a/src/solidlsp/ls.py +++ b/src/solidlsp/ls.py @@ -20,7 +20,11 @@ import tqdm from serena.text_utils import MatchedConsecutiveLines, search_files from solidlsp import ls_types +from solidlsp.ls_config import Language, LanguageServerConfig +from solidlsp.ls_exceptions import LanguageServerException from solidlsp.ls_handler import SolidLanguageServerHandler +from solidlsp.ls_logger import LanguageServerLogger +from solidlsp.ls_utils import FileUtils, PathUtils, TextUtils from solidlsp.lsp_protocol_handler import lsp_types from solidlsp.lsp_protocol_handler import lsp_types as LSPTypes from solidlsp.lsp_protocol_handler.lsp_constants import LSPConstants @@ -30,10 +34,6 @@ from solidlsp.lsp_protocol_handler.server import ( ProcessLaunchInfo, StringDict, ) -from solidlsp.ls_config import Language, LanguageServerConfig -from solidlsp.ls_exceptions import LanguageServerException -from solidlsp.ls_logger import LanguageServerLogger -from solidlsp.ls_utils import FileUtils, PathUtils, TextUtils GenericDocumentSymbol = Union[LSPTypes.DocumentSymbol, LSPTypes.SymbolInformation, ls_types.UnifiedSymbolInformation] @@ -409,9 +409,7 @@ class SolidLanguageServer(ABC): ) del self.open_file_buffers[uri] - def insert_text_at_position( - self, relative_file_path: str, line: int, column: int, text_to_be_inserted: str - ) -> ls_types.Position: + def insert_text_at_position(self, relative_file_path: str, line: int, column: int, text_to_be_inserted: str) -> ls_types.Position: """ Insert text at the given line and column in the given file and return the updated cursor position after inserting the text. @@ -1035,9 +1033,7 @@ class SolidLanguageServer(ABC): lines = file_content.split("\n") end_line = len(lines) end_column = len(lines[-1]) - return ls_types.Range( - start=ls_types.Position(line=0, character=0), end=ls_types.Position(line=end_line, character=end_column) - ) + return ls_types.Range(start=ls_types.Position(line=0, character=0), end=ls_types.Position(line=end_line, character=end_column)) def request_dir_overview(self, relative_dir_path: str) -> dict[str, list[tuple[str, ls_types.SymbolKind, int, int]]]: """ @@ -1139,9 +1135,7 @@ class SolidLanguageServer(ABC): # ----------------------------- FROM HERE ON MODIFICATIONS BY MISCHA -------------------- - def retrieve_symbol_body( - self, symbol: ls_types.UnifiedSymbolInformation | LSPTypes.DocumentSymbol | LSPTypes.SymbolInformation - ) -> str: + def retrieve_symbol_body(self, symbol: ls_types.UnifiedSymbolInformation | LSPTypes.DocumentSymbol | LSPTypes.SymbolInformation) -> str: """ Load the body of the given symbol. If the body is already contained in the symbol, just return it. """ diff --git a/src/solidlsp/ls_handler.py b/src/solidlsp/ls_handler.py index 6de9ef7e..458a0236 100644 --- a/src/solidlsp/ls_handler.py +++ b/src/solidlsp/ls_handler.py @@ -12,6 +12,8 @@ from typing import Any import psutil +from solidlsp.ls_exceptions import LanguageServerException +from solidlsp.ls_request import LanguageServerRequest from solidlsp.lsp_protocol_handler.lsp_requests import LspNotification from solidlsp.lsp_protocol_handler.lsp_types import ErrorCodes from solidlsp.lsp_protocol_handler.server import ( @@ -28,8 +30,6 @@ from solidlsp.lsp_protocol_handler.server import ( make_request, make_response, ) -from solidlsp.ls_request import LanguageServerRequest -from solidlsp.ls_exceptions import LanguageServerException log = logging.getLogger(__name__) diff --git a/src/solidlsp/ls_utils.py b/src/solidlsp/ls_utils.py index 39a1d914..7aa610ed 100644 --- a/src/solidlsp/ls_utils.py +++ b/src/solidlsp/ls_utils.py @@ -54,7 +54,7 @@ class TextUtils: idx = 0 while line > 0: if idx >= len(text): - raise InvalidTextLocationError() + raise InvalidTextLocationError if text[idx] == "\n": line -= 1 idx += 1 @@ -95,7 +95,7 @@ class TextUtils: """ try: change_index = TextUtils.get_index_from_line_col(text, line, col) - except InvalidTextLocationError as e: + except InvalidTextLocationError: num_lines_in_text = text.count("\n") + 1 max_line = num_lines_in_text - 1 if line == max_line + 1 and col == 0: # trying to insert at new line after full text diff --git a/src/solidlsp/lsp_protocol_handler/server.py b/src/solidlsp/lsp_protocol_handler/server.py index 0a001f44..5045312c 100644 --- a/src/solidlsp/lsp_protocol_handler/server.py +++ b/src/solidlsp/lsp_protocol_handler/server.py @@ -28,19 +28,12 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ -import asyncio import dataclasses import json import logging import os -import threading -from collections.abc import Callable from typing import Any, Union -import psutil - -from ..ls_exceptions import LanguageServerException -from .lsp_requests import LspNotification, LspRequest from .lsp_types import ErrorCodes StringDict = dict[str, Any] @@ -127,4 +120,3 @@ def content_length(line: bytes) -> int | None: except ValueError: raise ValueError(f"Invalid Content-Length header: {value}") return None - From dfc841857e34f8c5098db397166754fc2a11ff2e Mon Sep 17 00:00:00 2001 From: Michael Panchenko Date: Mon, 23 Jun 2025 20:44:42 +0200 Subject: [PATCH 14/14] Typo --- src/serena/symbol.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/serena/symbol.py b/src/serena/symbol.py index 5f5fbf14..0f48bb54 100644 --- a/src/serena/symbol.py +++ b/src/serena/symbol.py @@ -767,7 +767,7 @@ class SymbolManager: col = 0 line = pos["line"] + 1 # make sure a suitable number of leading empty lines is used (at least 0/1 depending on the symbol type, - # otherweise as many as the caller wanted to insert) + # otherwise as many as the caller wanted to insert) original_leading_newlines = self._count_leading_newlines(body) body = body.lstrip("\r\n") min_empty_lines = 0