src files
This commit is contained in:
parent
d6579aede2
commit
4f88f30cbb
340
src/codeeditor/file_manager.py
Normal file
340
src/codeeditor/file_manager.py
Normal file
@ -0,0 +1,340 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
"""File management module for the codeeditor application."""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import platform
|
||||||
|
import subprocess
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Any, Dict, List, Optional, Set, Tuple
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class FileManager:
|
||||||
|
"""Class for managing file operations in the code editor."""
|
||||||
|
|
||||||
|
def __init__(self, root_dir: Path):
|
||||||
|
"""Initialize the FileManager with a root directory.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
root_dir: The root directory to manage files from.
|
||||||
|
"""
|
||||||
|
# If root_dir is empty or doesn't exist, use current directory
|
||||||
|
if not root_dir or not root_dir.exists():
|
||||||
|
self.root_dir = Path.cwd()
|
||||||
|
else:
|
||||||
|
self.root_dir = root_dir
|
||||||
|
|
||||||
|
self.code_extensions = [
|
||||||
|
".py",
|
||||||
|
".js",
|
||||||
|
".html",
|
||||||
|
".css",
|
||||||
|
".json",
|
||||||
|
".md",
|
||||||
|
".txt",
|
||||||
|
".yaml",
|
||||||
|
".yml",
|
||||||
|
".toml",
|
||||||
|
".sh",
|
||||||
|
".bat",
|
||||||
|
".c",
|
||||||
|
".cpp",
|
||||||
|
".h",
|
||||||
|
".hpp",
|
||||||
|
".java",
|
||||||
|
".go",
|
||||||
|
".rs",
|
||||||
|
".ts",
|
||||||
|
".tsx",
|
||||||
|
".jsx",
|
||||||
|
]
|
||||||
|
|
||||||
|
# File extension categories for filtering
|
||||||
|
self.file_categories = {
|
||||||
|
"Python": [".py", ".pyw", ".pyc", ".pyd", ".pyo", ".pyi"],
|
||||||
|
"Web": [".html", ".css", ".js", ".ts", ".jsx", ".tsx", ".vue", ".svelte"],
|
||||||
|
"Data": [".json", ".csv", ".xml", ".yaml", ".yml", ".toml"],
|
||||||
|
"Documents": [".md", ".txt", ".pdf", ".docx", ".xlsx", ".pptx"],
|
||||||
|
"Images": [".jpg", ".jpeg", ".png", ".gif", ".svg", ".ico", ".webp"],
|
||||||
|
"All Files": ["*"],
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info(f"FileManager initialized with root directory: {self.root_dir}")
|
||||||
|
|
||||||
|
def list_files(
|
||||||
|
self, directory: Optional[Path] = None, filter_category: str = "All Files"
|
||||||
|
) -> List[Tuple[str, bool]]:
|
||||||
|
"""List all files in the given directory.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
directory: The directory to list files from. If None, uses root_dir.
|
||||||
|
filter_category: Filter files by category.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A list of tuples containing (file_path, is_directory).
|
||||||
|
"""
|
||||||
|
if directory is None:
|
||||||
|
directory = self.root_dir
|
||||||
|
|
||||||
|
# If directory is empty string or doesn't exist, return empty list
|
||||||
|
if not directory or not directory.exists():
|
||||||
|
return []
|
||||||
|
|
||||||
|
try:
|
||||||
|
file_list = []
|
||||||
|
|
||||||
|
# Walk through all directories and files recursively
|
||||||
|
for root, dirs, files in os.walk(directory):
|
||||||
|
# Skip hidden directories
|
||||||
|
dirs[:] = [d for d in dirs if not d.startswith(".")]
|
||||||
|
|
||||||
|
# Process directories
|
||||||
|
for dir_name in dirs:
|
||||||
|
dir_path = Path(root) / dir_name
|
||||||
|
try:
|
||||||
|
rel_path = dir_path.relative_to(self.root_dir)
|
||||||
|
file_list.append((str(rel_path), True))
|
||||||
|
except ValueError:
|
||||||
|
# If dir is not relative to root_dir (can happen with symlinks)
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Process files
|
||||||
|
for file_name in files:
|
||||||
|
# Skip hidden files except .env
|
||||||
|
if file_name.startswith(".") and file_name != ".env":
|
||||||
|
continue
|
||||||
|
|
||||||
|
file_path = Path(root) / file_name
|
||||||
|
try:
|
||||||
|
rel_path = file_path.relative_to(self.root_dir)
|
||||||
|
|
||||||
|
# Apply filter if not "All Files"
|
||||||
|
if filter_category != "All Files":
|
||||||
|
if not any(
|
||||||
|
file_name.endswith(ext)
|
||||||
|
for ext in self.file_categories.get(filter_category, [])
|
||||||
|
):
|
||||||
|
continue
|
||||||
|
|
||||||
|
file_list.append((str(rel_path), False))
|
||||||
|
except ValueError:
|
||||||
|
# If file is not relative to root_dir (can happen with symlinks)
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Sort the list: directories first, then files, both alphabetically
|
||||||
|
file_list.sort(key=lambda x: (not x[1], x[0].lower()))
|
||||||
|
return file_list
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error listing files in {directory}: {e}")
|
||||||
|
return []
|
||||||
|
|
||||||
|
def get_file_tree(
|
||||||
|
self, expanded_folders: Set[str], filter_category: str = "All Files"
|
||||||
|
) -> Dict:
|
||||||
|
"""Get a hierarchical file tree structure.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
expanded_folders: Set of folder paths that are expanded in the UI.
|
||||||
|
filter_category: Filter files by category.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A dictionary representing the file tree structure.
|
||||||
|
"""
|
||||||
|
if not self.root_dir or not self.root_dir.exists():
|
||||||
|
return {}
|
||||||
|
|
||||||
|
file_tree = {}
|
||||||
|
|
||||||
|
def add_to_tree(path_parts, current_dict, is_dir, full_path):
|
||||||
|
if not path_parts:
|
||||||
|
return
|
||||||
|
|
||||||
|
part = path_parts[0]
|
||||||
|
if len(path_parts) == 1:
|
||||||
|
# Leaf node
|
||||||
|
if is_dir:
|
||||||
|
if part not in current_dict:
|
||||||
|
current_dict[part] = {
|
||||||
|
"__type": "directory",
|
||||||
|
"__path": full_path,
|
||||||
|
"__children": {},
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
current_dict[part] = {"__type": "file", "__path": full_path}
|
||||||
|
else:
|
||||||
|
# Directory node
|
||||||
|
if part not in current_dict:
|
||||||
|
current_dict[part] = {
|
||||||
|
"__type": "directory",
|
||||||
|
"__path": full_path,
|
||||||
|
"__children": {},
|
||||||
|
}
|
||||||
|
add_to_tree(
|
||||||
|
path_parts[1:], current_dict[part]["__children"], is_dir, full_path
|
||||||
|
)
|
||||||
|
|
||||||
|
for file_path, is_dir in self.list_files(filter_category=filter_category):
|
||||||
|
path_parts = Path(file_path).parts
|
||||||
|
add_to_tree(path_parts, file_tree, is_dir, file_path)
|
||||||
|
|
||||||
|
return file_tree
|
||||||
|
|
||||||
|
def read_file(self, file_path: str) -> Optional[str]:
|
||||||
|
"""Read the contents of a file.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
file_path: The path to the file to read, relative to root_dir.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The contents of the file as a string, or None if the file cannot be read.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
full_path = self.root_dir / file_path
|
||||||
|
with open(full_path, "r", encoding="utf-8") as f:
|
||||||
|
content = f.read()
|
||||||
|
logger.info(f"Read file: {file_path}")
|
||||||
|
return content
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error reading file {file_path}: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def save_file(self, file_path: str, content: str) -> bool:
|
||||||
|
"""Save content to a file.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
file_path: The path to the file to save, relative to root_dir.
|
||||||
|
content: The content to save to the file.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
True if the file was saved successfully, False otherwise.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
full_path = self.root_dir / file_path
|
||||||
|
# Create parent directories if they don't exist
|
||||||
|
full_path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
with open(full_path, "w", encoding="utf-8") as f:
|
||||||
|
f.write(content)
|
||||||
|
logger.info(f"Saved file: {file_path}")
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error saving file {file_path}: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def create_directory(self, dir_path: str) -> bool:
|
||||||
|
"""Create a new directory.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
dir_path: The path to the directory to create, relative to root_dir.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
True if the directory was created successfully, False otherwise.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
full_path = self.root_dir / dir_path
|
||||||
|
full_path.mkdir(parents=True, exist_ok=True)
|
||||||
|
logger.info(f"Created directory: {dir_path}")
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error creating directory {dir_path}: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def delete_item(self, item_path: str) -> bool:
|
||||||
|
"""Delete a file or directory.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
item_path: The path to the item to delete, relative to root_dir.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
True if the item was deleted successfully, False otherwise.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
full_path = self.root_dir / item_path
|
||||||
|
if full_path.is_dir():
|
||||||
|
# Remove directory and all contents
|
||||||
|
import shutil
|
||||||
|
|
||||||
|
shutil.rmtree(full_path)
|
||||||
|
logger.info(f"Deleted directory: {item_path}")
|
||||||
|
else:
|
||||||
|
# Remove file
|
||||||
|
full_path.unlink()
|
||||||
|
logger.info(f"Deleted file: {item_path}")
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error deleting item {item_path}: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def is_code_file(self, file_path: str) -> bool:
|
||||||
|
"""Check if a file is a code file based on its extension.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
file_path: The path to the file.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
True if the file is a code file, False otherwise.
|
||||||
|
"""
|
||||||
|
return any(file_path.endswith(ext) for ext in self.code_extensions)
|
||||||
|
|
||||||
|
def get_file_extension(self, file_path: str) -> str:
|
||||||
|
"""Get the extension of a file.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
file_path: The path to the file.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The file extension.
|
||||||
|
"""
|
||||||
|
return os.path.splitext(file_path)[1].lower()
|
||||||
|
|
||||||
|
def get_file_icon(self, file_path: str) -> str:
|
||||||
|
"""Get an icon for a file based on its extension.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
file_path: The path to the file.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
An emoji icon representing the file type.
|
||||||
|
"""
|
||||||
|
ext = self.get_file_extension(file_path)
|
||||||
|
|
||||||
|
# Map file extensions to icons
|
||||||
|
icon_map = {
|
||||||
|
".py": "🐍", # Python
|
||||||
|
".js": "📜", # JavaScript
|
||||||
|
".html": "🌐", # HTML
|
||||||
|
".css": "🎨", # CSS
|
||||||
|
".json": "📋", # JSON
|
||||||
|
".md": "📝", # Markdown
|
||||||
|
".txt": "📄", # Text
|
||||||
|
".yml": "⚙️", # YAML
|
||||||
|
".yaml": "⚙️", # YAML
|
||||||
|
".toml": "⚙️", # TOML
|
||||||
|
".sh": "🐚", # Shell
|
||||||
|
".bat": "🐚", # Batch
|
||||||
|
".c": "🔧", # C
|
||||||
|
".cpp": "🔧", # C++
|
||||||
|
".h": "🔧", # Header
|
||||||
|
".hpp": "🔧", # C++ Header
|
||||||
|
".java": "☕", # Java
|
||||||
|
".go": "🔵", # Go
|
||||||
|
".rs": "🦀", # Rust
|
||||||
|
".ts": "📘", # TypeScript
|
||||||
|
".jsx": "⚛️", # React JSX
|
||||||
|
".tsx": "⚛️", # React TSX
|
||||||
|
}
|
||||||
|
|
||||||
|
return icon_map.get(ext, "📄") # Default to generic file icon
|
||||||
|
|
||||||
|
def get_file_categories(self) -> Dict[str, List[str]]:
|
||||||
|
"""Get file categories for filtering.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Dictionary of file categories and their extensions.
|
||||||
|
"""
|
||||||
|
return self.file_categories
|
179
src/codeeditor/search_manager.py
Normal file
179
src/codeeditor/search_manager.py
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
"""Search management module for the codeeditor application."""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
from typing import Dict, List, Optional
|
||||||
|
|
||||||
|
import requests
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
|
# Load environment variables from .env file
|
||||||
|
load_dotenv()
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class SearchManager:
|
||||||
|
"""Class for managing internet searches."""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
"""Initialize the SearchManager."""
|
||||||
|
self.api_key = os.getenv("SEARCH_API_KEY")
|
||||||
|
self.search_engine_id = os.getenv("SEARCH_ENGINE_ID")
|
||||||
|
logger.info("SearchManager initialized")
|
||||||
|
|
||||||
|
def search(self, query: str, num_results: int = 5) -> List[Dict[str, str]]:
|
||||||
|
"""Perform an internet search for the given query.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
query: The search query.
|
||||||
|
num_results: The number of results to return.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A list of dictionaries containing search results.
|
||||||
|
"""
|
||||||
|
results = []
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Use Google Custom Search API if API key is available
|
||||||
|
if self.api_key and self.search_engine_id:
|
||||||
|
results = self._google_search(query, num_results)
|
||||||
|
else:
|
||||||
|
# Fallback to a simple search simulation
|
||||||
|
logger.warning(
|
||||||
|
"Search API keys not found. Using simulated search results."
|
||||||
|
)
|
||||||
|
results = self._simulated_search(query)
|
||||||
|
|
||||||
|
logger.info(f"Search completed for query: {query}")
|
||||||
|
return results
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error performing search: {e}")
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
"title": "Search Error",
|
||||||
|
"link": "",
|
||||||
|
"snippet": f"Error performing search: {str(e)}",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
def _google_search(self, query: str, num_results: int = 5) -> List[Dict[str, str]]:
|
||||||
|
"""Perform a search using Google Custom Search API.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
query: The search query.
|
||||||
|
num_results: The number of results to return.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A list of dictionaries containing search results.
|
||||||
|
"""
|
||||||
|
url = "https://www.googleapis.com/customsearch/v1"
|
||||||
|
params = {
|
||||||
|
"key": self.api_key,
|
||||||
|
"cx": self.search_engine_id,
|
||||||
|
"q": query,
|
||||||
|
"num": min(num_results, 10), # API limit is 10
|
||||||
|
}
|
||||||
|
|
||||||
|
response = requests.get(url, params=params)
|
||||||
|
data = response.json()
|
||||||
|
|
||||||
|
results = []
|
||||||
|
if "items" in data:
|
||||||
|
for item in data["items"]:
|
||||||
|
results.append(
|
||||||
|
{
|
||||||
|
"title": item.get("title", ""),
|
||||||
|
"link": item.get("link", ""),
|
||||||
|
"snippet": item.get("snippet", ""),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return results
|
||||||
|
|
||||||
|
def _simulated_search(self, query: str) -> List[Dict[str, str]]:
|
||||||
|
"""Simulate search results when API keys are not available.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
query: The search query.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A list of dictionaries containing simulated search results.
|
||||||
|
"""
|
||||||
|
# This is a fallback method that returns simulated results
|
||||||
|
# In a real application, you might want to use a free alternative or web scraping
|
||||||
|
# with proper rate limiting and respect for robots.txt
|
||||||
|
|
||||||
|
# Always include these informational results
|
||||||
|
results = [
|
||||||
|
{
|
||||||
|
"title": "Search API Key Required",
|
||||||
|
"link": "https://developers.google.com/custom-search/v1/overview",
|
||||||
|
"snippet": "To enable real search functionality, please add SEARCH_API_KEY and SEARCH_ENGINE_ID to your .env file.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": f"Search Results for: {query}",
|
||||||
|
"link": f"https://www.google.com/search?q={query.replace(' ', '+')}",
|
||||||
|
"snippet": "Click this link to perform the search manually in your browser.",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
# Add some simulated results based on common programming queries
|
||||||
|
query_lower = query.lower()
|
||||||
|
|
||||||
|
if "python" in query_lower:
|
||||||
|
results.extend(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"title": "Python Documentation",
|
||||||
|
"link": "https://docs.python.org/3/",
|
||||||
|
"snippet": "Python 3 documentation. Welcome! This is the official documentation for Python 3. Parts of the documentation: What's new in Python 3? Or all 'What's new' documents since 2.0.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Python Tutorial - W3Schools",
|
||||||
|
"link": "https://www.w3schools.com/python/",
|
||||||
|
"snippet": "Python is a popular programming language. Python can be used on a server to create web applications. Start learning Python now.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "The Python Standard Library",
|
||||||
|
"link": "https://docs.python.org/3/library/",
|
||||||
|
"snippet": "The Python Standard Library. While The Python Language Reference describes the exact syntax and semantics of the Python language, this library reference manual describes the standard library that is distributed with Python.",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
)
|
||||||
|
elif "javascript" in query_lower:
|
||||||
|
results.extend(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"title": "JavaScript - MDN Web Docs",
|
||||||
|
"link": "https://developer.mozilla.org/en-US/docs/Web/JavaScript",
|
||||||
|
"snippet": "JavaScript (JS) is a lightweight, interpreted, or just-in-time compiled programming language with first-class functions.",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
)
|
||||||
|
elif "streamlit" in query_lower:
|
||||||
|
results.extend(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"title": "Streamlit Documentation",
|
||||||
|
"link": "https://docs.streamlit.io/",
|
||||||
|
"snippet": "Streamlit is an open-source Python library that makes it easy to create and share beautiful, custom web apps for machine learning and data science.",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
# Add a generic result for any query to ensure we always return something
|
||||||
|
if len(results) <= 2:
|
||||||
|
results.append(
|
||||||
|
{
|
||||||
|
"title": f"{query} - Programming Resources",
|
||||||
|
"link": f"https://github.com/search?q={query.replace(' ', '+')}",
|
||||||
|
"snippet": f"Find open-source projects and resources related to {query} on GitHub.",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return results
|
213
src/codeeditor/system_prompter.py
Normal file
213
src/codeeditor/system_prompter.py
Normal file
@ -0,0 +1,213 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
"""System prompt generation module for the codeeditor application."""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Dict, List, Optional
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class SystemPrompter:
|
||||||
|
"""Class for generating system prompts for the AI assistant."""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
"""Initialize the SystemPrompter."""
|
||||||
|
self.base_prompt = (
|
||||||
|
"You are an AI coding assistant helping with programming tasks. "
|
||||||
|
"You provide clear, concise, and accurate code suggestions, explanations, "
|
||||||
|
"and debugging help. Your responses should be helpful, informative, and "
|
||||||
|
"focused on solving the user's coding problems.\n\n"
|
||||||
|
"When providing code examples, always format them with markdown code blocks "
|
||||||
|
"with the appropriate language syntax highlighting. For example:\n"
|
||||||
|
"```python\n"
|
||||||
|
"def hello_world():\n"
|
||||||
|
" print('Hello, World!')\n"
|
||||||
|
"```\n\n"
|
||||||
|
"When suggesting changes to existing code, clearly indicate which parts should "
|
||||||
|
"be modified, added, or removed."
|
||||||
|
)
|
||||||
|
logger.info("SystemPrompter initialized")
|
||||||
|
|
||||||
|
def generate_prompt(self, file_context: Optional[str] = None) -> str:
|
||||||
|
"""Generate a system prompt for the AI assistant.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
file_context: Optional context from the current file.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A system prompt string.
|
||||||
|
"""
|
||||||
|
prompt = self.base_prompt
|
||||||
|
|
||||||
|
if file_context:
|
||||||
|
# Add file context to the prompt
|
||||||
|
file_path = file_context.split("\n", 1)[0].replace("File: ", "")
|
||||||
|
file_content = (
|
||||||
|
file_context.split("\n", 1)[1] if "\n" in file_context else ""
|
||||||
|
)
|
||||||
|
|
||||||
|
prompt += (
|
||||||
|
f"\n\nHere is the current file content that the user is working with:\n"
|
||||||
|
f"File: {file_path}\n"
|
||||||
|
)
|
||||||
|
prompt += "```\n" + file_content + "\n```\n"
|
||||||
|
|
||||||
|
# Add file type specific context
|
||||||
|
file_ext = Path(file_path).suffix.lower()
|
||||||
|
if file_ext:
|
||||||
|
language_context = self._get_language_context(file_ext)
|
||||||
|
if language_context:
|
||||||
|
prompt += f"\n{language_context}\n"
|
||||||
|
|
||||||
|
prompt += "\nPlease consider this context when providing assistance."
|
||||||
|
|
||||||
|
return prompt
|
||||||
|
|
||||||
|
def _get_language_context(self, file_extension: str) -> str:
|
||||||
|
"""Get language-specific context based on file extension.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
file_extension: The file extension including the dot.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Language-specific context string.
|
||||||
|
"""
|
||||||
|
language_contexts = {
|
||||||
|
".py": (
|
||||||
|
"This is a Python file. When suggesting improvements, consider Python best practices "
|
||||||
|
"such as PEP 8 style guidelines, type hints, docstrings, and efficient use of "
|
||||||
|
"Python's standard library and idioms."
|
||||||
|
),
|
||||||
|
".js": (
|
||||||
|
"This is a JavaScript file. Consider modern JavaScript (ES6+) features, "
|
||||||
|
"asynchronous patterns, and clean code practices when providing suggestions."
|
||||||
|
),
|
||||||
|
".html": (
|
||||||
|
"This is an HTML file. Consider semantic HTML5 elements, accessibility best practices, "
|
||||||
|
"and proper document structure when providing suggestions."
|
||||||
|
),
|
||||||
|
".css": (
|
||||||
|
"This is a CSS file. Consider responsive design principles, browser compatibility, "
|
||||||
|
"and modern CSS features when providing suggestions."
|
||||||
|
),
|
||||||
|
".jsx": (
|
||||||
|
"This is a React JSX file. Consider React best practices, component structure, "
|
||||||
|
"hooks usage, and state management when providing suggestions."
|
||||||
|
),
|
||||||
|
".tsx": (
|
||||||
|
"This is a TypeScript React file. Consider TypeScript type safety, React best practices, "
|
||||||
|
"component structure, hooks usage, and state management when providing suggestions."
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
return language_contexts.get(file_extension, "")
|
||||||
|
|
||||||
|
def generate_code_improvement_prompt(
|
||||||
|
self, code: str, file_path: Optional[str] = None
|
||||||
|
) -> str:
|
||||||
|
"""Generate a prompt for code improvement suggestions.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
code: The code to improve.
|
||||||
|
file_path: Optional path to the file.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A system prompt string for code improvement.
|
||||||
|
"""
|
||||||
|
prompt = self.base_prompt
|
||||||
|
prompt += "\n\nPlease review the following code and suggest improvements "
|
||||||
|
prompt += "for readability, efficiency, and best practices:\n"
|
||||||
|
|
||||||
|
if file_path:
|
||||||
|
prompt += f"File: {file_path}\n"
|
||||||
|
|
||||||
|
# Add language-specific context
|
||||||
|
file_ext = Path(file_path).suffix.lower()
|
||||||
|
if file_ext:
|
||||||
|
language_context = self._get_language_context(file_ext)
|
||||||
|
if language_context:
|
||||||
|
prompt += f"\n{language_context}\n"
|
||||||
|
|
||||||
|
prompt += "```\n" + code + "\n```\n"
|
||||||
|
prompt += "\nPlease provide specific suggestions with examples."
|
||||||
|
|
||||||
|
return prompt
|
||||||
|
|
||||||
|
def generate_debugging_prompt(
|
||||||
|
self, code: str, error_message: str, file_path: Optional[str] = None
|
||||||
|
) -> str:
|
||||||
|
"""Generate a prompt for debugging assistance.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
code: The code to debug.
|
||||||
|
error_message: The error message to debug.
|
||||||
|
file_path: Optional path to the file.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A system prompt string for debugging.
|
||||||
|
"""
|
||||||
|
prompt = self.base_prompt
|
||||||
|
prompt += (
|
||||||
|
"\n\nPlease help debug the following code that is producing an error:\n"
|
||||||
|
)
|
||||||
|
|
||||||
|
if file_path:
|
||||||
|
prompt += f"File: {file_path}\n"
|
||||||
|
|
||||||
|
# Add language-specific context
|
||||||
|
file_ext = Path(file_path).suffix.lower()
|
||||||
|
if file_ext:
|
||||||
|
language_context = self._get_language_context(file_ext)
|
||||||
|
if language_context:
|
||||||
|
prompt += f"\n{language_context}\n"
|
||||||
|
|
||||||
|
prompt += "```\n" + code + "\n```\n"
|
||||||
|
prompt += "\nError message:\n"
|
||||||
|
prompt += "```\n" + error_message + "\n```\n"
|
||||||
|
prompt += (
|
||||||
|
"\nPlease explain what's causing the error and suggest a fix. "
|
||||||
|
"Include a corrected version of the code."
|
||||||
|
)
|
||||||
|
|
||||||
|
return prompt
|
||||||
|
|
||||||
|
def generate_completion_prompt(
|
||||||
|
self, code: str, cursor_position: int, file_path: Optional[str] = None
|
||||||
|
) -> str:
|
||||||
|
"""Generate a prompt for code completion.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
code: The code to complete.
|
||||||
|
cursor_position: The position of the cursor in the code.
|
||||||
|
file_path: Optional path to the file.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A system prompt string for code completion.
|
||||||
|
"""
|
||||||
|
prompt = self.base_prompt
|
||||||
|
prompt += "\n\nPlease help complete the following code at the cursor position (marked by |):\n"
|
||||||
|
|
||||||
|
if file_path:
|
||||||
|
prompt += f"File: {file_path}\n"
|
||||||
|
|
||||||
|
# Add language-specific context
|
||||||
|
file_ext = Path(file_path).suffix.lower()
|
||||||
|
if file_ext:
|
||||||
|
language_context = self._get_language_context(file_ext)
|
||||||
|
if language_context:
|
||||||
|
prompt += f"\n{language_context}\n"
|
||||||
|
|
||||||
|
# Insert cursor marker
|
||||||
|
code_with_cursor = code[:cursor_position] + "|" + code[cursor_position:]
|
||||||
|
|
||||||
|
prompt += "```\n" + code_with_cursor + "\n```\n"
|
||||||
|
prompt += (
|
||||||
|
"\nPlease suggest code completions that would make sense at the cursor position. "
|
||||||
|
"Provide a few different options if appropriate."
|
||||||
|
)
|
||||||
|
|
||||||
|
return prompt
|
1842
src/codeeditor/ui_components.py
Normal file
1842
src/codeeditor/ui_components.py
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user