flake_edit/app/commands/
add.rs1use nix_uri::FlakeRef;
8
9use crate::change::{Change, ChangeId};
10use crate::edit::FlakeEdit;
11use crate::tui;
12
13use super::super::editor::Editor;
14use super::super::state::AppState;
15use super::uri::{BuildKind, UriOptions, apply_uri_options, build_uri_change, transform_uri};
16use super::{Error, Result, apply_change};
17
18pub fn add(
19 editor: &Editor,
20 flake_edit: &mut FlakeEdit,
21 state: &AppState,
22 id: Option<String>,
23 uri: Option<String>,
24 no_flake: bool,
25 opts: UriOptions<'_>,
26) -> Result<()> {
27 let change = match (id, uri, state.interactive) {
28 (Some(id_val), Some(uri_str), _) => {
30 build_uri_change(BuildKind::Add { no_flake }, id_val, uri_str, &opts)?
31 }
32 (id, None, true) | (None, id, true) => {
34 add_interactive(editor, state, id.as_deref(), no_flake, &opts)?
35 }
36 (Some(uri), None, false) | (None, Some(uri), false) => add_infer_id(uri, no_flake, &opts)?,
38 (None, None, false) => {
39 return Err(Error::NoUri);
40 }
41 };
42
43 apply_change(editor, flake_edit, state, change)
44}
45
46fn add_interactive(
47 editor: &Editor,
48 state: &AppState,
49 prefill_uri: Option<&str>,
50 no_flake: bool,
51 opts: &UriOptions<'_>,
52) -> Result<Change> {
53 let tui_app = tui::App::add("Add", editor.text(), prefill_uri, state.cache_config());
54 let Some(tui::AppResult::Change(tui_change)) = tui::run(tui_app)? else {
55 return Ok(Change::None);
57 };
58
59 if let Change::Add { id, uri, flake } = tui_change {
61 let final_uri = uri
62 .map(|u| transform_uri(u, opts.ref_or_rev, opts.shallow))
63 .transpose()?;
64 Ok(Change::Add {
65 id,
66 uri: final_uri,
67 flake: flake && !no_flake,
68 })
69 } else {
70 Ok(tui_change)
71 }
72}
73
74fn add_infer_id(uri: String, no_flake: bool, opts: &UriOptions<'_>) -> Result<Change> {
77 let (inferred_id, final_uri) = match uri.parse::<FlakeRef>() {
78 Ok(flake_ref) => {
79 let flake_ref = apply_uri_options(flake_ref, opts.ref_or_rev, opts.shallow);
80 let id = flake_ref.id().map(str::to_owned);
81 (id, flake_ref.into_uri())
82 }
83 Err(_) => (None, uri.clone()),
84 };
85
86 let final_id = inferred_id.ok_or_else(|| Error::CouldNotInferId { uri: uri.clone() })?;
87 let final_id = ChangeId::parse(&final_id).map_err(|source| Error::InvalidInputId {
88 id: final_id,
89 source,
90 })?;
91
92 Ok(Change::Add {
93 id: Some(final_id),
94 uri: Some(final_uri),
95 flake: !no_flake,
96 })
97}