chore: enable clippy::redundant_clone (#3489)

Created this PR by:

- adding `redundant_clone` to `[workspace.lints.clippy]` in
`cargo-rs/Cargol.toml`
- running `cargo clippy --tests --fix`
- running `just fmt`

Though I had to clean up one instance of the following that resulted:

```rust
let codex = codex;
```
This commit is contained in:
Michael Bolin
2025-09-11 11:59:37 -07:00
committed by GitHub
parent 66967500bb
commit bec51f6c05
34 changed files with 71 additions and 98 deletions

View File

@@ -34,6 +34,7 @@ rust = {}
[workspace.lints.clippy] [workspace.lints.clippy]
expect_used = "deny" expect_used = "deny"
redundant_clone = "deny"
uninlined_format_args = "deny" uninlined_format_args = "deny"
unwrap_used = "deny" unwrap_used = "deny"

View File

@@ -617,7 +617,7 @@ fn test_parse_patch_lenient() {
assert_eq!( assert_eq!(
parse_patch_text(&patch_text_in_double_quoted_heredoc, ParseMode::Lenient), parse_patch_text(&patch_text_in_double_quoted_heredoc, ParseMode::Lenient),
Ok(ApplyPatchArgs { Ok(ApplyPatchArgs {
hunks: expected_patch.clone(), hunks: expected_patch,
patch: patch_text.to_string(), patch: patch_text.to_string(),
workdir: None, workdir: None,
}) })
@@ -637,7 +637,7 @@ fn test_parse_patch_lenient() {
"<<EOF\n*** Begin Patch\n*** Update File: file2.py\nEOF\n".to_string(); "<<EOF\n*** Begin Patch\n*** Update File: file2.py\nEOF\n".to_string();
assert_eq!( assert_eq!(
parse_patch_text(&patch_text_with_missing_closing_heredoc, ParseMode::Strict), parse_patch_text(&patch_text_with_missing_closing_heredoc, ParseMode::Strict),
Err(expected_error.clone()) Err(expected_error)
); );
assert_eq!( assert_eq!(
parse_patch_text(&patch_text_with_missing_closing_heredoc, ParseMode::Lenient), parse_patch_text(&patch_text_with_missing_closing_heredoc, ParseMode::Lenient),

View File

@@ -131,8 +131,7 @@ impl CodexAuth {
} }
pub fn get_account_id(&self) -> Option<String> { pub fn get_account_id(&self) -> Option<String> {
self.get_current_token_data() self.get_current_token_data().and_then(|t| t.account_id)
.and_then(|t| t.account_id.clone())
} }
pub fn get_plan_type(&self) -> Option<String> { pub fn get_plan_type(&self) -> Option<String> {
@@ -146,7 +145,7 @@ impl CodexAuth {
} }
fn get_current_token_data(&self) -> Option<TokenData> { fn get_current_token_data(&self) -> Option<TokenData> {
self.get_current_auth_json().and_then(|t| t.tokens.clone()) self.get_current_auth_json().and_then(|t| t.tokens)
} }
/// Consider this private to integration tests. /// Consider this private to integration tests.
@@ -291,10 +290,10 @@ async fn update_tokens(
let tokens = auth_dot_json.tokens.get_or_insert_with(TokenData::default); let tokens = auth_dot_json.tokens.get_or_insert_with(TokenData::default);
tokens.id_token = parse_id_token(&id_token).map_err(std::io::Error::other)?; tokens.id_token = parse_id_token(&id_token).map_err(std::io::Error::other)?;
if let Some(access_token) = access_token { if let Some(access_token) = access_token {
tokens.access_token = access_token.to_string(); tokens.access_token = access_token;
} }
if let Some(refresh_token) = refresh_token { if let Some(refresh_token) = refresh_token {
tokens.refresh_token = refresh_token.to_string(); tokens.refresh_token = refresh_token;
} }
auth_dot_json.last_refresh = Some(Utc::now()); auth_dot_json.last_refresh = Some(Utc::now());
write_auth_json(auth_file, &auth_dot_json)?; write_auth_json(auth_file, &auth_dot_json)?;

View File

@@ -214,12 +214,7 @@ impl Codex {
let conversation_id = session.conversation_id; let conversation_id = session.conversation_id;
// This task will run until Op::Shutdown is received. // This task will run until Op::Shutdown is received.
tokio::spawn(submission_loop( tokio::spawn(submission_loop(session, turn_context, config, rx_sub));
session.clone(),
turn_context,
config,
rx_sub,
));
let codex = Codex { let codex = Codex {
next_id: AtomicU64::new(0), next_id: AtomicU64::new(0),
tx_sub, tx_sub,
@@ -1074,7 +1069,7 @@ impl AgentTask {
id: self.sub_id, id: self.sub_id,
msg: EventMsg::TurnAborted(TurnAbortedEvent { reason }), msg: EventMsg::TurnAborted(TurnAbortedEvent { reason }),
}; };
let sess = self.sess.clone(); let sess = self.sess;
tokio::spawn(async move { tokio::spawn(async move {
sess.send_event(event).await; sess.send_event(event).await;
}); });
@@ -1772,7 +1767,7 @@ async fn try_run_turn(
} }
}) })
.map(|call_id| ResponseItem::CustomToolCallOutput { .map(|call_id| ResponseItem::CustomToolCallOutput {
call_id: call_id.clone(), call_id,
output: "aborted".to_string(), output: "aborted".to_string(),
}) })
.collect::<Vec<_>>() .collect::<Vec<_>>()
@@ -1792,7 +1787,7 @@ async fn try_run_turn(
cwd: turn_context.cwd.clone(), cwd: turn_context.cwd.clone(),
approval_policy: turn_context.approval_policy, approval_policy: turn_context.approval_policy,
sandbox_policy: turn_context.sandbox_policy.clone(), sandbox_policy: turn_context.sandbox_policy.clone(),
model: turn_context.client.get_model().clone(), model: turn_context.client.get_model(),
effort: turn_context.client.get_reasoning_effort(), effort: turn_context.client.get_reasoning_effort(),
summary: turn_context.client.get_reasoning_summary(), summary: turn_context.client.get_reasoning_summary(),
}); });
@@ -3154,7 +3149,7 @@ mod tests {
exit_code: 0, exit_code: 0,
stdout: StreamOutput::new(String::new()), stdout: StreamOutput::new(String::new()),
stderr: StreamOutput::new(String::new()), stderr: StreamOutput::new(String::new()),
aggregated_output: StreamOutput::new(full.clone()), aggregated_output: StreamOutput::new(full),
duration: StdDuration::from_secs(1), duration: StdDuration::from_secs(1),
}; };
@@ -3188,7 +3183,7 @@ mod tests {
fn model_truncation_respects_byte_budget() { fn model_truncation_respects_byte_budget() {
// Construct a large output (about 100kB) so byte budget dominates // Construct a large output (about 100kB) so byte budget dominates
let big_line = "x".repeat(100); let big_line = "x".repeat(100);
let full = std::iter::repeat_n(big_line.clone(), 1000) let full = std::iter::repeat_n(big_line, 1000)
.collect::<Vec<_>>() .collect::<Vec<_>>()
.join("\n"); .join("\n");

View File

@@ -63,7 +63,7 @@ impl EnvironmentContext {
if writable_roots.is_empty() { if writable_roots.is_empty() {
None None
} else { } else {
Some(writable_roots.clone()) Some(writable_roots)
} }
} }
_ => None, _ => None,

View File

@@ -159,7 +159,7 @@ mod tests {
EventMsg::UserMessage(user) => { EventMsg::UserMessage(user) => {
assert_eq!(user.message, "Hello world"); assert_eq!(user.message, "Hello world");
assert!(matches!(user.kind, Some(InputMessageKind::Plain))); assert!(matches!(user.kind, Some(InputMessageKind::Plain)));
assert_eq!(user.images, Some(vec![img1.clone(), img2.clone()])); assert_eq!(user.images, Some(vec![img1, img2]));
} }
other => panic!("expected UserMessage, got {other:?}"), other => panic!("expected UserMessage, got {other:?}"),
} }

View File

@@ -802,7 +802,7 @@ mod tests {
async fn resolve_root_git_project_for_trust_regular_repo_returns_repo_root() { async fn resolve_root_git_project_for_trust_regular_repo_returns_repo_root() {
let temp_dir = TempDir::new().expect("Failed to create temp dir"); let temp_dir = TempDir::new().expect("Failed to create temp dir");
let repo_path = create_test_git_repo(&temp_dir).await; let repo_path = create_test_git_repo(&temp_dir).await;
let expected = std::fs::canonicalize(&repo_path).unwrap().to_path_buf(); let expected = std::fs::canonicalize(&repo_path).unwrap();
assert_eq!( assert_eq!(
resolve_root_git_project_for_trust(&repo_path), resolve_root_git_project_for_trust(&repo_path),
@@ -810,10 +810,7 @@ mod tests {
); );
let nested = repo_path.join("sub/dir"); let nested = repo_path.join("sub/dir");
std::fs::create_dir_all(&nested).unwrap(); std::fs::create_dir_all(&nested).unwrap();
assert_eq!( assert_eq!(resolve_root_git_project_for_trust(&nested), Some(expected));
resolve_root_git_project_for_trust(&nested),
Some(expected.clone())
);
} }
#[tokio::test] #[tokio::test]

View File

@@ -868,7 +868,7 @@ pub fn parse_command_impl(command: &[String]) -> Vec<ParsedCommand> {
let parts = if contains_connectors(&normalized) { let parts = if contains_connectors(&normalized) {
split_on_connectors(&normalized) split_on_connectors(&normalized)
} else { } else {
vec![normalized.clone()] vec![normalized]
}; };
// Preserve left-to-right execution order for all commands, including bash -c/-lc // Preserve left-to-right execution order for all commands, including bash -c/-lc
@@ -1201,10 +1201,7 @@ fn parse_bash_lc_commands(original: &[String]) -> Option<Vec<ParsedCommand>> {
name, name,
} }
} else { } else {
ParsedCommand::Read { ParsedCommand::Read { cmd, name }
cmd: cmd.clone(),
name,
}
} }
} else { } else {
ParsedCommand::Read { ParsedCommand::Read {
@@ -1215,10 +1212,7 @@ fn parse_bash_lc_commands(original: &[String]) -> Option<Vec<ParsedCommand>> {
} }
ParsedCommand::ListFiles { path, cmd, .. } => { ParsedCommand::ListFiles { path, cmd, .. } => {
if had_connectors { if had_connectors {
ParsedCommand::ListFiles { ParsedCommand::ListFiles { cmd, path }
cmd: cmd.clone(),
path,
}
} else { } else {
ParsedCommand::ListFiles { ParsedCommand::ListFiles {
cmd: shlex_join(&script_tokens), cmd: shlex_join(&script_tokens),
@@ -1230,11 +1224,7 @@ fn parse_bash_lc_commands(original: &[String]) -> Option<Vec<ParsedCommand>> {
query, path, cmd, .. query, path, cmd, ..
} => { } => {
if had_connectors { if had_connectors {
ParsedCommand::Search { ParsedCommand::Search { cmd, query, path }
cmd: cmd.clone(),
query,
path,
}
} else { } else {
ParsedCommand::Search { ParsedCommand::Search {
cmd: shlex_join(&script_tokens), cmd: shlex_join(&script_tokens),

View File

@@ -115,7 +115,7 @@ pub fn discover_project_doc_paths(config: &Config) -> std::io::Result<Vec<PathBu
// Build chain from cwd upwards and detect git root. // Build chain from cwd upwards and detect git root.
let mut chain: Vec<PathBuf> = vec![dir.clone()]; let mut chain: Vec<PathBuf> = vec![dir.clone()];
let mut git_root: Option<PathBuf> = None; let mut git_root: Option<PathBuf> = None;
let mut cursor = dir.clone(); let mut cursor = dir;
while let Some(parent) = cursor.parent() { while let Some(parent) = cursor.parent() {
let git_marker = cursor.join(".git"); let git_marker = cursor.join(".git");
let git_exists = match std::fs::metadata(&git_marker) { let git_exists = match std::fs::metadata(&git_marker) {

View File

@@ -305,7 +305,7 @@ async fn test_pagination_cursor() {
path: p1, path: p1,
head: head_1, head: head_1,
}], }],
next_cursor: Some(expected_cursor3.clone()), next_cursor: Some(expected_cursor3),
num_scanned_files: 5, // scanned 05, 04 (anchor), 03, 02 (anchor), 01 num_scanned_files: 5, // scanned 05, 04 (anchor), 03, 02 (anchor), 01
reached_scan_cap: false, reached_scan_cap: false,
}; };
@@ -344,7 +344,7 @@ async fn test_get_conversation_contents() {
let expected_cursor: Cursor = serde_json::from_str(&format!("\"{ts}|{uuid}\"")).unwrap(); let expected_cursor: Cursor = serde_json::from_str(&format!("\"{ts}|{uuid}\"")).unwrap();
let expected_page = ConversationsPage { let expected_page = ConversationsPage {
items: vec![ConversationItem { items: vec![ConversationItem {
path: expected_path.clone(), path: expected_path,
head: expected_head, head: expected_head,
}], }],
next_cursor: Some(expected_cursor), next_cursor: Some(expected_cursor),
@@ -437,7 +437,7 @@ async fn test_stable_ordering_same_second_pagination() {
path: p1, path: p1,
head: head(u1), head: head(u1),
}], }],
next_cursor: Some(expected_cursor2.clone()), next_cursor: Some(expected_cursor2),
num_scanned_files: 3, // scanned u3, u2 (anchor), u1 num_scanned_files: 3, // scanned u3, u2 (anchor), u1
reached_scan_cap: false, reached_scan_cap: false,
}; };

View File

@@ -293,7 +293,7 @@ mod tests {
// With the parent dir explicitly added as a writable root, the // With the parent dir explicitly added as a writable root, the
// outside write should be permitted. // outside write should be permitted.
let policy_with_parent = SandboxPolicy::WorkspaceWrite { let policy_with_parent = SandboxPolicy::WorkspaceWrite {
writable_roots: vec![parent.clone()], writable_roots: vec![parent],
network_access: false, network_access: false,
exclude_tmpdir_env_var: true, exclude_tmpdir_env_var: true,
exclude_slash_tmp: true, exclude_slash_tmp: true,

View File

@@ -153,7 +153,7 @@ mod tests {
// Build a policy that only includes the two test roots as writable and // Build a policy that only includes the two test roots as writable and
// does not automatically include defaults TMPDIR or /tmp. // does not automatically include defaults TMPDIR or /tmp.
let policy = SandboxPolicy::WorkspaceWrite { let policy = SandboxPolicy::WorkspaceWrite {
writable_roots: vec![root_with_git.clone(), root_without_git.clone()], writable_roots: vec![root_with_git, root_without_git],
network_access: false, network_access: false,
exclude_tmpdir_env_var: true, exclude_tmpdir_env_var: true,
exclude_slash_tmp: true, exclude_slash_tmp: true,

View File

@@ -326,10 +326,7 @@ mod tests {
.format_default_shell_invocation(input.iter().map(|s| s.to_string()).collect()); .format_default_shell_invocation(input.iter().map(|s| s.to_string()).collect());
let expected_cmd = expected_cmd let expected_cmd = expected_cmd
.iter() .iter()
.map(|s| { .map(|s| s.replace("BASHRC_PATH", bashrc_path.to_str().unwrap()))
s.replace("BASHRC_PATH", bashrc_path.to_str().unwrap())
.to_string()
})
.collect(); .collect();
assert_eq!(actual_cmd, Some(expected_cmd)); assert_eq!(actual_cmd, Some(expected_cmd));
@@ -435,10 +432,7 @@ mod macos_tests {
.format_default_shell_invocation(input.iter().map(|s| s.to_string()).collect()); .format_default_shell_invocation(input.iter().map(|s| s.to_string()).collect());
let expected_cmd = expected_cmd let expected_cmd = expected_cmd
.iter() .iter()
.map(|s| { .map(|s| s.replace("ZSHRC_PATH", zshrc_path.to_str().unwrap()))
s.replace("ZSHRC_PATH", zshrc_path.to_str().unwrap())
.to_string()
})
.collect(); .collect();
assert_eq!(actual_cmd, Some(expected_cmd)); assert_eq!(actual_cmd, Some(expected_cmd));

View File

@@ -678,7 +678,7 @@ index {left_oid}..{right_oid}
let dest = dir.path().join("dest.txt"); let dest = dir.path().join("dest.txt");
let mut acc = TurnDiffTracker::new(); let mut acc = TurnDiffTracker::new();
let mv = HashMap::from([( let mv = HashMap::from([(
src.clone(), src,
FileChange::Update { FileChange::Update {
unified_diff: "".into(), unified_diff: "".into(),
move_path: Some(dest.clone()), move_path: Some(dest.clone()),

View File

@@ -280,7 +280,7 @@ impl EventProcessor for EventProcessorWithHumanOutput {
parsed_cmd: _, parsed_cmd: _,
}) => { }) => {
self.call_id_to_command.insert( self.call_id_to_command.insert(
call_id.clone(), call_id,
ExecCommandBegin { ExecCommandBegin {
command: command.clone(), command: command.clone(),
}, },
@@ -382,7 +382,7 @@ impl EventProcessor for EventProcessorWithHumanOutput {
// Store metadata so we can calculate duration later when we // Store metadata so we can calculate duration later when we
// receive the corresponding PatchApplyEnd event. // receive the corresponding PatchApplyEnd event.
self.call_id_to_patch.insert( self.call_id_to_patch.insert(
call_id.clone(), call_id,
PatchApplyBegin { PatchApplyBegin {
start_time: Instant::now(), start_time: Instant::now(),
auto_approved, auto_approved,

View File

@@ -61,7 +61,7 @@ pub(crate) async fn run_e2e_exec_test(cwd: &Path, response_streams: Vec<String>)
.context("should find binary for codex-exec") .context("should find binary for codex-exec")
.expect("should find binary for codex-exec") .expect("should find binary for codex-exec")
.current_dir(cwd.clone()) .current_dir(cwd.clone())
.env("CODEX_HOME", cwd.clone()) .env("CODEX_HOME", cwd)
.env("OPENAI_API_KEY", "dummy") .env("OPENAI_API_KEY", "dummy")
.env("OPENAI_BASE_URL", format!("{uri}/v1")) .env("OPENAI_BASE_URL", format!("{uri}/v1"))
.arg("--skip-git-repo-check") .arg("--skip-git-repo-check")

View File

@@ -88,7 +88,7 @@ impl ExecvChecker {
let mut program = valid_exec.program.to_string(); let mut program = valid_exec.program.to_string();
for system_path in valid_exec.system_path { for system_path in valid_exec.system_path {
if is_executable_file(&system_path) { if is_executable_file(&system_path) {
program = system_path.to_string(); program = system_path;
break; break;
} }
} }
@@ -196,7 +196,7 @@ system_path=[{fake_cp:?}]
let checker = setup(&fake_cp); let checker = setup(&fake_cp);
let exec_call = ExecCall { let exec_call = ExecCall {
program: "cp".into(), program: "cp".into(),
args: vec![source.clone(), dest.clone()], args: vec![source, dest.clone()],
}; };
let valid_exec = match checker.r#match(&exec_call)? { let valid_exec = match checker.r#match(&exec_call)? {
MatchedExec::Match { exec } => exec, MatchedExec::Match { exec } => exec,
@@ -207,7 +207,7 @@ system_path=[{fake_cp:?}]
assert_eq!( assert_eq!(
checker.check(valid_exec.clone(), &cwd, &[], &[]), checker.check(valid_exec.clone(), &cwd, &[], &[]),
Err(ReadablePathNotInReadableFolders { Err(ReadablePathNotInReadableFolders {
file: source_path.clone(), file: source_path,
folders: vec![] folders: vec![]
}), }),
); );
@@ -229,7 +229,7 @@ system_path=[{fake_cp:?}]
// Both readable and writeable folders specified. // Both readable and writeable folders specified.
assert_eq!( assert_eq!(
checker.check( checker.check(
valid_exec.clone(), valid_exec,
&cwd, &cwd,
std::slice::from_ref(&root_path), std::slice::from_ref(&root_path),
std::slice::from_ref(&root_path) std::slice::from_ref(&root_path)
@@ -241,7 +241,7 @@ system_path=[{fake_cp:?}]
// folders. // folders.
let exec_call_folders_as_args = ExecCall { let exec_call_folders_as_args = ExecCall {
program: "cp".into(), program: "cp".into(),
args: vec![root.clone(), root.clone()], args: vec![root.clone(), root],
}; };
let valid_exec_call_folders_as_args = match checker.r#match(&exec_call_folders_as_args)? { let valid_exec_call_folders_as_args = match checker.r#match(&exec_call_folders_as_args)? {
MatchedExec::Match { exec } => exec, MatchedExec::Match { exec } => exec,
@@ -254,7 +254,7 @@ system_path=[{fake_cp:?}]
std::slice::from_ref(&root_path), std::slice::from_ref(&root_path),
std::slice::from_ref(&root_path) std::slice::from_ref(&root_path)
), ),
Ok(cp.clone()), Ok(cp),
); );
// Specify a parent of a readable folder as input. // Specify a parent of a readable folder as input.

View File

@@ -104,7 +104,7 @@ impl PolicyBuilder {
info!("adding program spec: {program_spec:?}"); info!("adding program spec: {program_spec:?}");
let name = program_spec.program.clone(); let name = program_spec.program.clone();
let mut programs = self.programs.borrow_mut(); let mut programs = self.programs.borrow_mut();
programs.insert(name.clone(), program_spec); programs.insert(name, program_spec);
} }
fn add_forbidden_substrings(&self, substrings: &[String]) { fn add_forbidden_substrings(&self, substrings: &[String]) {

View File

@@ -42,7 +42,7 @@ impl ServerOptions {
pub fn new(codex_home: PathBuf, client_id: String) -> Self { pub fn new(codex_home: PathBuf, client_id: String) -> Self {
Self { Self {
codex_home, codex_home,
client_id: client_id.to_string(), client_id,
issuer: DEFAULT_ISSUER.to_string(), issuer: DEFAULT_ISSUER.to_string(),
port: DEFAULT_PORT, port: DEFAULT_PORT,
open_browser: true, open_browser: true,
@@ -126,7 +126,7 @@ pub fn run_login_server(opts: ServerOptions) -> io::Result<LoginServer> {
let shutdown_notify = Arc::new(tokio::sync::Notify::new()); let shutdown_notify = Arc::new(tokio::sync::Notify::new());
let server_handle = { let server_handle = {
let shutdown_notify = shutdown_notify.clone(); let shutdown_notify = shutdown_notify.clone();
let server = server.clone(); let server = server;
tokio::spawn(async move { tokio::spawn(async move {
let result = loop { let result = loop {
tokio::select! { tokio::select! {

View File

@@ -222,7 +222,7 @@ async fn run_codex_tool_session_inner(
} }
EventMsg::TaskComplete(TaskCompleteEvent { last_agent_message }) => { EventMsg::TaskComplete(TaskCompleteEvent { last_agent_message }) => {
let text = match last_agent_message { let text = match last_agent_message {
Some(msg) => msg.clone(), Some(msg) => msg,
None => "".to_string(), None => "".to_string(),
}; };
let result = CallToolResult { let result = CallToolResult {

View File

@@ -531,7 +531,6 @@ impl MessageProcessor {
// Spawn the long-running reply handler. // Spawn the long-running reply handler.
tokio::spawn({ tokio::spawn({
let codex = codex.clone();
let outgoing = outgoing.clone(); let outgoing = outgoing.clone();
let prompt = prompt.clone(); let prompt = prompt.clone();
let running_requests_id_to_codex_uuid = running_requests_id_to_codex_uuid.clone(); let running_requests_id_to_codex_uuid = running_requests_id_to_codex_uuid.clone();

View File

@@ -299,7 +299,7 @@ mod tests {
let Ok(expected_params) = serde_json::to_value(&event) else { let Ok(expected_params) = serde_json::to_value(&event) else {
panic!("Event must serialize"); panic!("Event must serialize");
}; };
assert_eq!(params, Some(expected_params.clone())); assert_eq!(params, Some(expected_params));
} }
#[tokio::test] #[tokio::test]

View File

@@ -304,7 +304,7 @@ impl App {
} }
pub(crate) fn token_usage(&self) -> codex_core::protocol::TokenUsage { pub(crate) fn token_usage(&self) -> codex_core::protocol::TokenUsage {
self.chat_widget.token_usage().clone() self.chat_widget.token_usage()
} }
async fn handle_key_event(&mut self, tui: &mut tui::Tui, key_event: KeyEvent) { async fn handle_key_event(&mut self, tui: &mut tui::Tui, key_event: KeyEvent) {

View File

@@ -487,7 +487,7 @@ impl ChatComposer {
} => { } => {
// Hide popup without modifying text, remember token to avoid immediate reopen. // Hide popup without modifying text, remember token to avoid immediate reopen.
if let Some(tok) = Self::current_at_token(&self.textarea) { if let Some(tok) = Self::current_at_token(&self.textarea) {
self.dismissed_file_popup_token = Some(tok.to_string()); self.dismissed_file_popup_token = Some(tok);
} }
self.active_popup = ActivePopup::None; self.active_popup = ActivePopup::None;
(InputResult::None, true) (InputResult::None, true)
@@ -546,7 +546,7 @@ impl ChatComposer {
Some(ext) if ext == "jpg" || ext == "jpeg" => "JPEG", Some(ext) if ext == "jpg" || ext == "jpeg" => "JPEG",
_ => "IMG", _ => "IMG",
}; };
self.attach_image(path_buf.clone(), w, h, format_label); self.attach_image(path_buf, w, h, format_label);
// Add a trailing space to keep typing fluid. // Add a trailing space to keep typing fluid.
self.textarea.insert_str(" "); self.textarea.insert_str(" ");
} else { } else {
@@ -2123,7 +2123,7 @@ mod tests {
// Re-add and test backspace in middle: should break the placeholder string // Re-add and test backspace in middle: should break the placeholder string
// and drop the image mapping (same as text placeholder behavior). // and drop the image mapping (same as text placeholder behavior).
composer.attach_image(path.clone(), 20, 10, "PNG"); composer.attach_image(path, 20, 10, "PNG");
let placeholder2 = composer.attached_images[0].placeholder.clone(); let placeholder2 = composer.attached_images[0].placeholder.clone();
// Move cursor to roughly middle of placeholder // Move cursor to roughly middle of placeholder
if let Some(start_pos) = composer.textarea.text().find(&placeholder2) { if let Some(start_pos) = composer.textarea.text().find(&placeholder2) {
@@ -2182,7 +2182,7 @@ mod tests {
let path1 = PathBuf::from("/tmp/image_dup1.png"); let path1 = PathBuf::from("/tmp/image_dup1.png");
let path2 = PathBuf::from("/tmp/image_dup2.png"); let path2 = PathBuf::from("/tmp/image_dup2.png");
composer.attach_image(path1.clone(), 10, 5, "PNG"); composer.attach_image(path1, 10, 5, "PNG");
// separate placeholders with a space for clarity // separate placeholders with a space for clarity
composer.handle_paste(" ".into()); composer.handle_paste(" ".into());
composer.attach_image(path2.clone(), 10, 5, "PNG"); composer.attach_image(path2.clone(), 10, 5, "PNG");
@@ -2231,7 +2231,7 @@ mod tests {
assert!(composer.textarea.text().starts_with("[image 3x2 PNG] ")); assert!(composer.textarea.text().starts_with("[image 3x2 PNG] "));
let imgs = composer.take_recent_submission_images(); let imgs = composer.take_recent_submission_images();
assert_eq!(imgs, vec![tmp_path.clone()]); assert_eq!(imgs, vec![tmp_path]);
} }
#[test] #[test]

View File

@@ -564,7 +564,7 @@ mod tests {
let (tx_raw, rx) = unbounded_channel::<AppEvent>(); let (tx_raw, rx) = unbounded_channel::<AppEvent>();
let tx = AppEventSender::new(tx_raw); let tx = AppEventSender::new(tx_raw);
let mut pane = BottomPane::new(BottomPaneParams { let mut pane = BottomPane::new(BottomPaneParams {
app_event_tx: tx.clone(), app_event_tx: tx,
frame_requester: FrameRequester::test_dummy(), frame_requester: FrameRequester::test_dummy(),
has_input_focus: true, has_input_focus: true,
enhanced_keys_supported: false, enhanced_keys_supported: false,

View File

@@ -649,9 +649,7 @@ impl TextArea {
} }
fn add_element(&mut self, range: Range<usize>) { fn add_element(&mut self, range: Range<usize>) {
let elem = TextElement { let elem = TextElement { range };
range: range.clone(),
};
self.elements.push(elem); self.elements.push(elem);
self.elements.sort_by_key(|e| e.range.start); self.elements.sort_by_key(|e| e.range.start);
} }

View File

@@ -574,14 +574,14 @@ impl ChatWidget {
self.active_exec_cell = Some(history_cell::new_active_exec_command( self.active_exec_cell = Some(history_cell::new_active_exec_command(
ev.call_id.clone(), ev.call_id.clone(),
ev.command.clone(), ev.command.clone(),
ev.parsed_cmd.clone(), ev.parsed_cmd,
)); ));
} }
} else { } else {
self.active_exec_cell = Some(history_cell::new_active_exec_command( self.active_exec_cell = Some(history_cell::new_active_exec_command(
ev.call_id.clone(), ev.call_id.clone(),
ev.command.clone(), ev.command.clone(),
ev.parsed_cmd.clone(), ev.parsed_cmd,
)); ));
} }
@@ -804,7 +804,7 @@ impl ChatWidget {
"attach_image path={path:?} width={width} height={height} format={format_label}", "attach_image path={path:?} width={width} height={height} format={format_label}",
); );
self.bottom_pane self.bottom_pane
.attach_image(path.clone(), width, height, format_label); .attach_image(path, width, height, format_label);
self.request_redraw(); self.request_redraw();
} }
@@ -986,7 +986,7 @@ impl ChatWidget {
// Only show the text portion in conversation history. // Only show the text portion in conversation history.
if !text.is_empty() { if !text.is_empty() {
self.add_to_history(history_cell::new_user_prompt(text.clone())); self.add_to_history(history_cell::new_user_prompt(text));
} }
} }
@@ -1055,10 +1055,10 @@ impl ChatWidget {
EventMsg::PlanUpdate(update) => self.on_plan_update(update), EventMsg::PlanUpdate(update) => self.on_plan_update(update),
EventMsg::ExecApprovalRequest(ev) => { EventMsg::ExecApprovalRequest(ev) => {
// For replayed events, synthesize an empty id (these should not occur). // For replayed events, synthesize an empty id (these should not occur).
self.on_exec_approval_request(id.clone().unwrap_or_default(), ev) self.on_exec_approval_request(id.unwrap_or_default(), ev)
} }
EventMsg::ApplyPatchApprovalRequest(ev) => { EventMsg::ApplyPatchApprovalRequest(ev) => {
self.on_apply_patch_approval_request(id.clone().unwrap_or_default(), ev) self.on_apply_patch_approval_request(id.unwrap_or_default(), ev)
} }
EventMsg::ExecCommandBegin(ev) => self.on_exec_command_begin(ev), EventMsg::ExecCommandBegin(ev) => self.on_exec_command_begin(ev),
EventMsg::ExecCommandOutputDelta(delta) => self.on_exec_command_output_delta(delta), EventMsg::ExecCommandOutputDelta(delta) => self.on_exec_command_output_delta(delta),

View File

@@ -20,7 +20,7 @@ pub(crate) fn spawn_agent(
) -> UnboundedSender<Op> { ) -> UnboundedSender<Op> {
let (codex_op_tx, mut codex_op_rx) = unbounded_channel::<Op>(); let (codex_op_tx, mut codex_op_rx) = unbounded_channel::<Op>();
let app_event_tx_clone = app_event_tx.clone(); let app_event_tx_clone = app_event_tx;
tokio::spawn(async move { tokio::spawn(async move {
let NewConversation { let NewConversation {
conversation_id: _, conversation_id: _,
@@ -71,7 +71,7 @@ pub(crate) fn spawn_agent_from_existing(
) -> UnboundedSender<Op> { ) -> UnboundedSender<Op> {
let (codex_op_tx, mut codex_op_rx) = unbounded_channel::<Op>(); let (codex_op_tx, mut codex_op_rx) = unbounded_channel::<Op>();
let app_event_tx_clone = app_event_tx.clone(); let app_event_tx_clone = app_event_tx;
tokio::spawn(async move { tokio::spawn(async move {
// Forward the captured `SessionConfigured` event so it can be rendered in the UI. // Forward the captured `SessionConfigured` event so it can be rendered in the UI.
let ev = codex_core::protocol::Event { let ev = codex_core::protocol::Event {

View File

@@ -352,7 +352,7 @@ fn exec_approval_decision_truncates_multiline_and_long_commands() {
let long = format!("echo {}", "a".repeat(200)); let long = format!("echo {}", "a".repeat(200));
let ev_long = ExecApprovalRequestEvent { let ev_long = ExecApprovalRequestEvent {
call_id: "call-long".into(), call_id: "call-long".into(),
command: vec!["bash".into(), "-lc".into(), long.clone()], command: vec!["bash".into(), "-lc".into(), long],
cwd: std::env::current_dir().unwrap_or_else(|_| PathBuf::from(".")), cwd: std::env::current_dir().unwrap_or_else(|_| PathBuf::from(".")),
reason: None, reason: None,
}; };

View File

@@ -737,10 +737,10 @@ mod tests {
let mut changes: HashMap<PathBuf, FileChange> = HashMap::new(); let mut changes: HashMap<PathBuf, FileChange> = HashMap::new();
changes.insert( changes.insert(
abs_old.clone(), abs_old,
FileChange::Update { FileChange::Update {
unified_diff: patch, unified_diff: patch,
move_path: Some(abs_new.clone()), move_path: Some(abs_new),
}, },
); );

View File

@@ -697,7 +697,7 @@ fn spinner(start_time: Option<Instant>) -> Span<'static> {
pub(crate) fn new_active_mcp_tool_call(invocation: McpInvocation) -> PlainHistoryCell { pub(crate) fn new_active_mcp_tool_call(invocation: McpInvocation) -> PlainHistoryCell {
let title_line = Line::from(vec!["tool".magenta(), " running...".dim()]); let title_line = Line::from(vec!["tool".magenta(), " running...".dim()]);
let lines: Vec<Line> = vec![title_line, format_mcp_invocation(invocation.clone())]; let lines: Vec<Line> = vec![title_line, format_mcp_invocation(invocation)];
PlainHistoryCell { lines } PlainHistoryCell { lines }
} }
@@ -1324,7 +1324,7 @@ fn format_mcp_invocation<'a>(invocation: McpInvocation) -> Line<'a> {
let invocation_spans = vec![ let invocation_spans = vec![
invocation.server.clone().cyan(), invocation.server.clone().cyan(),
".".into(), ".".into(),
invocation.tool.clone().cyan(), invocation.tool.cyan(),
"(".into(), "(".into(),
args_str.dim(), args_str.dim(),
")".into(), ")".into(),

View File

@@ -432,7 +432,7 @@ impl AuthModeWidget {
match &mut *guard { match &mut *guard {
SignInState::ApiKeyEntry(state) => { SignInState::ApiKeyEntry(state) => {
if state.value.is_empty() { if state.value.is_empty() {
if let Some(prefill) = prefill_from_env.clone() { if let Some(prefill) = prefill_from_env {
state.value = prefill; state.value = prefill;
state.prepopulated_from_env = true; state.prepopulated_from_env = true;
} else { } else {

View File

@@ -71,7 +71,7 @@ impl OnboardingScreen {
config, config,
} = args; } = args;
let cwd = config.cwd.clone(); let cwd = config.cwd.clone();
let codex_home = config.codex_home.clone(); let codex_home = config.codex_home;
let mut steps: Vec<Step> = vec![Step::Welcome(WelcomeWidget { let mut steps: Vec<Step> = vec![Step::Welcome(WelcomeWidget {
is_logged_in: !matches!(login_status, LoginStatus::NotAuthenticated), is_logged_in: !matches!(login_status, LoginStatus::NotAuthenticated),
})]; })];

View File

@@ -244,7 +244,7 @@ impl UserApprovalWidget {
"You ".into(), "You ".into(),
"approved".bold(), "approved".bold(),
" codex to run ".into(), " codex to run ".into(),
snippet.clone().dim(), snippet.dim(),
" this time".bold(), " this time".bold(),
]); ]);
} }
@@ -254,7 +254,7 @@ impl UserApprovalWidget {
"You ".into(), "You ".into(),
"approved".bold(), "approved".bold(),
" codex to run ".into(), " codex to run ".into(),
snippet.clone().dim(), snippet.dim(),
" every time this session".bold(), " every time this session".bold(),
]); ]);
} }
@@ -264,7 +264,7 @@ impl UserApprovalWidget {
"You ".into(), "You ".into(),
"did not approve".bold(), "did not approve".bold(),
" codex to run ".into(), " codex to run ".into(),
snippet.clone().dim(), snippet.dim(),
]); ]);
} }
ReviewDecision::Abort => { ReviewDecision::Abort => {
@@ -273,7 +273,7 @@ impl UserApprovalWidget {
"You ".into(), "You ".into(),
"canceled".bold(), "canceled".bold(),
" the request to run ".into(), " the request to run ".into(),
snippet.clone().dim(), snippet.dim(),
]); ]);
} }
} }