Download crates/forge_app/src/fmt/fmt_output.rs from SaylorTwift/forgecode: direct link, hf CLI and curl.
- Browser
- Download file 17.8 kB
-
https://huggingface.co/SaylorTwift/forgecode/resolve/main/crates/forge_app/src/fmt/fmt_output.rs
- Command line
-
hf download hf://SaylorTwift/forgecode/crates/forge_app/src/fmt/fmt_output.rs
-
curl -L -o fmt_output.rs https://huggingface.co/SaylorTwift/forgecode/resolve/main/crates/forge_app/src/fmt/fmt_output.rs
17.8 kB
| use forge_display::DiffFormat; | |
| use forge_domain::{ChatResponseContent, Environment, TitleFormat}; | |
| use crate::fmt::content::FormatContent; | |
| use crate::fmt::todo_fmt::{format_todos, format_todos_diff}; | |
| use crate::operation::ToolOperation; | |
| use crate::utils::format_display_path; | |
| impl FormatContent for ToolOperation { | |
| fn to_content(&self, env: &Environment) -> Option<ChatResponseContent> { | |
| match self { | |
| ToolOperation::FsWrite { input, output } => { | |
| if let Some(ref before) = output.before { | |
| let after = &input.content; | |
| Some(ChatResponseContent::ToolOutput( | |
| DiffFormat::format(before, after).diff().to_string(), | |
| )) | |
| } else { | |
| None | |
| } | |
| } | |
| ToolOperation::FsPatch { input: _, output } => Some(ChatResponseContent::ToolOutput( | |
| DiffFormat::format(&output.before, &output.after) | |
| .diff() | |
| .to_string(), | |
| )), | |
| ToolOperation::FsMultiPatch { input: _, output } => { | |
| Some(ChatResponseContent::ToolOutput( | |
| DiffFormat::format(&output.before, &output.after) | |
| .diff() | |
| .to_string(), | |
| )) | |
| } | |
| ToolOperation::PlanCreate { input: _, output } => Some({ | |
| let title = TitleFormat::debug(format!( | |
| "Create {}", | |
| format_display_path(&output.path, &env.cwd) | |
| )); | |
| title.into() | |
| }), | |
| ToolOperation::TodoWrite { before, after } => Some(ChatResponseContent::ToolOutput( | |
| format_todos_diff(before, after), | |
| )), | |
| ToolOperation::TodoRead { output } => { | |
| Some(ChatResponseContent::ToolOutput(format_todos(output))) | |
| } | |
| ToolOperation::FsRead { input: _, output: _ } | |
| | ToolOperation::FsRemove { input: _, output: _ } | |
| | ToolOperation::FsSearch { input: _, output: _ } | |
| | ToolOperation::CodebaseSearch { output: _ } | |
| | ToolOperation::FsUndo { input: _, output: _ } | |
| | ToolOperation::NetFetch { input: _, output: _ } | |
| | ToolOperation::Shell { output: _ } | |
| | ToolOperation::FollowUp { output: _ } | |
| | ToolOperation::Skill { output: _ } => None, | |
| } | |
| } | |
| } | |
| mod tests { | |
| use std::path::PathBuf; | |
| use console::strip_ansi_codes; | |
| use forge_display::DiffFormat; | |
| use forge_domain::{ChatResponseContent, Environment, FileInfo}; | |
| use insta::assert_snapshot; | |
| use pretty_assertions::assert_eq; | |
| use super::FormatContent; | |
| // ContentFormat is now ChatResponseContent | |
| use crate::operation::ToolOperation; | |
| use crate::{ | |
| Content, FsRemoveOutput, FsUndoOutput, FsWriteOutput, HttpResponse, Match, MatchResult, | |
| PatchOutput, ReadOutput, ResponseContext, SearchResult, ShellOutput, | |
| }; | |
| // ContentFormat methods are now implemented in ChatResponseContent | |
| fn fixture_environment() -> Environment { | |
| use fake::{Fake, Faker}; | |
| Faker.fake() | |
| } | |
| fn test_fs_read_single_line() { | |
| let content = "Hello, world!"; | |
| let fixture = ToolOperation::FsRead { | |
| input: forge_domain::FSRead { | |
| file_path: "/home/user/test.txt".to_string(), | |
| range: None, | |
| show_line_numbers: true, | |
| }, | |
| output: ReadOutput { | |
| content: Content::file(content), | |
| info: FileInfo::new(1, 1, 5, crate::compute_hash(content)), | |
| }, | |
| }; | |
| let env = fixture_environment(); | |
| let actual = fixture.to_content(&env); | |
| let expected = None; | |
| assert_eq!(actual, expected); | |
| } | |
| fn test_fs_read_multiple_lines() { | |
| let content = "Line 1\nLine 2\nLine 3"; | |
| let fixture = ToolOperation::FsRead { | |
| input: forge_domain::FSRead { | |
| file_path: "/home/user/test.txt".to_string(), | |
| range: Some(forge_domain::FSReadRange { start_line: Some(2), end_line: Some(4) }), | |
| show_line_numbers: true, | |
| }, | |
| output: ReadOutput { | |
| content: Content::file(content), | |
| info: FileInfo::new(2, 4, 10, crate::compute_hash(content)), | |
| }, | |
| }; | |
| let env = fixture_environment(); | |
| let actual = fixture.to_content(&env); | |
| let expected = None; | |
| assert_eq!(actual, expected); | |
| } | |
| fn test_fs_create_new_file() { | |
| let content = "New file content"; | |
| let fixture = ToolOperation::FsWrite { | |
| input: forge_domain::FSWrite { | |
| file_path: "/home/user/project/new_file.txt".to_string(), | |
| content: content.to_string(), | |
| overwrite: false, | |
| }, | |
| output: FsWriteOutput { | |
| path: "/home/user/project/new_file.txt".to_string(), | |
| before: None, | |
| errors: vec![], | |
| content_hash: crate::compute_hash(content), | |
| }, | |
| }; | |
| let env = fixture_environment(); | |
| let actual = fixture.to_content(&env); | |
| let expected = None; | |
| assert_eq!(actual, expected); | |
| } | |
| fn test_fs_create_overwrite() { | |
| let content = "new content"; | |
| let fixture = ToolOperation::FsWrite { | |
| input: forge_domain::FSWrite { | |
| file_path: "/home/user/project/existing_file.txt".to_string(), | |
| content: content.to_string(), | |
| overwrite: true, | |
| }, | |
| output: FsWriteOutput { | |
| path: "/home/user/project/existing_file.txt".to_string(), | |
| before: Some("old content".to_string()), | |
| errors: vec![], | |
| content_hash: crate::compute_hash(content), | |
| }, | |
| }; | |
| let env = fixture_environment(); | |
| let actual = fixture.to_content(&env); | |
| let expected = Some(ChatResponseContent::ToolOutput( | |
| DiffFormat::format("old content", "new content") | |
| .diff() | |
| .to_string(), | |
| )); | |
| assert_eq!(actual, expected); | |
| } | |
| fn test_fs_create_with_warning() { | |
| let content = "File content"; | |
| let fixture = ToolOperation::FsWrite { | |
| input: forge_domain::FSWrite { | |
| file_path: "/home/user/project/file.txt".to_string(), | |
| content: content.to_string(), | |
| overwrite: false, | |
| }, | |
| output: FsWriteOutput { | |
| path: "/home/user/project/file.txt".to_string(), | |
| before: None, | |
| errors: vec![forge_domain::SyntaxError { | |
| line: 5, | |
| column: 10, | |
| message: "Syntax error".to_string(), | |
| }], | |
| content_hash: crate::compute_hash(content), | |
| }, | |
| }; | |
| let env = fixture_environment(); | |
| let actual = fixture.to_content(&env); | |
| let expected = None; | |
| assert_eq!(actual, expected); | |
| } | |
| fn test_fs_remove() { | |
| let fixture = ToolOperation::FsRemove { | |
| input: forge_domain::FSRemove { path: "/home/user/project/file.txt".to_string() }, | |
| output: FsRemoveOutput { content: "".to_string() }, | |
| }; | |
| let env = fixture_environment(); | |
| let actual = fixture.to_content(&env); | |
| let expected = None; | |
| assert_eq!(actual, expected); | |
| } | |
| fn test_fs_search_with_matches() { | |
| let fixture = ToolOperation::FsSearch { | |
| input: forge_domain::FSSearch { | |
| path: Some("/home/user/project".to_string()), | |
| pattern: "Hello".to_string(), | |
| ..Default::default() | |
| }, | |
| output: Some(SearchResult { | |
| matches: vec![ | |
| Match { | |
| path: "file1.txt".to_string(), | |
| result: Some(MatchResult::Found { | |
| line_number: Some(1), | |
| line: "Hello world".to_string(), | |
| }), | |
| }, | |
| Match { | |
| path: "file2.txt".to_string(), | |
| result: Some(MatchResult::Found { | |
| line_number: Some(3), | |
| line: "Hello universe".to_string(), | |
| }), | |
| }, | |
| ], | |
| }), | |
| }; | |
| let env = fixture_environment(); | |
| let actual = fixture.to_content(&env); | |
| let expected = None; | |
| assert_eq!(actual, expected); | |
| } | |
| fn test_fs_search_no_matches() { | |
| let fixture = ToolOperation::FsSearch { | |
| input: forge_domain::FSSearch { | |
| path: Some("/home/user/project".to_string()), | |
| pattern: "nonexistent".to_string(), | |
| ..Default::default() | |
| }, | |
| output: Some(SearchResult { | |
| matches: vec![Match { | |
| path: "file1.txt".to_string(), | |
| result: Some(MatchResult::Error("Permission denied".to_string())), | |
| }], | |
| }), | |
| }; | |
| let env = fixture_environment(); | |
| let actual = fixture.to_content(&env); | |
| let expected = None; | |
| assert_eq!(actual, expected); | |
| } | |
| fn test_fs_search_none() { | |
| let fixture = ToolOperation::FsSearch { | |
| input: forge_domain::FSSearch { | |
| path: Some("/home/user/project".to_string()), | |
| pattern: "search".to_string(), | |
| ..Default::default() | |
| }, | |
| output: None, | |
| }; | |
| let env = fixture_environment(); | |
| let actual = fixture.to_content(&env); | |
| let expected = None; | |
| assert_eq!(actual, expected); | |
| } | |
| fn test_fs_patch_success() { | |
| let after_content = "Hello universe\nThis is a test\nNew line"; | |
| let fixture = ToolOperation::FsPatch { | |
| input: forge_domain::FSPatch { | |
| file_path: "/home/user/project/test.txt".to_string(), | |
| old_string: "Hello world".to_string(), | |
| new_string: "Hello universe".to_string(), | |
| replace_all: false, | |
| }, | |
| output: PatchOutput { | |
| errors: vec![], | |
| before: "Hello world\nThis is a test".to_string(), | |
| after: after_content.to_string(), | |
| content_hash: crate::compute_hash(after_content), | |
| }, | |
| }; | |
| let env = fixture_environment(); | |
| let actual = fixture.to_content(&env).unwrap(); | |
| let actual = strip_ansi_codes(actual.as_str()); | |
| assert_snapshot!(actual) | |
| } | |
| fn test_fs_patch_with_warning() { | |
| let after_content = "line1\nnew line\nline2"; | |
| let fixture = ToolOperation::FsPatch { | |
| input: forge_domain::FSPatch { | |
| file_path: "/home/user/project/large_file.txt".to_string(), | |
| old_string: "line2".to_string(), | |
| new_string: "new line\nline2".to_string(), | |
| replace_all: false, | |
| }, | |
| output: PatchOutput { | |
| errors: vec![forge_domain::SyntaxError { | |
| line: 10, | |
| column: 5, | |
| message: "Syntax error".to_string(), | |
| }], | |
| before: "line1\nline2".to_string(), | |
| after: after_content.to_string(), | |
| content_hash: crate::compute_hash(after_content), | |
| }, | |
| }; | |
| let env = fixture_environment(); | |
| let actual = fixture.to_content(&env); | |
| // Should return Some(String) with formatted diff output | |
| assert!(actual.is_some()); | |
| let output = actual.unwrap(); | |
| assert!(output.contains("line1")); | |
| assert!(output.contains("new line")); | |
| } | |
| fn test_fs_undo() { | |
| let fixture = ToolOperation::FsUndo { | |
| input: forge_domain::FSUndo { path: "/home/user/project/test.txt".to_string() }, | |
| output: FsUndoOutput { | |
| before_undo: Some("ABC".to_string()), | |
| after_undo: Some("PQR".to_string()), | |
| }, | |
| }; | |
| let env = fixture_environment(); | |
| let actual = fixture.to_content(&env); | |
| let expected = None; | |
| assert_eq!(actual, expected); | |
| } | |
| fn test_net_fetch_success() { | |
| let fixture = ToolOperation::NetFetch { | |
| input: forge_domain::NetFetch { | |
| url: "https://example.com".to_string(), | |
| raw: Some(false), | |
| }, | |
| output: HttpResponse { | |
| content: "# Example Website\n\nThis is content.".to_string(), | |
| code: 200, | |
| context: ResponseContext::Parsed, | |
| content_type: "text/html".to_string(), | |
| }, | |
| }; | |
| let env = fixture_environment(); | |
| let actual = fixture.to_content(&env); | |
| let expected = None; | |
| assert_eq!(actual, expected); | |
| } | |
| fn test_net_fetch_error() { | |
| let fixture = ToolOperation::NetFetch { | |
| input: forge_domain::NetFetch { | |
| url: "https://example.com/notfound".to_string(), | |
| raw: Some(true), | |
| }, | |
| output: HttpResponse { | |
| content: "Not Found".to_string(), | |
| code: 404, | |
| context: ResponseContext::Raw, | |
| content_type: "text/plain".to_string(), | |
| }, | |
| }; | |
| let env = fixture_environment(); | |
| let actual = fixture.to_content(&env); | |
| let expected = None; | |
| assert_eq!(actual, expected); | |
| } | |
| fn test_shell_success() { | |
| let fixture = ToolOperation::Shell { | |
| output: ShellOutput { | |
| output: forge_domain::CommandOutput { | |
| command: "ls -la".to_string(), | |
| stdout: "file1.txt\nfile2.txt".to_string(), | |
| stderr: "".to_string(), | |
| exit_code: Some(0), | |
| }, | |
| shell: "/bin/bash".to_string(), | |
| description: None, | |
| }, | |
| }; | |
| let env = fixture_environment(); | |
| let actual = fixture.to_content(&env); | |
| let expected = None; | |
| assert_eq!(actual, expected); | |
| } | |
| fn test_shell_success_with_stderr() { | |
| let fixture = ToolOperation::Shell { | |
| output: ShellOutput { | |
| output: forge_domain::CommandOutput { | |
| command: "command_with_warnings".to_string(), | |
| stdout: "output line".to_string(), | |
| stderr: "warning line".to_string(), | |
| exit_code: Some(0), | |
| }, | |
| shell: "/bin/bash".to_string(), | |
| description: None, | |
| }, | |
| }; | |
| let env = fixture_environment(); | |
| let actual = fixture.to_content(&env); | |
| let expected = None; | |
| assert_eq!(actual, expected); | |
| } | |
| fn test_shell_failure() { | |
| let fixture = ToolOperation::Shell { | |
| output: ShellOutput { | |
| output: forge_domain::CommandOutput { | |
| command: "failing_command".to_string(), | |
| stdout: "".to_string(), | |
| stderr: "Error: command not found".to_string(), | |
| exit_code: Some(127), | |
| }, | |
| shell: "/bin/bash".to_string(), | |
| description: None, | |
| }, | |
| }; | |
| let env = fixture_environment(); | |
| let actual = fixture.to_content(&env); | |
| let expected = None; | |
| assert_eq!(actual, expected); | |
| } | |
| fn test_follow_up_with_response() { | |
| let fixture = ToolOperation::FollowUp { | |
| output: Some("Yes, continue with the operation".to_string()), | |
| }; | |
| let env = fixture_environment(); | |
| let actual = fixture.to_content(&env); | |
| let expected = None; | |
| assert_eq!(actual, expected); | |
| } | |
| fn test_follow_up_no_response() { | |
| let fixture = ToolOperation::FollowUp { output: None }; | |
| let env = fixture_environment(); | |
| let actual = fixture.to_content(&env); | |
| let expected = None; | |
| assert_eq!(actual, expected); | |
| } | |
| fn test_plan_create() { | |
| let fixture = ToolOperation::PlanCreate { | |
| input: forge_domain::PlanCreate { | |
| plan_name: "test-plan".to_string(), | |
| version: "v1".to_string(), | |
| content: | |
| "# Test Plan\n\n## Task 1\n- Do something\n\n## Task 2\n- Do something else" | |
| .to_string(), | |
| }, | |
| output: crate::PlanCreateOutput { | |
| path: PathBuf::from("plans/2024-08-11-test-plan-v1.md"), | |
| before: None, | |
| }, | |
| }; | |
| let env = fixture_environment(); | |
| let actual = fixture.to_content(&env); | |
| if let Some(ChatResponseContent::ToolInput(title)) = actual { | |
| assert_eq!(title.title, "Create plans/2024-08-11-test-plan-v1.md"); | |
| assert_eq!(title.category, forge_domain::Category::Debug); | |
| assert_eq!(title.sub_title, None); | |
| } else { | |
| panic!("Expected Title content"); | |
| } | |
| } | |
| } | |