Skip to content

Commit

Permalink
assistant: Add basic glob support for expanding items in /docs (zed…
Browse files Browse the repository at this point in the history
…-industries#14370)

This PR updates the `/docs` slash command with basic globbing support
for expanding docs.

A `*` can be added to the item path to signify the end of a prefix
match.

For example:

```
# This will match any documentation items starting with `auk::`.
# In this case, it will pull in the docs for each item in the crate.
/docs docs-rs auk::*

# This will match any documentation items starting with `auk::visitor::`,
# which will pull in docs for the `visitor` module.
/docs docs-rs auk::visitor::*
```


https://github.com/user-attachments/assets/5e1e21f1-241b-483f-9cd1-facc3aa76365

Release Notes:

- N/A
  • Loading branch information
maxdeviant authored Jul 12, 2024
1 parent fe3fe94 commit 3deb000
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 20 deletions.
59 changes: 39 additions & 20 deletions crates/assistant/src/slash_command/docs_command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,46 +200,65 @@ impl SlashCommand for DocsSlashCommand {
};

let args = DocsSlashCommandArgs::parse(argument);
let text = cx.background_executor().spawn({
let task = cx.background_executor().spawn({
let store = args
.provider()
.ok_or_else(|| anyhow!("no docs provider specified"))
.and_then(|provider| IndexedDocsStore::try_global(provider, cx));
async move {
match args {
let (provider, key) = match args {
DocsSlashCommandArgs::NoProvider => bail!("no docs provider specified"),
DocsSlashCommandArgs::SearchPackageDocs {
provider, package, ..
} => {
let store = store?;
let item_docs = store.load(package.clone()).await?;

anyhow::Ok((provider, package, item_docs.to_string()))
}
} => (provider, package),
DocsSlashCommandArgs::SearchItemDocs {
provider,
item_path,
..
} => {
let store = store?;
let item_docs = store.load(item_path.clone()).await?;
} => (provider, item_path),
};

let store = store?;
let (text, ranges) = if let Some((prefix, _)) = key.split_once('*') {
let docs = store.load_many_by_prefix(prefix.to_string()).await?;

anyhow::Ok((provider, item_path, item_docs.to_string()))
let mut text = String::new();
let mut ranges = Vec::new();

for (key, docs) in docs {
let prev_len = text.len();

text.push_str(&docs.0);
text.push_str("\n");
ranges.push((key, prev_len..text.len()));
text.push_str("\n");
}
}

(text, ranges)
} else {
let item_docs = store.load(key.clone()).await?;
let text = item_docs.to_string();
let range = 0..text.len();

(text, vec![(key, range)])
};

anyhow::Ok((provider, text, ranges))
}
});

cx.foreground_executor().spawn(async move {
let (provider, path, text) = text.await?;
let range = 0..text.len();
let (provider, text, ranges) = task.await?;
Ok(SlashCommandOutput {
text,
sections: vec![SlashCommandOutputSection {
range,
icon: IconName::FileDoc,
label: format!("docs ({provider}): {path}",).into(),
}],
sections: ranges
.into_iter()
.map(|(key, range)| SlashCommandOutputSection {
range,
icon: IconName::FileDoc,
label: format!("docs ({provider}): {key}",).into(),
})
.collect(),
run_commands_in_text: false,
})
})
Expand Down
31 changes: 31 additions & 0 deletions crates/indexed_docs/src/store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,15 @@ impl IndexedDocsStore {
.await
}

pub async fn load_many_by_prefix(&self, prefix: String) -> Result<Vec<(String, MarkdownDocs)>> {
self.database_future
.clone()
.await
.map_err(|err| anyhow!(err))?
.load_many_by_prefix(prefix)
.await
}

pub fn index(
self: Arc<Self>,
package: PackageName,
Expand Down Expand Up @@ -257,6 +266,28 @@ impl IndexedDocsDatabase {
})
}

pub fn load_many_by_prefix(&self, prefix: String) -> Task<Result<Vec<(String, MarkdownDocs)>>> {
let env = self.env.clone();
let entries = self.entries;

self.executor.spawn(async move {
let txn = env.read_txn()?;
let results = entries
.iter(&txn)?
.filter_map(|entry| {
let (key, value) = entry.ok()?;
if key.starts_with(&prefix) {
Some((key, value))
} else {
None
}
})
.collect::<Vec<_>>();

Ok(results)
})
}

pub fn insert(&self, key: String, docs: String) -> Task<Result<()>> {
let env = self.env.clone();
let entries = self.entries;
Expand Down

0 comments on commit 3deb000

Please sign in to comment.