From 2ffeb4e926b5f4835efba54f81c3e210cfcce66c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=ED=83=9C=ED=98=B8?= Date: Sun, 26 Mar 2023 15:27:51 +0900 Subject: [PATCH] feat: append codeeditor.summary (#9) --- core/editor/read.py | 140 +++++++++++++++++++++++++++++++++++++++++++- core/tools/cpu.py | 22 ++++++- 2 files changed, 160 insertions(+), 2 deletions(-) diff --git a/core/editor/read.py b/core/editor/read.py index c22624f..42bac94 100644 --- a/core/editor/read.py +++ b/core/editor/read.py @@ -3,6 +3,98 @@ read protocol: |- """ +from typing import Optional, List, Tuple + + +class Line: + def __init__(self, content: str, line_number: int, depth: int): + self.__content: str = content + self.__line_number: int = line_number + self.__depth: int = depth + self.__children: List[Line] = [] + + def get_content(self) -> str: + return self.__content + + def get_depth(self) -> int: + return self.__depth + + def append_child(self, child: "Line") -> None: + self.__children.append(child) + + def find_by_lte_depth(self, depth: int) -> List["Line"]: + if self.__depth > depth: + return [] + + lines: List[Line] = [self] + for child in self.__children: + lines += child.find_by_lte_depth(depth) + return lines + + def find_by_content(self, content: str) -> List["Line"]: + if content in self.__content: + return [self] + + lines: List[Line] = [] + for child in self.__children: + lines += child.find_by_content(content) + return lines + + def find_last_lines(self) -> List["Line"]: + if len(self.__children) == 0: + return [self] + else: + return [self, *self.__children[-1].find_last_lines()] + + def print(self, depth: int = 0) -> None: + print(f"{' ' * depth}{self}", end="") + for child in self.__children: + child.print(depth + 1) + + def __repr__(self): + return f"{self.__line_number}: {self.__content}" + + +class CodeTree: + def __init__(self): + self.root: Line = Line("\n", -1, -1) + + def append(self, content: str, line_number: int) -> None: + last_lines: List[Line] = self.root.find_last_lines() + new_leading_spaces: int = self.__get_leading_spaces(content) + + previous_line: Line = self.root + previous_leading_spaces: int = -1 + for line in last_lines: + leading_spaces = self.__get_leading_spaces(line.get_content()) + if ( + previous_leading_spaces < new_leading_spaces + and new_leading_spaces <= leading_spaces + ): + break + previous_line, previous_leading_spaces = line, leading_spaces + + new_line_depth: int = previous_line.get_depth() + 1 + previous_line.append_child(Line(content, line_number, new_line_depth)) + + def find_from_root(self, depth: int) -> List[Line]: + return self.root.find_by_lte_depth(depth) + + def find_from_parent(self, depth: int, parent_content: str) -> List[Line]: + lines: List[Line] = self.root.find_by_content(parent_content) + if len(lines) == 0: + return [] + parent = lines[0] + return parent.find_by_lte_depth(depth + parent.get_depth()) + + def print(self): + print("Code Tree:") + print("=================================") + self.root.print() + print("=================================") + + def __get_leading_spaces(self, content: str) -> int: + return len(content) - len(content.lstrip()) class ReadCommand: @@ -13,9 +105,10 @@ class ReadCommand: self.start: int = start self.end: int = end - def execute(self): + def execute(self) -> str: with open(self.filepath, "r") as f: code = f.readlines() + if self.start == self.end: code = code[self.start - 1] else: @@ -29,7 +122,52 @@ class ReadCommand: return ReadCommand(filepath, int(start), int(end)) +class SummaryCommand: + separator = "|" + + def __init__(self, filepath: str, depth: int, parent_content: Optional[str] = None): + self.filepath: str = filepath + self.depth: int = depth + self.parent_content: Optional[str] = parent_content + + def execute(self) -> str: + with open(self.filepath, "r") as f: + code = f.readlines() + + code_tree = CodeTree() + for i, line in enumerate(code): + if line.strip() != "": + code_tree.append(line, i + 1) + + # code_tree.print() + + if self.parent_content is None: + lines = code_tree.find_from_root(self.depth) + else: + lines = code_tree.find_from_parent(self.depth, self.parent_content) + return "".join([str(line) for line in lines]) + + @staticmethod + def from_str(command: str) -> "SummaryCommand": + command_list: List[str] = command.split(SummaryCommand.separator) + filepath: str = command_list[0] + depth: int = int(command_list[1]) + parent_content: str | None = command_list[2] if len(command_list) == 3 else None + return SummaryCommand( + filepath=filepath, depth=depth, parent_content=parent_content + ) + + class CodeReader: @staticmethod def read(command: str) -> str: return ReadCommand.from_str(command).execute() + + @staticmethod + def summary(command: str) -> str: + return SummaryCommand.from_str(command).execute() + + +if __name__ == "__main__": + summary = CodeReader.summary("read.py|1|class ReadCommand:") + print(summary) diff --git a/core/tools/cpu.py b/core/tools/cpu.py index d18bd8b..ce7a4d5 100644 --- a/core/tools/cpu.py +++ b/core/tools/cpu.py @@ -45,7 +45,7 @@ class CodeEditor(BaseToolSet): @tool( name="CodeEditor.READ", description="Read and understand code. " - "Input should be filename and line number group. ex. test.py,1-10 " + f"Input should be filename and line number group. ex. test.py|1-10 " "and the output will be code. ", ) def read(self, inputs: str) -> str: @@ -60,6 +60,26 @@ class CodeEditor(BaseToolSet): ) return output + @tool( + name="CodeEditor.SUMMARY", + description="Summary code. " + "Read the code structured into a tree. " + "If you set specific line, it will show the code from the specific line. " + "Input should be filename, depth, and specific line if you want. ex. test.py|2 or test.py|3|print('hello world') " + "and the output will be list of (line number: code). ", + ) + def summary(self, inputs: str) -> str: + try: + output = CodeReader.summary(inputs) + except Exception as e: + output = str(e) + + logger.debug( + f"\nProcessed CodeEditor.SUMMARY, Input Commands: {inputs} " + f"Output Answer: {output}" + ) + return output + @tool( name="CodeEditor.APPEND", description="Append code to the existing file. "