Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add navigation suggestion and file skeleton for view command #41

Draft
wants to merge 4 commits into
base: ht/refactor-nav-commands
Choose a base branch
from

Conversation

ryanhoangt
Copy link
Collaborator

Description

This PR is to:

  • Improve upon the existing view command implementation.

Some remaining TODOs:

  • Max token control
  • Symbol ranking to choose what to show

view command on a file path

{
    "command": "view", 
    "path": "/home/hoang/openhands-aci/openhands_aci/utils/shell.py"
}
New output with navigation suggestion
Here's the result of running `cat -n` on /home/hoang/openhands-aci/openhands_aci/
utils/shell.py:
     1  import os
     2  import subprocess
     3  import time
     4
     5  from openhands_aci.editor.config import MAX_RESPONSE_LEN_CHAR
     6  from openhands_aci.editor.results import maybe_truncate
     7
     8
     9  def run_shell_cmd(
    10      cmd: str,
    11      timeout: float | None = 120.0,  # seconds
    12      truncate_after: int | None = MAX_RESPONSE_LEN_CHAR,
    13  ) -> tuple[int, str, str]:
    14      """Run a shell command synchronously with a timeout.
    15
    16      Args:
    17          cmd: The shell command to run.
    18          timeout: The maximum time to wait for the command to complete.
    19          truncate_after: The maximum number of characters to return for stdout and stderr.
    20
    21      Returns:
    22          A tuple containing the return code, stdout, and stderr.
    23      """
    24
    25      start_time = time.time()
    26
    27      try:
    28          process = subprocess.Popen(
    29              cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True
    30          )
    31
    32          stdout, stderr = process.communicate(timeout=timeout)
    33
    34          return (
    35              process.returncode or 0,
    36              maybe_truncate(stdout, truncate_after=truncate_after),
    37              maybe_truncate(stderr, truncate_after=truncate_after),
    38          )
    39      except subprocess.TimeoutExpired:
    40          process.kill()
    41          elapsed_time = time.time() - start_time
    42          raise TimeoutError(
    43              f"Command '{cmd}' timed out after {elapsed_time:.2f} seconds"
    44          )
    45
    46
    47  def check_tool_installed(tool_name: str) -> bool:
    48      """Check if a tool is installed."""
    49      try:
    50          subprocess.run(
    51              [tool_name, '--version'],
    52              check=True,
    53              cwd=os.getcwd(),
    54              stdout=subprocess.PIPE,
    55              stderr=subprocess.PIPE,
    56          )
    57          return True
    58      except (subprocess.CalledProcessError, FileNotFoundError):
    59          return False
    60

Files that this file uses:
- openhands_aci/editor/results.py (via `maybe_truncate`)

Files that refer to this file:
- tests/unit/test_shell_utils.py (via `run_shell_cmd`, `check_tool_installed`)
- openhands_aci/linter/impl/python.py (via `run_shell_cmd`)
- openhands_aci/editor/editor.py (via `run_shell_cmd`)
<TIP>Use the `jump_to_definition` and `find_references` commands to understand 
more about those class, function/method and how they are used in the codebase.</TIP>

view command on a directory path

{
    "command": "view", 
    "path": "/home/hoang/openhands-aci/openhands_aci/utils"
}
New output with file skeleton
Here's the files with its skeleton (i.e., class, function/method signatures) and 
directories up to 2 levels deep in /home/hoang/openhands-aci/openhands_aci/utils, 
excluding hidden items:
/home/hoang/openhands-aci/openhands_aci/utils
/home/hoang/openhands-aci/openhands_aci/utils/file.py
...⋮...
  7│class GitRepoUtils:
  8│    def __init__(self, abs_repo_path: str) -> None:
  9│        from git import Repo
 10│
 11│        if not Path(abs_repo_path).is_absolute():
 12│            raise ValueError('The path must be absolute')
 13│
 14│        self.repo_path = Path(abs_repo_path)
 15│        try:
 16│            self.repo = Repo(self.repo_path)
 17│        except Exception:
...⋮...
 23│    def get_all_absolute_tracked_files(self, depth: int | None = None) -> list[str]:
...⋮...
 31│    def get_all_relative_tracked_files(self, depth: int | None = None) -> list[str]:
...⋮...
 39│    def get_all_absolute_staged_files(self) -> list[str]:
...⋮...
 44│    def get_absolute_tracked_files_in_directory(
 45│        self, rel_dir_path: str, depth: int | None = None
...⋮...
 57│def get_modified_time(abs_path: str) -> int:
...⋮...
 64│def read_text(abs_path: str) -> str:
...⋮...
/home/hoang/openhands-aci/openhands_aci/utils/shell.py
...⋮...
  9│def run_shell_cmd(
 10│    cmd: str,
 11│    timeout: float | None = 120.0,  # seconds
 12│    truncate_after: int | None = MAX_RESPONSE_LEN_CHAR,
...⋮...
 47│def check_tool_installed(tool_name: str) -> bool:
...⋮...
/home/hoang/openhands-aci/openhands_aci/utils/logger.py

/home/hoang/openhands-aci/openhands_aci/utils/diff.py
...⋮...
  6│def get_diff(old_contents: str, new_contents: str, filepath: str = 'file') -> str:
...⋮...
 21│def parse_diff(diff_patch: str) -> list[whatthepatch.patch.Change]:
...⋮...
/home/hoang/openhands-aci/openhands_aci/utils/__pycache__
/home/hoang/openhands-aci/openhands_aci/utils/__pycache__/path.cpython-312.pyc
/home/hoang/openhands-aci/openhands_aci/utils/__pycache__/shell.cpython-312.pyc
/home/hoang/openhands-aci/openhands_aci/utils/__pycache__/diff.cpython-312.pyc
/home/hoang/openhands-aci/openhands_aci/utils/__pycache__/file.cpython-312.pyc
/home/hoang/openhands-aci/openhands_aci/utils/__pycache__/logger.cpython-312.pyc
/home/hoang/openhands-aci/openhands_aci/utils/path.py
...⋮...
  4│class PathUtils:
  5│    def __init__(self, root: str) -> None:
...⋮...
  8│    def get_absolute_path_str(self, rel_path: str) -> str:
...⋮...
 11│    def get_relative_path_str(self, abs_path: str) -> str:
...⋮...
 14│    def get_depth_from_root(self, abs_path: str) -> int:
...⋮...
 18│def has_image_extension(path: str) -> bool:
...⋮...
 23│def get_depth_of_rel_path(rel_path: str) -> int:
...⋮...

Related Issue

This can be seen as an alternative to the original RepoMap. Progress towards All-Hands-AI/OpenHands#2185

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant