From 21f2550499ac4076f1efa7f1da7eb1168921d698 Mon Sep 17 00:00:00 2001 From: ali Date: Thu, 28 Aug 2025 16:02:42 +0300 Subject: [PATCH 1/4] lsp: get new/modified functions inside a git commit --- codeflash/code_utils/git_utils.py | 10 ++++- codeflash/discovery/functions_to_optimize.py | 15 ++++++-- codeflash/lsp/beta.py | 40 +++++++++++++++++++- 3 files changed, 59 insertions(+), 6 deletions(-) diff --git a/codeflash/code_utils/git_utils.py b/codeflash/code_utils/git_utils.py index 92f2be8a1..c324b2b05 100644 --- a/codeflash/code_utils/git_utils.py +++ b/codeflash/code_utils/git_utils.py @@ -23,12 +23,18 @@ from git import Repo -def get_git_diff(repo_directory: Path | None = None, *, uncommitted_changes: bool = False) -> dict[str, list[int]]: +def get_git_diff( + repo_directory: Path | None = None, *, only_this_commit: Optional[str] = None, uncommitted_changes: bool = False +) -> dict[str, list[int]]: if repo_directory is None: repo_directory = Path.cwd() repository = git.Repo(repo_directory, search_parent_directories=True) commit = repository.head.commit - if uncommitted_changes: + if only_this_commit: + uni_diff_text = repository.git.diff( + only_this_commit + "^1", only_this_commit, ignore_blank_lines=True, ignore_space_at_eol=True + ) + elif uncommitted_changes: uni_diff_text = repository.git.diff(None, "HEAD", ignore_blank_lines=True, ignore_space_at_eol=True) else: uni_diff_text = repository.git.diff( diff --git a/codeflash/discovery/functions_to_optimize.py b/codeflash/discovery/functions_to_optimize.py index 27a46af0a..65bedb54a 100644 --- a/codeflash/discovery/functions_to_optimize.py +++ b/codeflash/discovery/functions_to_optimize.py @@ -232,7 +232,16 @@ def get_functions_to_optimize( def get_functions_within_git_diff(uncommitted_changes: bool) -> dict[str, list[FunctionToOptimize]]: # noqa: FBT001 modified_lines: dict[str, list[int]] = get_git_diff(uncommitted_changes=uncommitted_changes) - modified_functions: dict[str, list[FunctionToOptimize]] = {} + return get_functions_inside_lines(modified_lines) + + +def get_functions_inside_a_commit(commit_hash: str) -> dict[str, list[FunctionToOptimize]]: + modified_lines: dict[str, list[int]] = get_git_diff(only_this_commit=commit_hash) + return get_functions_inside_lines(modified_lines) + + +def get_functions_inside_lines(modified_lines: dict[str, list[int]]) -> dict[str, list[FunctionToOptimize]]: + functions: dict[str, list[FunctionToOptimize]] = {} for path_str, lines_in_file in modified_lines.items(): path = Path(path_str) if not path.exists(): @@ -246,14 +255,14 @@ def get_functions_within_git_diff(uncommitted_changes: bool) -> dict[str, list[F continue function_lines = FunctionVisitor(file_path=str(path)) wrapper.visit(function_lines) - modified_functions[str(path)] = [ + functions[str(path)] = [ function_to_optimize for function_to_optimize in function_lines.functions if (start_line := function_to_optimize.starting_line) is not None and (end_line := function_to_optimize.ending_line) is not None and any(start_line <= line <= end_line for line in lines_in_file) ] - return modified_functions + return functions def get_all_files_and_functions(module_root_path: Path) -> dict[str, list[FunctionToOptimize]]: diff --git a/codeflash/lsp/beta.py b/codeflash/lsp/beta.py index 77d87e8a6..e6882ac5d 100644 --- a/codeflash/lsp/beta.py +++ b/codeflash/lsp/beta.py @@ -13,7 +13,11 @@ from codeflash.cli_cmds.cli import process_pyproject_config from codeflash.code_utils.git_utils import create_diff_patch_from_worktree from codeflash.code_utils.shell_utils import save_api_key_to_rc -from codeflash.discovery.functions_to_optimize import filter_functions, get_functions_within_git_diff +from codeflash.discovery.functions_to_optimize import ( + filter_functions, + get_functions_inside_a_commit, + get_functions_within_git_diff, +) from codeflash.either import is_successful from codeflash.lsp.server import CodeflashLanguageServer, CodeflashLanguageServerProtocol @@ -22,6 +26,8 @@ from lsprotocol import types + from codeflash.discovery.functions_to_optimize import FunctionToOptimize + @dataclass class OptimizableFunctionsParams: @@ -39,9 +45,15 @@ class ProvideApiKeyParams: api_key: str +@dataclass +class OptimizableFunctionsInCommitParams: + commit_hash: str + + server = CodeflashLanguageServer("codeflash-language-server", "v1.0", protocol_cls=CodeflashLanguageServerProtocol) +# TODO: use _group_functions_by_file once https://github.com/codeflash-ai/codeflash/pull/688 is merged @server.feature("getOptimizableFunctionsInCurrentDiff") def get_functions_in_current_git_diff( server: CodeflashLanguageServer, _params: OptimizableFunctionsParams @@ -59,6 +71,32 @@ def get_functions_in_current_git_diff( return {"functions": qualified_names, "status": "success"} +@server.feature("getOptimizableFunctionsInCommit") +def get_functions_in_commit( + server: CodeflashLanguageServer, params: OptimizableFunctionsInCommitParams +) -> dict[str, str | dict[str, list[str]]]: + functions = get_functions_inside_a_commit(params.commit_hash) + file_to_qualified_names = _group_functions_by_file(server, functions) + return {"functions": file_to_qualified_names, "status": "success"} + + +def _group_functions_by_file( + _server: CodeflashLanguageServer, functions: dict[str, list[FunctionToOptimize]] +) -> dict[str, list[str]]: + file_to_funcs_to_optimize, _ = filter_functions( + modified_functions=functions, + tests_root=_server.optimizer.test_cfg.tests_root, + ignore_paths=[], + project_root=_server.optimizer.args.project_root, + module_root=_server.optimizer.args.module_root, + previous_checkpoint_functions={}, + ) + file_to_qualified_names: dict[str, list[str]] = { + str(path): [f.qualified_name for f in funcs] for path, funcs in file_to_funcs_to_optimize.items() + } + return file_to_qualified_names + + @server.feature("getOptimizableFunctions") def get_optimizable_functions( server: CodeflashLanguageServer, params: OptimizableFunctionsParams From b2c76376c330c08c2dc8754297d1010741410501 Mon Sep 17 00:00:00 2001 From: ali Date: Thu, 28 Aug 2025 17:53:11 +0300 Subject: [PATCH 2/4] better name --- codeflash/discovery/functions_to_optimize.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/codeflash/discovery/functions_to_optimize.py b/codeflash/discovery/functions_to_optimize.py index 65bedb54a..9f4db7b5e 100644 --- a/codeflash/discovery/functions_to_optimize.py +++ b/codeflash/discovery/functions_to_optimize.py @@ -232,15 +232,15 @@ def get_functions_to_optimize( def get_functions_within_git_diff(uncommitted_changes: bool) -> dict[str, list[FunctionToOptimize]]: # noqa: FBT001 modified_lines: dict[str, list[int]] = get_git_diff(uncommitted_changes=uncommitted_changes) - return get_functions_inside_lines(modified_lines) + return get_functions_within_lines(modified_lines) def get_functions_inside_a_commit(commit_hash: str) -> dict[str, list[FunctionToOptimize]]: modified_lines: dict[str, list[int]] = get_git_diff(only_this_commit=commit_hash) - return get_functions_inside_lines(modified_lines) + return get_functions_within_lines(modified_lines) -def get_functions_inside_lines(modified_lines: dict[str, list[int]]) -> dict[str, list[FunctionToOptimize]]: +def get_functions_within_lines(modified_lines: dict[str, list[int]]) -> dict[str, list[FunctionToOptimize]]: functions: dict[str, list[FunctionToOptimize]] = {} for path_str, lines_in_file in modified_lines.items(): path = Path(path_str) From 4031e3488689d5eeee360ea7db7e119b3f31f18f Mon Sep 17 00:00:00 2001 From: ali Date: Tue, 2 Sep 2025 01:17:08 +0300 Subject: [PATCH 3/4] refactor --- codeflash/lsp/beta.py | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/codeflash/lsp/beta.py b/codeflash/lsp/beta.py index 2c7f58880..f865f2be2 100644 --- a/codeflash/lsp/beta.py +++ b/codeflash/lsp/beta.py @@ -53,23 +53,12 @@ class OptimizableFunctionsInCommitParams: server = CodeflashLanguageServer("codeflash-language-server", "v1.0", protocol_cls=CodeflashLanguageServerProtocol) -# TODO: use _group_functions_by_file once https://github.com/codeflash-ai/codeflash/pull/688 is merged @server.feature("getOptimizableFunctionsInCurrentDiff") def get_functions_in_current_git_diff( server: CodeflashLanguageServer, _params: OptimizableFunctionsParams ) -> dict[str, str | dict[str, list[str]]]: functions = get_functions_within_git_diff(uncommitted_changes=True) - file_to_funcs_to_optimize, _ = filter_functions( - modified_functions=functions, - tests_root=server.optimizer.test_cfg.tests_root, - ignore_paths=[], - project_root=server.optimizer.args.project_root, - module_root=server.optimizer.args.module_root, - previous_checkpoint_functions={}, - ) - file_to_qualified_names: dict[str, list[str]] = { - str(path): [f.qualified_name for f in funcs] for path, funcs in file_to_funcs_to_optimize.items() - } + file_to_qualified_names = _group_functions_by_file(server, functions) return {"functions": file_to_qualified_names, "status": "success"} From 7a24a50afea96abcff094c006ecd73abd38e1bab Mon Sep 17 00:00:00 2001 From: ali Date: Tue, 2 Sep 2025 01:18:09 +0300 Subject: [PATCH 4/4] revert --- codeflash/lsp/beta.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/codeflash/lsp/beta.py b/codeflash/lsp/beta.py index f865f2be2..a68688ed6 100644 --- a/codeflash/lsp/beta.py +++ b/codeflash/lsp/beta.py @@ -72,14 +72,14 @@ def get_functions_in_commit( def _group_functions_by_file( - _server: CodeflashLanguageServer, functions: dict[str, list[FunctionToOptimize]] + server: CodeflashLanguageServer, functions: dict[str, list[FunctionToOptimize]] ) -> dict[str, list[str]]: file_to_funcs_to_optimize, _ = filter_functions( modified_functions=functions, - tests_root=_server.optimizer.test_cfg.tests_root, + tests_root=server.optimizer.test_cfg.tests_root, ignore_paths=[], - project_root=_server.optimizer.args.project_root, - module_root=_server.optimizer.args.module_root, + project_root=server.optimizer.args.project_root, + module_root=server.optimizer.args.module_root, previous_checkpoint_functions={}, ) file_to_qualified_names: dict[str, list[str]] = {