@@ -3656,6 +3656,119 @@ fn has_previous_statusline() -> bool {
36563656 get_lovstudio_dir ( ) . join ( "statusline" ) . join ( "_previous.sh" ) . exists ( )
36573657}
36583658
3659+ /// Context passed to Lovcode statusbar script
3660+ #[ derive( Debug , Serialize , Deserialize ) ]
3661+ pub struct StatusBarContext {
3662+ pub app_name : String ,
3663+ pub version : String ,
3664+ pub projects_count : usize ,
3665+ pub features_count : usize ,
3666+ pub today_lines_added : usize ,
3667+ pub today_lines_deleted : usize ,
3668+ pub timestamp : String ,
3669+ pub home_dir : String ,
3670+ }
3671+
3672+ /// Execute Lovcode's GUI statusbar script and return output
3673+ #[ tauri:: command]
3674+ fn execute_statusbar_script ( script_path : String , context : StatusBarContext ) -> Result < String , String > {
3675+ use std:: io:: Write ;
3676+ use std:: process:: { Command , Stdio } ;
3677+
3678+ // Expand ~ to home dir
3679+ let home = dirs:: home_dir ( ) . unwrap_or_default ( ) ;
3680+ let expanded_path = if script_path. starts_with ( "~" ) {
3681+ script_path. replacen ( "~" , & home. to_string_lossy ( ) , 1 )
3682+ } else {
3683+ script_path
3684+ } ;
3685+
3686+ let path = std:: path:: Path :: new ( & expanded_path) ;
3687+ if !path. exists ( ) {
3688+ return Err ( format ! ( "Script not found: {}" , expanded_path) ) ;
3689+ }
3690+
3691+ // Serialize context to JSON
3692+ let context_json = serde_json:: to_string ( & context) . map_err ( |e| e. to_string ( ) ) ?;
3693+
3694+ // Determine how to execute the script
3695+ #[ cfg( unix) ]
3696+ let mut child = Command :: new ( & expanded_path)
3697+ . stdin ( Stdio :: piped ( ) )
3698+ . stdout ( Stdio :: piped ( ) )
3699+ . stderr ( Stdio :: piped ( ) )
3700+ . spawn ( )
3701+ . map_err ( |e| format ! ( "Failed to spawn script: {}" , e) ) ?;
3702+
3703+ #[ cfg( windows) ]
3704+ let mut child = Command :: new ( "powershell" )
3705+ . args ( [ "-ExecutionPolicy" , "Bypass" , "-File" , & expanded_path] )
3706+ . stdin ( Stdio :: piped ( ) )
3707+ . stdout ( Stdio :: piped ( ) )
3708+ . stderr ( Stdio :: piped ( ) )
3709+ . spawn ( )
3710+ . map_err ( |e| format ! ( "Failed to spawn script: {}" , e) ) ?;
3711+
3712+ // Write context JSON to stdin
3713+ if let Some ( mut stdin) = child. stdin . take ( ) {
3714+ stdin. write_all ( context_json. as_bytes ( ) ) . ok ( ) ;
3715+ }
3716+
3717+ // Wait for output with timeout
3718+ let output = child
3719+ . wait_with_output ( )
3720+ . map_err ( |e| format ! ( "Script execution failed: {}" , e) ) ?;
3721+
3722+ // Get first line of stdout
3723+ let stdout = String :: from_utf8_lossy ( & output. stdout ) ;
3724+ let first_line = stdout. lines ( ) . next ( ) . unwrap_or ( "" ) . to_string ( ) ;
3725+
3726+ Ok ( first_line)
3727+ }
3728+
3729+ /// Get Lovcode statusbar settings from workspace.json
3730+ #[ tauri:: command]
3731+ fn get_statusbar_settings ( ) -> Result < Option < serde_json:: Value > , String > {
3732+ let settings_path = get_lovstudio_dir ( ) . join ( "statusbar-settings.json" ) ;
3733+ if !settings_path. exists ( ) {
3734+ return Ok ( None ) ;
3735+ }
3736+ let content = fs:: read_to_string ( & settings_path) . map_err ( |e| e. to_string ( ) ) ?;
3737+ let settings: serde_json:: Value = serde_json:: from_str ( & content) . map_err ( |e| e. to_string ( ) ) ?;
3738+ Ok ( Some ( settings) )
3739+ }
3740+
3741+ /// Save Lovcode statusbar settings
3742+ #[ tauri:: command]
3743+ fn save_statusbar_settings ( settings : serde_json:: Value ) -> Result < ( ) , String > {
3744+ let settings_path = get_lovstudio_dir ( ) . join ( "statusbar-settings.json" ) ;
3745+ let content = serde_json:: to_string_pretty ( & settings) . map_err ( |e| e. to_string ( ) ) ?;
3746+ fs:: write ( & settings_path, content) . map_err ( |e| e. to_string ( ) )
3747+ }
3748+
3749+ /// Write Lovcode statusbar script to ~/.lovstudio/lovcode/statusbar/
3750+ #[ tauri:: command]
3751+ fn write_lovcode_statusbar_script ( name : String , content : String ) -> Result < String , String > {
3752+ let statusbar_dir = get_lovstudio_dir ( ) . join ( "statusbar" ) ;
3753+ fs:: create_dir_all ( & statusbar_dir) . map_err ( |e| e. to_string ( ) ) ?;
3754+
3755+ let script_path = statusbar_dir. join ( format ! ( "{}.sh" , name) ) ;
3756+ fs:: write ( & script_path, & content) . map_err ( |e| e. to_string ( ) ) ?;
3757+
3758+ // Make executable on Unix
3759+ #[ cfg( unix) ]
3760+ {
3761+ use std:: os:: unix:: fs:: PermissionsExt ;
3762+ let mut perms = fs:: metadata ( & script_path)
3763+ . map_err ( |e| e. to_string ( ) ) ?
3764+ . permissions ( ) ;
3765+ perms. set_mode ( 0o755 ) ;
3766+ fs:: set_permissions ( & script_path, perms) . map_err ( |e| e. to_string ( ) ) ?;
3767+ }
3768+
3769+ Ok ( script_path. to_string_lossy ( ) . to_string ( ) )
3770+ }
3771+
36593772/// Remove installed statusline template
36603773#[ tauri:: command]
36613774fn remove_statusline_template ( name : String ) -> Result < ( ) , String > {
@@ -7184,6 +7297,10 @@ pub fn run() {
71847297 apply_statusline,
71857298 restore_previous_statusline,
71867299 has_previous_statusline,
7300+ execute_statusbar_script,
7301+ get_statusbar_settings,
7302+ save_statusbar_settings,
7303+ write_lovcode_statusbar_script,
71877304 remove_statusline_template,
71887305 open_in_editor,
71897306 open_file_at_line,
0 commit comments