mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-24 09:46:59 -06:00
Audit: export names, linked-file ids and MCP prompt arguments in one pass
This commit is contained in:
committed by
bflatastic
parent
028cafa52e
commit
9843d5f1ab
@@ -1366,15 +1366,17 @@ pub(crate) fn unique_file_names<'a>(names: impl IntoIterator<Item = (&'a str, St
|
||||
/// `names` with `-2`, `-3`… after a name already used (compared without case).
|
||||
fn distinct_names(names: impl IntoIterator<Item = String>) -> Vec<String> {
|
||||
let mut taken = std::collections::HashSet::new();
|
||||
// The next number to try for each base: a name repeated many times doesn't search the numbers
|
||||
// taken before it.
|
||||
let mut next: std::collections::HashMap<String, usize> = std::collections::HashMap::new();
|
||||
names
|
||||
.into_iter()
|
||||
.map(|base| {
|
||||
let mut name = base.clone();
|
||||
for i in 2.. {
|
||||
if taken.insert(name.to_lowercase()) {
|
||||
break;
|
||||
}
|
||||
name = format!("{base}-{i}");
|
||||
while !taken.insert(name.to_lowercase()) {
|
||||
let n = next.entry(base.to_lowercase()).or_insert(1);
|
||||
*n += 1;
|
||||
name = format!("{base}-{n}");
|
||||
}
|
||||
name
|
||||
})
|
||||
|
||||
@@ -182,6 +182,8 @@ pub(crate) fn linked_groups(d: &Document) -> Vec<(String, Vec<u64>)> {
|
||||
fn groups(d: &Document, ids: Option<&[NodeId]>) -> Vec<Group> {
|
||||
let mut out: Vec<Group> = vec![];
|
||||
let mut index: BTreeMap<(String, String, bool), usize> = BTreeMap::new();
|
||||
// Looked up for every linked node: a set, not the list (which may repeat an id many times).
|
||||
let wanted: Option<std::collections::HashSet<NodeId>> = ids.map(|ids| ids.iter().copied().collect());
|
||||
let mut add = |link: &LinkInfo, key: &str, document: Option<Shown>, id: Option<NodeId>| {
|
||||
let i = *index.entry((link.path.clone(), key.to_string(), document.is_some())).or_insert_with(|| {
|
||||
out.push(Group { link: link.clone(), key: key.to_string(), ids: vec![], document });
|
||||
@@ -193,7 +195,7 @@ fn groups(d: &Document, ids: Option<&[NodeId]>) -> Vec<Group> {
|
||||
};
|
||||
d.walk(|n| {
|
||||
if let Some((l, key, document)) = linked(n)
|
||||
&& ids.is_none_or(|ids| ids.contains(&n.id))
|
||||
&& wanted.as_ref().is_none_or(|ids| ids.contains(&n.id))
|
||||
{
|
||||
add(l, key, document, Some(n.id));
|
||||
}
|
||||
|
||||
@@ -405,7 +405,10 @@ pub fn get(name: &str, args: &Value) -> Result<Value, String> {
|
||||
let ids: Vec<&str> = PROMPTS.iter().map(|p| p.name).collect();
|
||||
return Err(format!("unknown prompt `{name}` ({})", ids.join("|")));
|
||||
};
|
||||
let mut text = flow(p.text);
|
||||
let template = flow(p.text);
|
||||
// (placeholder, value): filled in one pass over the template, so a value that looks like a
|
||||
// placeholder stays as it is.
|
||||
let mut values: Vec<(String, String)> = vec![];
|
||||
for a in p.arguments {
|
||||
let given = args.get(a.name).filter(|v| !v.is_null()).map(|v| match v {
|
||||
Value::String(s) => s.clone(),
|
||||
@@ -416,7 +419,21 @@ pub fn get(name: &str, args: &Value) -> Result<Value, String> {
|
||||
_ if a.required => return Err(format!("prompt `{name}` needs the `{a_name}` argument", a_name = a.name)),
|
||||
_ => a.default.to_string(),
|
||||
};
|
||||
text = text.replace(&format!("{{{}}}", a.name), &value);
|
||||
values.push((format!("{{{}}}", a.name), value));
|
||||
}
|
||||
let mut text = String::with_capacity(template.len());
|
||||
let mut rest = template.as_str();
|
||||
while let Some(c) = rest.chars().next() {
|
||||
match values.iter().find(|(placeholder, _)| rest.starts_with(placeholder.as_str())) {
|
||||
Some((placeholder, value)) => {
|
||||
text.push_str(value);
|
||||
rest = rest.get(placeholder.len()..).unwrap_or_default();
|
||||
}
|
||||
None => {
|
||||
text.push(c);
|
||||
rest = rest.get(c.len_utf8()..).unwrap_or_default();
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(json!({
|
||||
"description": p.description,
|
||||
|
||||
Reference in New Issue
Block a user