@@ -1248,19 +1248,8 @@ impl ChatSession {
1248
1248
let input = user_input. trim ( ) ;
1249
1249
1250
1250
// 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) ;
1264
1253
}
1265
1254
if let Some ( mut args) = input. strip_prefix ( "/" ) . and_then ( shlex:: split) {
1266
1255
// Required for printing errors correctly.
@@ -1648,15 +1637,11 @@ impl ChatSession {
1648
1637
tool_name_being_recvd = Some ( name) ;
1649
1638
} ,
1650
1639
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.
1652
1643
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 ( "`>` " ) ;
1660
1645
response_prefix_printed = true ;
1661
1646
}
1662
1647
buf. push_str ( & text) ;
@@ -2241,6 +2226,25 @@ where
2241
2226
result
2242
2227
}
2243
2228
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
+
2244
2248
#[ cfg( test) ]
2245
2249
mod tests {
2246
2250
use super :: * ;
@@ -2653,4 +2657,21 @@ mod tests {
2653
2657
. await
2654
2658
. unwrap ( ) ;
2655
2659
}
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
+ }
2656
2677
}
0 commit comments