Skip to content

Commit 501e114

Browse files
committed
feat(cli): add edit/rewrite/edit-frontmatter/delete write subcommands
1 parent 93baefc commit 501e114

1 file changed

Lines changed: 174 additions & 0 deletions

File tree

src/main.rs

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,50 @@ enum WriteAction {
208208
/// Archived note path (e.g., "04-Archive/01-Projects/note.md").
209209
file: String,
210210
},
211+
/// Edit a specific section of a note.
212+
Edit {
213+
/// Target note (path, basename, or #docid).
214+
#[arg(long)]
215+
file: String,
216+
/// Section heading to edit (case-insensitive).
217+
#[arg(long)]
218+
heading: String,
219+
/// Content to add/replace in the section.
220+
#[arg(long)]
221+
content: String,
222+
/// Edit mode: "replace", "prepend", or "append" (default: "append").
223+
#[arg(long, default_value = "append")]
224+
mode: String,
225+
},
226+
/// Rewrite a note's body content (preserves frontmatter by default).
227+
Rewrite {
228+
/// Target note (path, basename, or #docid).
229+
#[arg(long)]
230+
file: String,
231+
/// New body content.
232+
#[arg(long)]
233+
content: String,
234+
/// Preserve existing frontmatter (default: true).
235+
#[arg(long, default_value_t = true)]
236+
preserve_frontmatter: bool,
237+
},
238+
/// Edit a note's frontmatter properties.
239+
EditFrontmatter {
240+
/// Target note (path, basename, or #docid).
241+
#[arg(long)]
242+
file: String,
243+
/// Operations as JSON string: [{"op":"add_tag","value":"rust"},{"op":"set","key":"status","value":"done"}]
244+
#[arg(long)]
245+
operations: String,
246+
},
247+
/// Delete a note.
248+
Delete {
249+
/// Target note (path, basename, or #docid).
250+
file: String,
251+
/// Delete mode: "soft" (archive, default) or "hard" (permanent).
252+
#[arg(long, default_value = "soft")]
253+
mode: String,
254+
},
211255
}
212256

213257
#[derive(Subcommand, Debug)]
@@ -975,6 +1019,136 @@ async fn main() -> Result<()> {
9751019
println!("Restored: {} → {}", file, result.path);
9761020
}
9771021
}
1022+
WriteAction::Edit {
1023+
file,
1024+
heading,
1025+
content,
1026+
mode,
1027+
} => {
1028+
let edit_mode = match mode.as_str() {
1029+
"replace" => engraph::writer::EditMode::Replace,
1030+
"prepend" => engraph::writer::EditMode::Prepend,
1031+
_ => engraph::writer::EditMode::Append,
1032+
};
1033+
let input = engraph::writer::EditInput {
1034+
file,
1035+
heading,
1036+
content,
1037+
mode: edit_mode,
1038+
modified_by: "cli".into(),
1039+
};
1040+
let result =
1041+
engraph::writer::edit_note(&store, &vault_path, &input, None)?;
1042+
if cli.json {
1043+
println!("{}", serde_json::to_string_pretty(&result)?);
1044+
} else {
1045+
println!(
1046+
"Edited: {} section \"{}\" ({})",
1047+
result.path, result.heading, result.mode
1048+
);
1049+
}
1050+
}
1051+
WriteAction::Rewrite {
1052+
file,
1053+
content,
1054+
preserve_frontmatter,
1055+
} => {
1056+
let input = engraph::writer::RewriteInput {
1057+
file,
1058+
content,
1059+
preserve_frontmatter,
1060+
modified_by: "cli".into(),
1061+
};
1062+
let result =
1063+
engraph::writer::rewrite_note(&store, &vault_path, &input)?;
1064+
if cli.json {
1065+
println!("{}", serde_json::to_string_pretty(&result)?);
1066+
} else {
1067+
println!(
1068+
"Rewrote: {} (frontmatter {})",
1069+
result.path,
1070+
if preserve_frontmatter { "preserved" } else { "replaced" }
1071+
);
1072+
}
1073+
}
1074+
WriteAction::EditFrontmatter { file, operations } => {
1075+
let raw_ops: Vec<serde_json::Value> = serde_json::from_str(&operations)
1076+
.map_err(|e| anyhow::anyhow!("invalid JSON operations: {}", e))?;
1077+
let mut ops = Vec::new();
1078+
for raw in &raw_ops {
1079+
let op = raw.get("op").and_then(|v| v.as_str()).unwrap_or("");
1080+
match op {
1081+
"set" => {
1082+
let key = raw.get("key").and_then(|v| v.as_str()).unwrap_or("").to_string();
1083+
let value = raw.get("value").and_then(|v| v.as_str()).unwrap_or("").to_string();
1084+
ops.push(engraph::writer::FrontmatterOp::Set(key, value));
1085+
}
1086+
"remove" => {
1087+
let key = raw.get("key").and_then(|v| v.as_str()).unwrap_or("").to_string();
1088+
ops.push(engraph::writer::FrontmatterOp::Remove(key));
1089+
}
1090+
"add_tag" => {
1091+
let value = raw.get("value").and_then(|v| v.as_str()).unwrap_or("").to_string();
1092+
ops.push(engraph::writer::FrontmatterOp::AddTag(value));
1093+
}
1094+
"remove_tag" => {
1095+
let value = raw.get("value").and_then(|v| v.as_str()).unwrap_or("").to_string();
1096+
ops.push(engraph::writer::FrontmatterOp::RemoveTag(value));
1097+
}
1098+
"add_alias" => {
1099+
let value = raw.get("value").and_then(|v| v.as_str()).unwrap_or("").to_string();
1100+
ops.push(engraph::writer::FrontmatterOp::AddAlias(value));
1101+
}
1102+
"remove_alias" => {
1103+
let value = raw.get("value").and_then(|v| v.as_str()).unwrap_or("").to_string();
1104+
ops.push(engraph::writer::FrontmatterOp::RemoveAlias(value));
1105+
}
1106+
_ => {
1107+
return Err(anyhow::anyhow!("unknown frontmatter op: {:?}", op));
1108+
}
1109+
}
1110+
}
1111+
let input = engraph::writer::EditFrontmatterInput {
1112+
file,
1113+
operations: ops,
1114+
modified_by: "cli".into(),
1115+
};
1116+
let result =
1117+
engraph::writer::edit_frontmatter(&store, &vault_path, &input)?;
1118+
if cli.json {
1119+
println!("{}", serde_json::to_string_pretty(&result)?);
1120+
} else {
1121+
println!("Frontmatter updated: {}", result.path);
1122+
}
1123+
}
1124+
WriteAction::Delete { file, mode } => {
1125+
let delete_mode = match mode.as_str() {
1126+
"hard" => engraph::writer::DeleteMode::Hard,
1127+
_ => engraph::writer::DeleteMode::Soft,
1128+
};
1129+
let archive_folder = profile
1130+
.as_ref()
1131+
.and_then(|p| p.structure.folders.archive.as_deref())
1132+
.unwrap_or("04-Archive");
1133+
engraph::writer::delete_note(
1134+
&store,
1135+
&vault_path,
1136+
&file,
1137+
delete_mode,
1138+
archive_folder,
1139+
)?;
1140+
if cli.json {
1141+
println!(
1142+
"{}",
1143+
serde_json::to_string_pretty(&serde_json::json!({
1144+
"deleted": file,
1145+
"mode": mode
1146+
}))?
1147+
);
1148+
} else {
1149+
println!("Deleted: {} ({})", file, mode);
1150+
}
1151+
}
9781152
}
9791153
}
9801154

0 commit comments

Comments
 (0)