Skip to content

Commit dcb1875

Browse files
committed
refactor: split discussion command helpers
Separate interactive discussion looping from single-turn execution so follow-up flow control no longer lives inside one command body. Made-with: Cursor
1 parent bbc49af commit dcb1875

File tree

5 files changed

+112
-40
lines changed

5 files changed

+112
-40
lines changed

TODO.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@
8787
- [x] `src/commands/review/command.rs`: split review/check/compare entrypoints if they keep diverging.
8888
- [x] `src/commands/misc/feedback/command.rs`: separate file loading/ID normalization from store persistence.
8989
- [x] `src/commands/misc/feedback/apply.rs`: split acceptance/rejection counters from store mutation helpers.
90-
- [ ] `src/commands/misc/discussion/command.rs`: separate the interactive loop from single-shot execution.
90+
- [x] `src/commands/misc/discussion/command.rs`: separate the interactive loop from single-shot execution.
9191
- [ ] `src/commands/misc/discussion/selection.rs`: split file loading/ID repair from selection rules.
9292
- [ ] `src/commands/misc/changelog.rs`: evaluate splitting changelog collection from output formatting.
9393
- [x] `src/commands/eval/command.rs`: separate CLI option prep, fixture execution, and report lifecycle.

src/commands/misc/discussion/command.rs

Lines changed: 29 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,20 @@
11
use anyhow::Result;
22
use std::path::PathBuf;
33

4+
#[path = "command/interactive.rs"]
5+
mod interactive;
6+
#[path = "command/single.rs"]
7+
mod single;
8+
#[path = "command/turn.rs"]
9+
mod turn;
10+
411
use crate::adapters;
512
use crate::config;
613

7-
use super::prompt::answer_discussion_question;
814
use super::selection::{load_discussion_comments, select_discussion_comment};
9-
use super::thread::{load_discussion_thread, read_follow_up_question, save_discussion_thread};
10-
use super::types::DiscussionTurn;
15+
use super::thread::load_discussion_thread;
16+
use interactive::run_interactive_discussion;
17+
use single::run_single_discussion;
1118

1219
pub async fn discuss_command(
1320
config: config::Config,
@@ -25,45 +32,28 @@ pub async fn discuss_command(
2532
let model_config = config.to_model_config();
2633
let adapter = adapters::llm::create_adapter(&model_config)?;
2734

28-
let mut next_question = question;
29-
if next_question.is_none() && !interactive {
35+
if question.is_none() && !interactive {
3036
anyhow::bail!("Provide --question or use --interactive");
3137
}
3238

33-
loop {
34-
let current_question = if let Some(question) = next_question.take() {
35-
question
36-
} else if interactive {
37-
match read_follow_up_question()? {
38-
Some(question) => question,
39-
None => break,
40-
}
41-
} else {
42-
break;
43-
};
44-
45-
let answer =
46-
answer_discussion_question(adapter.as_ref(), &selected, &thread, &current_question)
47-
.await?;
48-
49-
println!("{}", answer.trim());
50-
51-
thread.turns.push(DiscussionTurn {
52-
role: "user".to_string(),
53-
message: current_question,
54-
});
55-
thread.turns.push(DiscussionTurn {
56-
role: "assistant".to_string(),
57-
message: answer,
58-
});
59-
60-
if let Some(path) = &thread_path {
61-
save_discussion_thread(path, &thread)?;
62-
}
63-
64-
if !interactive {
65-
break;
66-
}
39+
if interactive {
40+
run_interactive_discussion(
41+
adapter.as_ref(),
42+
&selected,
43+
&mut thread,
44+
question,
45+
thread_path.as_deref(),
46+
)
47+
.await?;
48+
} else if let Some(question) = question {
49+
run_single_discussion(
50+
adapter.as_ref(),
51+
&selected,
52+
&mut thread,
53+
question,
54+
thread_path.as_deref(),
55+
)
56+
.await?;
6757
}
6858

6959
Ok(())
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
use anyhow::Result;
2+
use std::path::Path;
3+
4+
use crate::adapters;
5+
use crate::core;
6+
7+
use super::super::thread::read_follow_up_question;
8+
use super::super::types::DiscussionThread;
9+
use super::turn::run_discussion_turn;
10+
11+
pub(super) async fn run_interactive_discussion(
12+
adapter: &dyn adapters::llm::LLMAdapter,
13+
selected: &core::Comment,
14+
thread: &mut DiscussionThread,
15+
initial_question: Option<String>,
16+
thread_path: Option<&Path>,
17+
) -> Result<()> {
18+
let mut next_question = initial_question;
19+
20+
loop {
21+
let Some(question) = next_question.take().or(read_follow_up_question()?) else {
22+
break;
23+
};
24+
run_discussion_turn(adapter, selected, thread, question, thread_path).await?;
25+
}
26+
27+
Ok(())
28+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
use anyhow::Result;
2+
use std::path::Path;
3+
4+
use crate::adapters;
5+
use crate::core;
6+
7+
use super::super::types::DiscussionThread;
8+
use super::turn::run_discussion_turn;
9+
10+
pub(super) async fn run_single_discussion(
11+
adapter: &dyn adapters::llm::LLMAdapter,
12+
selected: &core::Comment,
13+
thread: &mut DiscussionThread,
14+
question: String,
15+
thread_path: Option<&Path>,
16+
) -> Result<()> {
17+
run_discussion_turn(adapter, selected, thread, question, thread_path).await
18+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
use anyhow::Result;
2+
use std::path::Path;
3+
4+
use crate::adapters;
5+
use crate::core;
6+
7+
use super::super::prompt::answer_discussion_question;
8+
use super::super::thread::save_discussion_thread;
9+
use super::super::types::{DiscussionThread, DiscussionTurn};
10+
11+
pub(super) async fn run_discussion_turn(
12+
adapter: &dyn adapters::llm::LLMAdapter,
13+
selected: &core::Comment,
14+
thread: &mut DiscussionThread,
15+
question: String,
16+
thread_path: Option<&Path>,
17+
) -> Result<()> {
18+
let answer = answer_discussion_question(adapter, selected, thread, &question).await?;
19+
20+
println!("{}", answer.trim());
21+
22+
thread.turns.push(DiscussionTurn {
23+
role: "user".to_string(),
24+
message: question,
25+
});
26+
thread.turns.push(DiscussionTurn {
27+
role: "assistant".to_string(),
28+
message: answer,
29+
});
30+
31+
if let Some(path) = thread_path {
32+
save_discussion_thread(path, thread)?;
33+
}
34+
35+
Ok(())
36+
}

0 commit comments

Comments
 (0)