use crate::editor::Editor;
use crate::languages::LanguageName;
use crate::selector::{Operation, Selector};
use crate::state::SemanticEditTools;
use anyhow::Result;
use mcplease::{
traits::{Tool, WithExamples},
types::Example,
};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug, JsonSchema, clap::Args)]
#[serde(rename = "preview_edit")]
#[group(skip)]
pub struct PreviewEdit {
pub file_path: String,
#[serde(skip_serializing_if = "Option::is_none")]
#[arg(short, long, value_enum)]
pub language: Option<LanguageName>,
#[serde(flatten)]
#[clap(flatten)]
pub selector: Selector,
#[serde(skip_serializing_if = "Option::is_none")]
pub content: Option<String>,
}
impl WithExamples for PreviewEdit {
fn examples() -> Vec<Example<Self>> {
vec![
Example {
description: "Insert content after a function declaration",
item: Self {
file_path: "src/main.rs".into(),
selector: Selector {
anchor: "fn main() {".into(),
operation: Operation::InsertAfter,
},
content: Some("\n println!(\"Hello, world!\");".to_string()),
language: None,
},
},
Example {
description: "Replace a function with new implementation",
item: Self {
file_path: "src/main.rs".into(),
selector: Selector {
anchor: "fn hello()".to_string(),
operation: Operation::Replace,
},
content: Some("fn hello() { println!(\"Hello, world!\"); }".to_string()),
language: None,
},
},
Example {
description: "Replace an if statement",
item: Self {
file_path: "src/main.rs".into(),
selector: Selector {
operation: Operation::Replace,
anchor: "if let Some(user) = user {".to_string(),
},
content: Some("user.map(User::name)".into()),
language: None,
},
},
Example {
description: "Removing a function by omitting replacement content",
item: Self {
file_path: "src/main.rs".into(),
selector: Selector {
operation: Operation::Replace,
anchor: "fn main() {".to_string(),
},
content: None,
language: None,
},
},
]
}
}
impl Tool<SemanticEditTools> for PreviewEdit {
fn execute(self, state: &mut SemanticEditTools) -> Result<String> {
let Self {
file_path,
selector,
content,
language,
} = self;
let file_path = state.resolve_path(&file_path, None)?;
let language = state
.language_registry()
.get_language_with_hint(&file_path, language)?;
let editor = Editor::new(
content.unwrap_or_default(),
selector,
language,
file_path,
None,
)?;
let (message, staged_operation) = editor.preview()?;
state.preview_edit(None, staged_operation)?;
Ok(message)
}
}