@@ -7,8 +7,11 @@ local _terminal = {
77 id = nil , -- id for the unified terminal
88 id_old = nil , -- Old id to keep track of the buffer
99}
10- -- this coroutine will be used to check when command exits and runs on_exit function
11- local on_exit_coroutine
10+
11+ local last_run_config = {
12+ build_dir = nil ,
13+ launch_cmd = nil ,
14+ }
1215
1316function _terminal .has_active_job (opts )
1417 if _terminal .id then
@@ -479,40 +482,6 @@ function _terminal.get_buffers_with_prefix(prefix)
479482 return filtered_buffers
480483end
481484
482- function _terminal .prepare_cmd_for_run (cmd , env , args , cwd )
483- local full_cmd = " "
484-
485- -- Launch form executable's build directory by default
486- full_cmd = " cd " .. utils .transform_path (cwd ) .. " &&"
487-
488- if osys .iswin32 then
489- for k , v in pairs (env ) do
490- full_cmd = full_cmd .. " set " .. k .. " =" .. v .. " &&"
491- end
492- else
493- for k , v in pairs (env ) do
494- full_cmd = full_cmd .. " " .. k .. " =" .. v .. " "
495- end
496- end
497-
498- full_cmd = full_cmd .. " " .. utils .transform_path (cmd )
499-
500- if osys .islinux or osys .iswsl or osys .ismac then
501- full_cmd = " " .. full_cmd -- adding a space in front of the command prevents bash from recording the command in the history (if configured)
502- end
503-
504- -- Add args to the cmd
505- for _ , arg in ipairs (args ) do
506- full_cmd = full_cmd .. " " .. arg
507- end
508-
509- if osys .iswin32 then -- wrap in sub process to prevent env vars from being persited
510- full_cmd = ' cmd /C "' .. full_cmd .. ' "'
511- end
512-
513- return full_cmd
514- end
515-
516485local get_tmp_dir = function ()
517486 return vim .fn .stdpath (" data" ) .. " /cmake-tools-tmp"
518487end
@@ -600,53 +569,143 @@ end
600569--- @param on_exit function | nil function to be called on exit the terminal will pass commands exit code as an argument
601570--- @param on_output any !unused here added for the sake of unification
602571function _terminal .run (cmd , env_script , env , args , cwd , opts , on_exit , on_output )
603- local full_cmd = _terminal .prepare_cmd_for_run (cmd , env , args , cwd )
572+ local function prepare_run (cmd , env , args , cwd )
573+ -- Escape all special pattern characters
574+ local escapedCwd = cwd :gsub (" ([%^%$%(%)%%%.%[%]%*%+%-%?])" , " %%%1" )
575+ cmd = cmd :gsub (escapedCwd , osys .iswin32 and " .\\ " or " ./" )
576+ cwd = utils .transform_path (cwd )
577+ local envTbl = {}
578+ local fmtStr = osys .iswin32 and " set %s=%s" or " %s=%s"
579+ for k , v in pairs (env ) do
580+ table.insert (envTbl , string.format (fmtStr , k , v ))
581+ end
582+ env = table.concat (envTbl , " " )
583+ args = table.concat (args , " " )
584+
585+ return cmd , env , args , cwd
586+ end
604587
605- local prefix = opts .prefix_name -- [CMakeTools]
606- create_lock_file ()
607588 -- prefix is added to the terminal name because the reposition_term() function needs to find it
608589 local terminal_already_exists , buffer_idx = _terminal .create_if_not_exists (
609- prefix .. opts .name , -- [CMakeTools]Executor Terminal/Runner Terminal
590+ opts . prefix_name .. opts .name , -- [CMakeTools]Executor Terminal/Runner Terminal
610591 opts
611592 )
612593 _terminal .id = buffer_idx
613594
614595 -- Reposition the terminal buffer, before sending commands
615596 local final_win_id = _terminal .reposition (opts )
616597
617- --- NOTE: env_script needs to be run only once if the terminal buffer does not already exist
618- --- We compare the old and the new id and only if they are not the same, plus if the terminal exists,
619- -- only then, we do not reinitialize the environment, else we reinit the env
620- if not terminal_already_exists or _terminal .id_old ~= _terminal .id then
621- _terminal .id_old = _terminal .id
622- _terminal .send_data_to_terminal (buffer_idx , env_script , {
623- win_id = final_win_id ,
624- prefix = opts .prefix_name ,
625- split_direction = opts .split_direction ,
626- split_size = opts .split_size ,
627- start_insert = opts .start_insert ,
628- focus = opts .focus ,
629- })
598+ local exit_handler = (osys .iswin32 and " & " or " ; " ) .. get_command_handling_on_exit ()
599+ local final_cmd , final_env , final_args , build_dir = prepare_run (cmd , env , args , cwd )
600+ local full_cmd
601+ local call_update
602+
603+ local termOpts = {
604+ win_id = final_win_id ,
605+ prefix = opts .prefix_name ,
606+ split_direction = opts .split_direction ,
607+ split_size = opts .split_size ,
608+ start_insert = opts .start_insert ,
609+ auto_resize = opts .auto_resize ,
610+ focus = opts .focus ,
611+ }
612+
613+ if not opts .use_shell_alias then
614+ full_cmd = (osys .iswin32 and ' cmd /C "' or " " )
615+ .. " cd "
616+ .. build_dir
617+ .. " && "
618+ .. (final_env .. (final_env ~= " " and " " or " " ))
619+ .. final_cmd
620+ .. ((final_args ~= " " and " " or " " ) .. final_args )
621+ .. (osys .iswin32 and ' "' or " " )
622+ .. exit_handler
623+ else
624+ if osys .iswin32 then
625+ error (" using a shell alias is currently not suported for windows" )
626+ end
627+
628+ local alias_name = " cmake_run_target"
629+ local update_function = " cmake_update_target"
630+
631+ full_cmd = (final_env ~= " " and (final_env .. " " ) or " " ) .. alias_name .. " " .. final_args
632+ if not is_fish_shell and osys .islinux or osys .iswsl or osys .ismac then
633+ -- adding a space in front of the command prevents bash from recording the command in the history (if configured)
634+ full_cmd = " " .. full_cmd
635+ end
636+
637+ call_update = string.format (" %s '%s' '%s'" , update_function , build_dir , final_cmd )
638+
639+ --- NOTE: env_script needs to be run only once if the terminal buffer does not already exist
640+ --- We compare the old and the new id and only if they are not the same, plus if the terminal exists,
641+ -- only then, we do not reinitialize the environment, else we reinit the env
642+ if not terminal_already_exists or _terminal .id_old ~= _terminal .id then
643+ local env_var_build = " CMAKE_TOOLS_BUILD_DIR"
644+ local env_var_target = " CMAKE_TOOLS_LAUNCH_TARGET"
645+
646+ local userEnvScript = env_script
647+ local fmt = {}
648+
649+ if is_fish_shell () then
650+ fmt .update_func = " function %s; set -g %s $argv[1]; set -g %s $argv[2]; end; "
651+ fmt .run_func = " function %s; cd $%s && eval '$%s $argv' %s; end; "
652+ else
653+ fmt .update_func = " %s() { export %s=$1; export %s=$2; }; "
654+ fmt .run_func = " %s() { cd $%s && eval '$%s $*' %s; }; "
655+ end
656+
657+ -- Depending how the user defined env_script ends, we have to strip a trailing
658+ -- semicolon and replace it by a && to only clear the console if the user defined
659+ -- env_script ran successfully
660+ if userEnvScript and userEnvScript :match (" ^%s*$" ) == nil then
661+ if userEnvScript :match (" ;%s*$" ) then
662+ userEnvScript = userEnvScript :match (" ^(.-);%s*$" ) .. " &&"
663+ elseif not userEnvScript :match (" &&%s*$" ) then
664+ userEnvScript = userEnvScript .. " &&"
665+ end
666+ end
667+
668+ env_script = string.format (fmt .update_func , update_function , env_var_build , env_var_target )
669+ .. call_update
670+ .. " && "
671+ .. string.format (fmt .run_func , alias_name , env_var_build , env_var_target , exit_handler )
672+ .. userEnvScript
673+ .. " clear"
674+
675+ if not is_fish_shell and osys .islinux or osys .iswsl or osys .ismac then
676+ -- adding a space in front of the command prevents bash from recording the command in the history (if configured)
677+ env_script = " " .. env_script
678+ end
679+
680+ _terminal .id_old = _terminal .id
681+ _terminal .send_data_to_terminal (buffer_idx , env_script , termOpts )
682+ end
683+ end
684+
685+ if
686+ opts .use_shell_alias
687+ and (last_run_config .build_dir ~= build_dir or last_run_config .launch_cmd ~= final_cmd )
688+ then
689+ if last_run_config .build_dir then
690+ _terminal .send_data_to_terminal (buffer_idx , call_update , termOpts )
691+ end
692+
693+ last_run_config .build_dir = build_dir
694+ last_run_config .launch_cmd = final_cmd
630695 end
631696
697+ termOpts .do_not_add_newline = opts .do_not_add_newline
698+
699+ create_lock_file ()
700+
632701 -- Send final cmd to terminal
633- local chain_symb = osys .iswin32 and " & " or " ; "
634- _terminal .send_data_to_terminal (
635- buffer_idx ,
636- full_cmd .. chain_symb .. get_command_handling_on_exit (),
637- {
638- win_id = final_win_id ,
639- prefix = opts .prefix_name ,
640- split_direction = opts .split_direction ,
641- split_size = opts .split_size ,
642- start_insert = opts .start_insert ,
643- focus = opts .focus ,
644- auto_resize = opts .auto_resize ,
645- do_not_add_newline = opts .do_not_add_newline ,
646- }
647- )
702+ _terminal .send_data_to_terminal (buffer_idx , full_cmd , termOpts )
703+
704+ -- this coroutine will be used to check when command exits and runs on_exit function
705+ local on_exit_coroutine
648706 on_exit_coroutine = coroutine.create (function ()
649- while utils .file_exists (get_lock_file_path ()) do
707+ local lock_fie_path = get_lock_file_path ()
708+ while utils .file_exists (lock_fie_path ) do
650709 vim .defer_fn (function ()
651710 coroutine.resume (on_exit_coroutine )
652711 end , 25 )
@@ -658,20 +717,6 @@ function _terminal.run(cmd, env_script, env, args, cwd, opts, on_exit, on_output
658717 coroutine.resume (on_exit_coroutine )
659718end
660719
661- function _terminal .prepare_launch_path (path )
662- if osys .iswin32 then
663- path = ' "' .. path .. ' "' -- The path is kept in double quotes ... Windows Duh!
664- elseif osys .islinux then
665- path = path
666- elseif osys .iswsl then
667- path = path
668- elseif osys .ismac then
669- path = path
670- end
671-
672- return path
673- end
674-
675720function _terminal .close (opts )
676721 if not _terminal .id then
677722 log .info (" There is no terminal instance" )
0 commit comments