diff options
| -rw-r--r-- | continuedev/src/continuedev/__main__.py | 8 | ||||
| -rw-r--r-- | continuedev/src/continuedev/headless/__init__.py | 9 | ||||
| -rw-r--r-- | continuedev/src/continuedev/libs/util/ripgrep.py | 25 | ||||
| -rw-r--r-- | continuedev/src/continuedev/plugins/context_providers/search.py | 29 | ||||
| -rw-r--r-- | continuedev/src/continuedev/plugins/steps/refactor.py | 32 | ||||
| -rw-r--r-- | docs/sidebars.js | 1 | ||||
| -rw-r--r-- | extension/react-app/src/pages/gui.tsx | 20 | 
7 files changed, 83 insertions, 41 deletions
| diff --git a/continuedev/src/continuedev/__main__.py b/continuedev/src/continuedev/__main__.py index efd62d64..52fb85b7 100644 --- a/continuedev/src/continuedev/__main__.py +++ b/continuedev/src/continuedev/__main__.py @@ -1,9 +1,8 @@ -import asyncio  from typing import Optional  import typer -from .headless import start_headless_session +from .headless import run  from .server.main import run_server  app = typer.Typer() @@ -19,10 +18,7 @@ def main(      headless: bool = typer.Option(False, help="Run in headless mode"),  ):      if headless: -        loop = asyncio.get_event_loop() -        loop.run_until_complete(start_headless_session(config=config)) -        tasks = asyncio.all_tasks(loop) -        loop.run_until_complete(asyncio.gather(*tasks)) +        run(config)      else:          run_server(port=port, host=host) diff --git a/continuedev/src/continuedev/headless/__init__.py b/continuedev/src/continuedev/headless/__init__.py index 27722ee7..fb2c9768 100644 --- a/continuedev/src/continuedev/headless/__init__.py +++ b/continuedev/src/continuedev/headless/__init__.py @@ -22,9 +22,12 @@ async def start_headless_session(      return await session_manager.new_session(ide, config=config) -def run_step_headless(step: Step): -    config = ContinueConfig() -    config.steps_on_startup = [step] +def run(step_or_config: Union[Step, ContinueConfig]): +    if isinstance(step_or_config, ContinueConfig): +        config = step_or_config +    else: +        config = ContinueConfig() +        config.steps_on_startup = [step_or_config]      loop = asyncio.get_event_loop()      loop.run_until_complete(start_headless_session(config=config)) diff --git a/continuedev/src/continuedev/libs/util/ripgrep.py b/continuedev/src/continuedev/libs/util/ripgrep.py new file mode 100644 index 00000000..f7e0af9a --- /dev/null +++ b/continuedev/src/continuedev/libs/util/ripgrep.py @@ -0,0 +1,25 @@ +import os + + +def get_rg_path(): +    if os.name == "nt": +        paths_to_try = [ +            f"C:\\Users\\{os.getlogin()}\\AppData\\Local\\Programs\\Microsoft VS Code\\resources\\app\\node_modules.asar.unpacked\\@vscode\\ripgrep\\bin\\rg.exe", +            f"C:\\Users\\{os.getlogin()}\\AppData\\Local\\Programs\\Microsoft VS Code\\resources\\app\\node_modules.asar.unpacked\\vscode-ripgrep\\bin\\rg.exe", +        ] +        for path in paths_to_try: +            if os.path.exists(path): +                rg_path = path +                break +    elif os.name == "posix": +        if "darwin" in os.sys.platform: +            rg_path = "/Applications/Visual Studio Code.app/Contents/Resources/app/node_modules.asar.unpacked/@vscode/ripgrep/bin/rg" +        else: +            rg_path = "/usr/share/code/resources/app/node_modules.asar.unpacked/vscode-ripgrep/bin/rg" +    else: +        rg_path = "rg" + +    if not os.path.exists(rg_path): +        rg_path = "rg" + +    return rg_path diff --git a/continuedev/src/continuedev/plugins/context_providers/search.py b/continuedev/src/continuedev/plugins/context_providers/search.py index 4e2e33da..a36b2a0a 100644 --- a/continuedev/src/continuedev/plugins/context_providers/search.py +++ b/continuedev/src/continuedev/plugins/context_providers/search.py @@ -1,4 +1,3 @@ -import os  from typing import List  from pydantic import Field @@ -7,6 +6,7 @@ from ripgrepy import Ripgrepy  from ...core.context import ContextProvider  from ...core.main import ContextItem, ContextItemDescription, ContextItemId  from ...libs.util.logging import logger +from ...libs.util.ripgrep import get_rg_path  from .util import remove_meilisearch_disallowed_chars @@ -36,31 +36,8 @@ class SearchContextProvider(ContextProvider):              ),          ) -    def _get_rg_path(self): -        if os.name == "nt": -            paths_to_try = [ -                f"C:\\Users\\{os.getlogin()}\\AppData\\Local\\Programs\\Microsoft VS Code\\resources\\app\\node_modules.asar.unpacked\\@vscode\\ripgrep\\bin\\rg.exe", -                f"C:\\Users\\{os.getlogin()}\\AppData\\Local\\Programs\\Microsoft VS Code\\resources\\app\\node_modules.asar.unpacked\\vscode-ripgrep\\bin\\rg.exe", -            ] -            for path in paths_to_try: -                if os.path.exists(path): -                    rg_path = path -                    break -        elif os.name == "posix": -            if "darwin" in os.sys.platform: -                rg_path = "/Applications/Visual Studio Code.app/Contents/Resources/app/node_modules.asar.unpacked/@vscode/ripgrep/bin/rg" -            else: -                rg_path = "/usr/share/code/resources/app/node_modules.asar.unpacked/vscode-ripgrep/bin/rg" -        else: -            rg_path = "rg" - -        if not os.path.exists(rg_path): -            rg_path = "rg" - -        return rg_path -      async def _search(self, query: str) -> str: -        rg = Ripgrepy(query, self.workspace_dir, rg_path=self._get_rg_path()) +        rg = Ripgrepy(query, self.workspace_dir, rg_path=get_rg_path())          results = rg.I().context(2).run()          return f"Search results in workspace for '{query}':\n\n{results}" @@ -92,7 +69,7 @@ class SearchContextProvider(ContextProvider):          self.workspace_dir = workspace_dir          try: -            Ripgrepy("", workspace_dir, rg_path=self._get_rg_path()) +            Ripgrepy("", workspace_dir, rg_path=get_rg_path())          except Exception as e:              logger.warning(f"Failed to initialize ripgrepy: {e}")              return [] diff --git a/continuedev/src/continuedev/plugins/steps/refactor.py b/continuedev/src/continuedev/plugins/steps/refactor.py index cfbce662..56e9e09e 100644 --- a/continuedev/src/continuedev/plugins/steps/refactor.py +++ b/continuedev/src/continuedev/plugins/steps/refactor.py @@ -1,10 +1,13 @@  import asyncio -from typing import List +from typing import List, Optional + +from ripgrepy import Ripgrepy  from ...core.main import Step  from ...core.models import Models  from ...core.sdk import ContinueSDK  from ...libs.llm.prompts.edit import simplified_edit_prompt +from ...libs.util.ripgrep import get_rg_path  from ...libs.util.strings import remove_quotes_and_escapes, strip_code_block  from ...libs.util.templating import render_prompt_template  from ...models.filesystem import RangeInFile @@ -32,6 +35,33 @@ class RefactorReferencesStep(Step):          ) +class RefactorBySearchStep(Step): +    name: str = "Refactor by search" + +    pattern: str +    user_input: str + +    rg_path: Optional[str] = None +    "Optional path to ripgrep executable" + +    def get_range_for_result(self, result) -> RangeInFile: +        pass + +    async def run(self, sdk: ContinueSDK): +        rg = Ripgrepy( +            self.pattern, +            sdk.ide.workspace_directory, +            rg_path=self.rg_path or get_rg_path(), +        ) + +        results = rg.I().context(2).run() +        range_in_files = [self.get_range_for_result(result) for result in results] + +        await sdk.run_step( +            ParallelEditStep(user_input=self.user_input, range_in_files=range_in_files) +        ) + +  class ParallelEditStep(Step):      name: str = "Edit multiple ranges in parallel"      user_input: str diff --git a/docs/sidebars.js b/docs/sidebars.js index b6c7b899..d7e0ceda 100644 --- a/docs/sidebars.js +++ b/docs/sidebars.js @@ -40,6 +40,7 @@ const sidebars = {          "walkthroughs/codellama",          "walkthroughs/manually-run-continue",          "walkthroughs/running-continue-without-internet", +        "walkthroughs/headless-mode",        ],      },      "development-data", diff --git a/extension/react-app/src/pages/gui.tsx b/extension/react-app/src/pages/gui.tsx index 35531f8c..9f58c505 100644 --- a/extension/react-app/src/pages/gui.tsx +++ b/extension/react-app/src/pages/gui.tsx @@ -265,7 +265,10 @@ function GUI(props: GUIProps) {                    Continue's OpenAI API key. To keep using Continue, you can                    either use your own API key, or use a local LLM. To read more                    about the options, see our{" "} -                  <a href="https://continue.dev/docs/customization/models"> +                  <a +                    href="https://continue.dev/docs/customization/models" +                    target="_blank" +                  >                      documentation                    </a>                    . If you're just looking for fastest way to keep going, type @@ -433,6 +436,7 @@ function GUI(props: GUIProps) {                  <a                    style={{ color: "inherit" }}                    href="https://continue.dev/docs/troubleshooting" +                  target="_blank"                  >                    Troubleshooting help                  </a> @@ -462,13 +466,19 @@ function GUI(props: GUIProps) {                  cursor: "pointer",                  opacity: 0.7,                }} -              onClick={() => { -                postVscMessage("reloadWindow", {}); -              }}              > -              <u>Reload the window</u> +              <u> +                <a +                  style={{ color: "inherit" }} +                  href="https://continue.dev/docs/walkthroughs/manually-run-continue#recommended-use-the-continuedev-pypi-package" +                  target="_blank" +                > +                  Manually start server +                </a> +              </u>              </p>            </div> +            <div className="w-3/4 m-auto text-center text-xs">              {/* Tip: Drag the Continue logo from the far left of the window to the              right, then toggle Continue using option/alt+command+m. */} | 
