@@ -25,7 +25,10 @@ use crate::ui::gpui::{
2525use crate :: ui:: { async_trait, DisplayFragment , StreamingState , UIError , UiEvent , UserInterface } ;
2626use assets:: Assets ;
2727use async_channel;
28- use gpui:: { actions, px, AppContext , AsyncApp , Entity , Global , Point } ;
28+ use gpui:: {
29+ actions, px, App , AppContext , AsyncApp , Entity , Global , KeyBinding , Menu , MenuItem , Point ,
30+ SharedString ,
31+ } ;
2932use gpui_component:: input:: InputState ;
3033use gpui_component:: Root ;
3134pub use memory:: MemoryView ;
@@ -38,7 +41,7 @@ use tracing::{debug, error, trace, warn};
3841
3942use elements:: MessageContainer ;
4043
41- actions ! ( code_assistant, [ CloseWindow ] ) ;
44+ actions ! ( code_assistant, [ Quit , CloseWindow ] ) ;
4245
4346// Global UI event sender for chat components
4447#[ derive( Clone ) ]
@@ -104,6 +107,38 @@ pub struct Gpui {
104107 chat_sidebar : Arc < Mutex < Option < Entity < chat_sidebar:: ChatSidebar > > > > ,
105108}
106109
110+ fn init ( cx : & mut App ) {
111+ cx. bind_keys ( [ KeyBinding :: new ( "cmd-q" , Quit , None ) ] ) ;
112+
113+ cx. on_action ( |_: & Quit , cx : & mut App | {
114+ cx. quit ( ) ;
115+ } ) ;
116+
117+ use gpui_component:: input:: { Copy , Cut , Paste , Redo , Undo } ;
118+ cx. set_menus ( vec ! [
119+ Menu {
120+ name: "GPUI App" . into( ) ,
121+ items: vec![ MenuItem :: action( "Quit" , Quit ) ] ,
122+ } ,
123+ Menu {
124+ name: "Edit" . into( ) ,
125+ items: vec![
126+ MenuItem :: os_action( "Undo" , Undo , gpui:: OsAction :: Undo ) ,
127+ MenuItem :: os_action( "Redo" , Redo , gpui:: OsAction :: Redo ) ,
128+ MenuItem :: separator( ) ,
129+ MenuItem :: os_action( "Cut" , Cut , gpui:: OsAction :: Cut ) ,
130+ MenuItem :: os_action( "Copy" , Copy , gpui:: OsAction :: Copy ) ,
131+ MenuItem :: os_action( "Paste" , Paste , gpui:: OsAction :: Paste ) ,
132+ ] ,
133+ } ,
134+ Menu {
135+ name: "Window" . into( ) ,
136+ items: vec![ ] ,
137+ } ,
138+ ] ) ;
139+ cx. activate ( true ) ;
140+ }
141+
107142// Implement Global trait for Gpui
108143impl Global for Gpui { }
109144
@@ -208,6 +243,8 @@ impl Gpui {
208243 // Apply our custom theme colors
209244 theme:: init_themes ( cx) ;
210245
246+ init ( cx) ;
247+
211248 // Spawn task to receive UiEvents
212249 let rx = gpui_clone. event_receiver . lock ( ) . unwrap ( ) . clone ( ) ;
213250 let async_gpui_clone = gpui_clone. clone ( ) ;
@@ -279,68 +316,70 @@ impl Gpui {
279316 let bounds =
280317 gpui:: Bounds :: centered ( None , gpui:: size ( gpui:: px ( 1400.0 ) , gpui:: px ( 700.0 ) ) , cx) ;
281318 // Open window with titlebar
282- let window_result = cx. open_window (
283- gpui:: WindowOptions {
284- window_bounds : Some ( gpui:: WindowBounds :: Windowed ( bounds) ) ,
285- titlebar : Some ( gpui:: TitlebarOptions {
286- title : Some ( gpui:: SharedString :: from ( "Code Assistant" ) ) ,
287- appears_transparent : true ,
288- traffic_light_position : Some ( Point {
289- x : px ( 16. ) ,
290- y : px ( 16. ) ,
319+ let window = cx
320+ . open_window (
321+ gpui:: WindowOptions {
322+ window_bounds : Some ( gpui:: WindowBounds :: Windowed ( bounds) ) ,
323+ titlebar : Some ( gpui:: TitlebarOptions {
324+ title : Some ( gpui:: SharedString :: from ( "Code Assistant" ) ) ,
325+ appears_transparent : true ,
326+ traffic_light_position : Some ( Point {
327+ x : px ( 16. ) ,
328+ y : px ( 16. ) ,
329+ } ) ,
291330 } ) ,
292- } ) ,
293- ..Default :: default ( )
294- } ,
295- |window, cx| {
296- // Create TextInput with multi-line support
297- let text_input = cx. new ( |cx| {
298- InputState :: new ( window, cx)
299- . multi_line ( )
300- . auto_grow ( 1 , 8 )
301- . placeholder ( "Type your message..." )
302- } ) ;
303-
304- // Create MessagesView
305- let messages_view = cx. new ( |cx| MessagesView :: new ( message_queue. clone ( ) , cx) ) ;
306-
307- // Create ChatSidebar and store it in Gpui
308- let chat_sidebar = cx. new ( |cx| chat_sidebar:: ChatSidebar :: new ( cx) ) ;
309- * gpui_clone. chat_sidebar . lock ( ) . unwrap ( ) = Some ( chat_sidebar. clone ( ) ) ;
310-
311- // Create RootView
312- let root_view = cx. new ( |cx| {
313- RootView :: new (
314- text_input,
315- memory_view. clone ( ) ,
316- messages_view,
317- chat_sidebar. clone ( ) ,
318- cx,
319- input_value. clone ( ) ,
320- input_requested. clone ( ) ,
321- gpui_clone. streaming_state . clone ( ) ,
322- )
323- } ) ;
324-
325- // Wrap in Root component
326- cx. new ( |cx| Root :: new ( root_view. into ( ) , window, cx) )
327- } ,
328- ) ;
331+ ..Default :: default ( )
332+ } ,
333+ |window, cx| {
334+ // Create TextInput with multi-line support
335+ let text_input = cx. new ( |cx| {
336+ InputState :: new ( window, cx)
337+ . multi_line ( )
338+ . auto_grow ( 1 , 8 )
339+ . placeholder ( "Type your message..." )
340+ } ) ;
341+
342+ // Create MessagesView
343+ let messages_view =
344+ cx. new ( |cx| MessagesView :: new ( message_queue. clone ( ) , cx) ) ;
345+
346+ // Create ChatSidebar and store it in Gpui
347+ let chat_sidebar = cx. new ( |cx| chat_sidebar:: ChatSidebar :: new ( cx) ) ;
348+ * gpui_clone. chat_sidebar . lock ( ) . unwrap ( ) = Some ( chat_sidebar. clone ( ) ) ;
349+
350+ // Create RootView
351+ let root_view = cx. new ( |cx| {
352+ RootView :: new (
353+ text_input,
354+ memory_view. clone ( ) ,
355+ messages_view,
356+ chat_sidebar. clone ( ) ,
357+ cx,
358+ input_value. clone ( ) ,
359+ input_requested. clone ( ) ,
360+ gpui_clone. streaming_state . clone ( ) ,
361+ )
362+ } ) ;
363+
364+ // Wrap in Root component
365+ cx. new ( |cx| Root :: new ( root_view. into ( ) , window, cx) )
366+ } ,
367+ )
368+ . expect ( "failed to open window" ) ;
329369
330370 // Focus the TextInput if window was created successfully
331- if let Ok ( window_handle) = window_result {
332- window_handle
333- . update ( cx, |_root, window, cx| {
334- // Get the MessageView from the Root
335- if let Some ( _view) =
336- window. root :: < gpui_component:: Root > ( ) . and_then ( |root| root)
337- {
338- // Activate window
339- cx. activate ( true ) ;
340- }
341- } )
342- . ok ( ) ;
343- }
371+ window
372+ . update ( cx, |_root, window, cx| {
373+ window. activate_window ( ) ;
374+ window. set_window_title ( & SharedString :: from ( "Code Assistant" ) ) ;
375+ // Get the MessageView from the Root
376+ if let Some ( _view) = window. root :: < gpui_component:: Root > ( ) . and_then ( |root| root)
377+ {
378+ // Activate window
379+ cx. activate ( true ) ;
380+ }
381+ } )
382+ . expect ( "failed to update window" ) ;
344383 } ) ;
345384 }
346385
@@ -771,9 +810,9 @@ impl Gpui {
771810
772811 // Handle backend responses
773812 fn handle_backend_response ( & self , response : BackendResponse , _cx : & mut AsyncApp ) {
774- debug ! ( "UI: Received chat management response: {:?}" , response) ;
775813 match response {
776814 BackendResponse :: SessionCreated { session_id } => {
815+ debug ! ( "Received BackendResponse::SessionCreated" ) ;
777816 * self . current_session_id . lock ( ) . unwrap ( ) = Some ( session_id. clone ( ) ) ;
778817 // Refresh the session list
779818 if let Some ( sender) = self . backend_event_sender . lock ( ) . unwrap ( ) . as_ref ( ) {
@@ -783,12 +822,14 @@ impl Gpui {
783822 }
784823 }
785824 BackendResponse :: SessionDeleted { session_id : _ } => {
825+ debug ! ( "Received BackendResponse::SessionDeleted" ) ;
786826 // Refresh the session list
787827 if let Some ( sender) = self . backend_event_sender . lock ( ) . unwrap ( ) . as_ref ( ) {
788828 let _ = sender. try_send ( BackendEvent :: ListSessions ) ;
789829 }
790830 }
791831 BackendResponse :: SessionsListed { sessions } => {
832+ debug ! ( "Received BackendResponse::SessionsListed" ) ;
792833 * self . chat_sessions . lock ( ) . unwrap ( ) = sessions. clone ( ) ;
793834 self . push_event ( UiEvent :: UpdateChatList { sessions } ) ;
794835 }
0 commit comments