From 623770e24b4c8b00a58e93a2f9aa63e13e972002 Mon Sep 17 00:00:00 2001 From: Paul Gauthier Date: Thu, 5 Dec 2024 20:41:40 -0800 Subject: [PATCH] refactor: move clipboard context functionality to commands.py --- aider/coders/editor_editblock_coder.py | 46 -------------------------- aider/commands.py | 35 ++++++++++++++++++++ aider/copypaste.py | 3 +- aider/io.py | 16 ++++++--- aider/main.py | 6 +++- 5 files changed, 54 insertions(+), 52 deletions(-) diff --git a/aider/coders/editor_editblock_coder.py b/aider/coders/editor_editblock_coder.py index 5cb79e4f4..301ab14af 100644 --- a/aider/coders/editor_editblock_coder.py +++ b/aider/coders/editor_editblock_coder.py @@ -5,49 +5,3 @@ from .editor_editblock_prompts import EditorEditBlockPrompts class EditorEditBlockCoder(EditBlockCoder): edit_format = "editor-diff" gpt_prompts = EditorEditBlockPrompts() - - def format_chat_markdown(self): - chunks = self.format_chat_chunks() - - markdown = "" - - # Only include specified chunks in order - for messages in [chunks.repo, chunks.readonly_files, chunks.chat_files, chunks.cur]: - for msg in messages: - # Only include user messages - if msg["role"] != "user": - continue - - content = msg["content"] - - # Handle image/multipart content - if isinstance(content, list): - for part in content: - if part.get("type") == "text": - markdown += part["text"] + "\n\n" - else: - markdown += content + "\n\n" - - return markdown.strip() - - def format_chat_chunks(self): - chunks = super().format_chat_chunks() - # Only add reminder if there are current messages - if chunks.cur: - final = chunks.cur[-1] - if self.main_model.reminder == "sys" and self.gpt_prompts.system_reminder: - chunks.reminder = [ - dict( - role="system", - content=self.fmt_system_prompt(self.gpt_prompts.system_reminder), - ) - ] - elif self.main_model.reminder == "user" and final["role"] == "user": - # stuff it into the user message - new_content = ( - final["content"] - + "\n\n" - + self.fmt_system_prompt(self.gpt_prompts.system_reminder) - ) - chunks.cur[-1] = dict(role=final["role"], content=new_content) - return chunks diff --git a/aider/commands.py b/aider/commands.py index 5fc9161c1..017329c2b 100644 --- a/aider/commands.py +++ b/aider/commands.py @@ -1399,6 +1399,41 @@ class Commands: if user_input.strip(): self.io.set_placeholder(user_input.rstrip()) + def cmd_copy_context(self, args=None): + """Copy the current chat context as markdown, suitable to paste into a web UI""" + + chunks = self.coder.format_chat_chunks() + + markdown = "" + + # Only include specified chunks in order + for messages in [chunks.repo, chunks.readonly_files, chunks.chat_files]: + for msg in messages: + # Only include user messages + if msg["role"] != "user": + continue + + content = msg["content"] + + # Handle image/multipart content + if isinstance(content, list): + for part in content: + if part.get("type") == "text": + markdown += part["text"] + "\n\n" + else: + markdown += content + "\n\n" + + markdown += """ +Just tell me how to edit the files to make the changes. +Don't give me back entire files. +Just show me the edits I need to make. + + +""" + + pyperclip.copy(markdown) + self.io.tool_output("Copied context to clipboard.") + def expand_subdir(file_path): if file_path.is_file(): diff --git a/aider/copypaste.py b/aider/copypaste.py index f143954cd..9e56b15cc 100644 --- a/aider/copypaste.py +++ b/aider/copypaste.py @@ -13,6 +13,7 @@ class ClipboardWatcher: self.stop_event = None self.watcher_thread = None self.last_clipboard = None + self.io.clipboard_watcher = self def start(self): """Start watching clipboard for changes""" @@ -25,8 +26,8 @@ class ClipboardWatcher: current = pyperclip.paste() if current != self.last_clipboard: self.last_clipboard = current - self.io.placeholder = current self.io.interrupt_input() + self.io.placeholder = current time.sleep(0.5) except Exception as e: if self.verbose: diff --git a/aider/io.py b/aider/io.py index abb840287..226a50c25 100644 --- a/aider/io.py +++ b/aider/io.py @@ -176,6 +176,7 @@ class AutoCompleter(Completer): class InputOutput: num_error_outputs = 0 num_user_asks = 0 + clipboard_watcher = None def __init__( self, @@ -470,8 +471,11 @@ class InputOutput: self.placeholder = None self.interrupted = False - if not multiline_input and self.file_watcher: - self.file_watcher.start() + if not multiline_input: + if self.file_watcher: + self.file_watcher.start() + if self.clipboard_watcher: + self.clipboard_watcher.start() line = self.prompt_session.prompt( show, @@ -487,8 +491,10 @@ class InputOutput: # Check if we were interrupted by a file change if self.interrupted: - cmd = self.file_watcher.process_changes() - return cmd + line = line or "" + if self.file_watcher: + cmd = self.file_watcher.process_changes() + return cmd except EOFError: return "" @@ -504,6 +510,8 @@ class InputOutput: finally: if self.file_watcher: self.file_watcher.stop() + if self.clipboard_watcher: + self.clipboard_watcher.stop() if line.strip("\r\n") and not multiline_input: stripped = line.strip("\r\n") diff --git a/aider/main.py b/aider/main.py index 1133d8a4a..ba3727d5e 100644 --- a/aider/main.py +++ b/aider/main.py @@ -688,6 +688,10 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F editor_edit_format=args.editor_edit_format, ) + if args.copypaste and args.edit_format is None: + if main_model.edit_format in ("diff", "whole"): + main_model.edit_format = "editor-" + main_model.edit_format + if args.verbose: io.tool_output("Model metadata:") io.tool_output(json.dumps(main_model.info, indent=4)) @@ -828,7 +832,7 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F coder.file_watcher = file_watcher if args.copypaste: - coder.clipboard_watcher = ClipboardWatcher(coder.io, verbose=args.verbose) + ClipboardWatcher(coder.io, verbose=args.verbose) coder.show_announcements()