main
rs 47 lines 1.52 KB
Raw
1 //! `si browse [target]` — open something on sigit.si in the default browser.
2 //!
3 //! `target` accepts a bare `OWNER/NAME`, `OWNER/NAME/pull/N`, or
4 //! `OWNER/NAME/issue/N`; omitted, it falls back to the repository in the
5 //! current directory.
6
7 use {
8 crate::{cli::BrowseArgs, context::Ctx, ui},
9 anyhow::{anyhow, Result},
10 };
11
12 pub async fn run(ctx: &Ctx, args: BrowseArgs) -> Result<()> {
13 let url = match args.target {
14 Some(target) => resolve_target(ctx, &target)?,
15 None => {
16 let slug = ctx.resolve_repo(None)?;
17 format!("{}/{slug}", ctx.client.base_url())
18 }
19 };
20
21 open::that(&url)?;
22 ui::note(format!("Opened {url}"));
23 Ok(())
24 }
25
26 /// `OWNER/NAME`, `OWNER/NAME/pull/N`, or `OWNER/NAME/issue/N`.
27 fn resolve_target(ctx: &Ctx, target: &str) -> Result<String> {
28 let trimmed = target.trim().trim_matches('/');
29 let parts: Vec<&str> = trimmed.split('/').collect();
30
31 match parts.as_slice() {
32 [owner, name] => Ok(format!("{}/{owner}/{name}", ctx.client.base_url())),
33 [owner, name, kind @ ("pull" | "issue"), number] => {
34 number
35 .parse::<u64>()
36 .map_err(|_| anyhow!("Expected a number after {kind}/, got {number:?}."))?;
37 Ok(format!(
38 "{}/{owner}/{name}/{kind}/{number}",
39 ctx.client.base_url()
40 ))
41 }
42 _ => Err(anyhow!(
43 "Could not parse {target:?}. Expected OWNER/NAME, OWNER/NAME/pull/N, or \
44 OWNER/NAME/issue/N."
45 )),
46 }
47 }