overwrite
Replace selected text lines with new content in text files. The tool updates files by substituting original lines with specified replacements, handling different line counts.
Instructions
Overwrite the selected lines with new text. Amount of new lines can differ from the original selection
Args: new_lines (dict): Example: {"lines":["line one", "second line"]}
Returns: dict: Diff preview showing the proposed changes, and any syntax errors for JS or Python
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| new_lines | Yes |
Implementation Reference
- src/text_editor/server.py:564-732 (handler)The primary handler function implementing the 'overwrite' tool logic. Verifies selection integrity via ID check, processes new content lines (adding newlines as needed), generates a diff preview with context, performs syntax validation for Python (using Black) and JavaScript/JSX (using Babel), stores pending changes and diff for confirmation, and returns preview or syntax error details.async def overwrite( new_lines: dict, ) -> Dict[str, Any]: """ Overwrite the selected lines with new text. Amount of new lines can differ from the original selection Args: new_lines (dict): Example: {"lines":["line one", "second line"]} Returns: dict: Diff preview showing the proposed changes, and any syntax errors for JS or Python """ new_lines = new_lines.get("lines") if self.current_file_path is None: return {"error": "No file path is set. Use set_file first."} if ( self.selected_start is None or self.selected_end is None or self.selected_id is None ): return {"error": "No selection has been made. Use select tool first."} try: with open(self.current_file_path, "r", encoding="utf-8") as file: lines = file.readlines() except Exception as e: return {"error": f"Error reading file: {str(e)}"} start = self.selected_start end = self.selected_end id = self.selected_id current_content = "".join(lines[start - 1 : end]) computed_id = calculate_id(current_content, start, end) if computed_id != id: return { "error": "id verification failed. The content may have been modified since you last read it." } processed_new_lines = [] for line in new_lines: if not line.endswith("\n"): processed_new_lines.append(line + "\n") else: processed_new_lines.append(line) if ( processed_new_lines and end < len(lines) and not processed_new_lines[-1].endswith("\n") ): processed_new_lines[-1] += "\n" before = lines[: start - 1] after = lines[end:] modified_lines = before + processed_new_lines + after diff_result = generate_diff_preview(lines, modified_lines, start, end) error = None if self.current_file_path.endswith(".py"): full_content = "".join(modified_lines) try: black.format_file_contents( full_content, fast=True, mode=black.Mode(), ) except black.InvalidInput as e: error = { "error": f"Python syntax error: {str(e)}", "diff_lines": diff_result, "auto_cancel": self.fail_on_python_syntax_error, } except Exception as e: if not isinstance(e, NothingChanged): error = { "error": f"Black check raised {type(e)}: {str(e)}", "diff_lines": diff_result, } elif self.enable_js_syntax_check and self.current_file_path.endswith( (".jsx", ".js") ): with tempfile.NamedTemporaryFile( mode="w", suffix=".jsx", delete=False ) as temp: temp_path = temp.name temp.writelines(modified_lines) try: presets = ( ["@babel/preset-react"] if self.current_file_path.endswith(".jsx") else ["@babel/preset-env"] ) cmd = [ "npx", "babel", "--presets", ",".join(presets), "--no-babelrc", temp_path, "--out-file", "/dev/null", # Output to nowhere, we just want to check syntax ] # Execute Babel to transform (which validates syntax) process = subprocess.run(cmd, capture_output=True, text=True) if process.returncode != 0: error_output = process.stderr filtered_lines = [] for line in error_output.split("\n"): if "node_modules/@babel" not in line: filtered_lines.append(line) filtered_error = "\n".join(filtered_lines).strip() if not filtered_error: filtered_error = "JavaScript syntax error detected" error = { "error": f"JavaScript syntax error: {filtered_error}", "diff_lines": diff_result, "auto_cancel": self.fail_on_js_syntax_error, } except Exception as e: os.unlink(temp_path) error = { "error": f"Error checking JavaScript syntax: {str(e)}", "diff_lines": diff_result, } finally: if os.path.exists(temp_path): os.unlink(temp_path) self.pending_modified_lines = modified_lines self.pending_diff = diff_result result = { "status": "preview", "message": "Changes ready to apply. Use confirm() to apply or cancel() to discard.", "diff_lines": diff_result["diff_lines"], "start": start, "end": end, } if error: result.update(error) if error.get("auto_cancel", False): self.pending_modified_lines = None self.pending_diff = None result["status"] = "auto_cancelled" result["message"] = ( "Changes automatically cancelled due to syntax error. The lines are still selected." ) else: result["message"] += ( " It looks like there is a syntax error, but you can choose to fix it in the subsequent edits." ) return result
- src/text_editor/server.py:32-56 (helper)Helper function to compute a unique identifier for selected text content, combining optional line range prefix with truncated SHA-256 hash. Used in 'overwrite' for verifying that the selected content has not changed since selection.def calculate_id(text: str, start: int = None, end: int = None) -> str: """ Calculate a unique ID for content verification based on the text content. The ID is formed by combining a line prefix (if line numbers are provided) with a truncated SHA-256 id of the content. This allows quick verification that content hasn't changed between operations. Args: text (str): Content to generate ID for start (Optional[int]): Starting line number for the content end (Optional[int]): Ending line number for the content Returns: str: ID string in format: [LinePrefix]-[Truncatedid] Example: "L10-15-a7" for content spanning lines 10-15 Example: "L5-b3" for content on line 5 only """ prefix = "" if start and end: prefix = f"L{start}-{end}-" if start == end: prefix = f"L{start}-" return f"{prefix}{hashlib.sha256(text.encode()).hexdigest()[:2]}"
- src/text_editor/server.py:58-102 (helper)Helper function to generate a context-aware diff preview of proposed changes in 'overwrite' tool, showing removed (+/- prefixed), added lines, and surrounding context lines.def generate_diff_preview( original_lines: list, modified_lines: list, start: int, end: int ) -> dict: """ Generate a diff preview comparing original and modified content. Args: original_lines (list): List of original file lines modified_lines (list): List of modified file lines start (int): Start line number of the edit (1-based) end (int): End line number of the edit (1-based) Returns: dict: A dictionary with keys prefixed with + or - to indicate additions/deletions Format: [("-1", "removed line"), ("+1", "added line")] """ diffs = [] # Add some context lines before the change context_start = max(0, start - 1 - 3) # 3 lines of context before for i in range(context_start, start - 1): diffs.append((i + 1, original_lines[i].rstrip())) # Show removed lines for i in range(start - 1, end): diffs.append((f"-{i+1}", original_lines[i].rstrip())) # Show added lines new_content = "".join( modified_lines[ start - 1 : start - 1 + len(modified_lines) - len(original_lines) + (end - (start - 1)) ] ) new_lines = new_content.splitlines() for i, line in enumerate(new_lines): diffs.append((f"+{start+i}", line)) context_end = min(len(original_lines), end + 3) # 3 lines of context after for i in range(end, context_end): diffs.append((i + 1, original_lines[i].rstrip())) return { "diff_lines": diffs, }
- src/text_editor/server.py:564-564 (registration)The FastMCP decorator registering the overwrite handler function as a tool.async def overwrite(