@@ -1248,19 +1248,8 @@ impl ChatSession {
12481248 let input = user_input. trim ( ) ;
12491249
12501250 // handle image path
1251- if input. starts_with ( '/' ) {
1252- if let Some ( after_slash) = input. strip_prefix ( '/' ) {
1253- let looks_like_path = after_slash. contains ( MAIN_SEPARATOR )
1254- || after_slash. contains ( '/' )
1255- || after_slash. contains ( '\\' )
1256- || after_slash. contains ( '.' ) ;
1257-
1258- if looks_like_path {
1259- return Ok ( ChatState :: HandleInput {
1260- input : after_slash. to_string ( ) ,
1261- } ) ;
1262- }
1263- }
1251+ if let Some ( chat_state) = does_input_reference_file ( input) {
1252+ return Ok ( chat_state) ;
12641253 }
12651254 if let Some ( mut args) = input. strip_prefix ( "/" ) . and_then ( shlex:: split) {
12661255 // Required for printing errors correctly.
@@ -1648,15 +1637,11 @@ impl ChatSession {
16481637 tool_name_being_recvd = Some ( name) ;
16491638 } ,
16501639 parser:: ResponseEvent :: AssistantText ( text) => {
1651- // Add Q response prefix before the first assistant text
1640+ // Add Q response prefix before the first assistant text.
1641+ // This must be markdown - using a code tick, which is printed
1642+ // as green.
16521643 if !response_prefix_printed && !text. trim ( ) . is_empty ( ) {
1653- // Print the Q response prefix with cyan color
1654- execute ! (
1655- self . stdout,
1656- style:: SetForegroundColor ( Color :: Cyan ) ,
1657- style:: Print ( "> " ) ,
1658- style:: SetForegroundColor ( Color :: Reset )
1659- ) ?;
1644+ buf. push_str ( "`>` " ) ;
16601645 response_prefix_printed = true ;
16611646 }
16621647 buf. push_str ( & text) ;
@@ -2241,6 +2226,25 @@ where
22412226 result
22422227}
22432228
2229+ /// Checks if an input may be referencing a file and should not be handled as a typical slash
2230+ /// command. If true, then return [Option::Some<ChatState>], otherwise [Option::None].
2231+ fn does_input_reference_file ( input : & str ) -> Option < ChatState > {
2232+ let after_slash = input. strip_prefix ( "/" ) ?;
2233+
2234+ if let Some ( first) = shlex:: split ( after_slash) . unwrap_or_default ( ) . first ( ) {
2235+ let looks_like_path =
2236+ first. contains ( MAIN_SEPARATOR ) || first. contains ( '/' ) || first. contains ( '\\' ) || first. contains ( '.' ) ;
2237+
2238+ if looks_like_path {
2239+ return Some ( ChatState :: HandleInput {
2240+ input : after_slash. to_string ( ) ,
2241+ } ) ;
2242+ }
2243+ }
2244+
2245+ None
2246+ }
2247+
22442248#[ cfg( test) ]
22452249mod tests {
22462250 use super :: * ;
@@ -2653,4 +2657,21 @@ mod tests {
26532657 . await
26542658 . unwrap ( ) ;
26552659 }
2660+
2661+ #[ test]
2662+ fn test_does_input_reference_file ( ) {
2663+ let tests = & [
2664+ (
2665+ r"/Users/user/Desktop/Screenshot\ 2025-06-30\ at\ 2.13.34 PM.png read this image for me" ,
2666+ true ,
2667+ ) ,
2668+ ( "/path/to/file.json" , true ) ,
2669+ ( "/save output.json" , false ) ,
2670+ ( "~/does/not/start/with/slash" , false ) ,
2671+ ] ;
2672+ for ( input, expected) in tests {
2673+ let actual = does_input_reference_file ( input) . is_some ( ) ;
2674+ assert_eq ! ( actual, * expected, "expected {} for input {}" , expected, input) ;
2675+ }
2676+ }
26562677}
0 commit comments