@@ -4,6 +4,8 @@ local TASK = require 'quick-c.task'
44local B = {}
55local NAME_CACHE = {}
66local LAST_EXE = {}
7+ local LAST_COMPILE_ARGS = {}
8+
79local function cleanup_build_logs (base , max_keep )
810 local uv = vim .loop
911 local ok , req = pcall (uv .fs_scandir , base )
@@ -312,6 +314,7 @@ local function build_cmd(config, is_win, ft, sources, out)
312314 if not family then
313315 return nil
314316 end
317+
315318 if family == ' cl' then
316319 local args = { ' cl' , ' /Zi' , ' /Od' }
317320 for _ , s in ipairs (sources ) do
@@ -388,6 +391,176 @@ function B.get_output_name_async(config, sources, preset_name, cb, default_overr
388391 end
389392end
390393
394+ -- Expand a template list with placeholders into argv list
395+ -- tmpl: array, elements may contain placeholders {sources} {out} {cc} {ft}
396+ local function expand_template_argv (tmpl , vars )
397+ local out = {}
398+ for _ , part in ipairs (tmpl or {}) do
399+ if part == ' {sources}' then
400+ for _ , s in ipairs (vars .sources or {}) do table.insert (out , s ) end
401+ elseif part == ' {out}' then
402+ table.insert (out , vars .out )
403+ elseif part == ' {cc}' then
404+ table.insert (out , vars .cc )
405+ elseif part == ' {ft}' then
406+ table.insert (out , vars .ft )
407+ else
408+ local replaced = part
409+ replaced = replaced :gsub (' %%{sources%%}' , ' {sources}' )
410+ replaced = replaced :gsub (' %%{out%%}' , ' {out}' )
411+ replaced = replaced :gsub (' %%{cc%%}' , ' {cc}' )
412+ replaced = replaced :gsub (' %%{ft%%}' , ' {ft}' )
413+ replaced = replaced :gsub (' {out}' , vars .out )
414+ replaced = replaced :gsub (' {cc}' , vars .cc )
415+ replaced = replaced :gsub (' {ft}' , vars .ft )
416+ if replaced ~= ' {sources}' then
417+ table.insert (out , replaced )
418+ else
419+ for _ , s in ipairs (vars .sources or {}) do table.insert (out , s ) end
420+ end
421+ end
422+ end
423+ return out
424+ end
425+
426+ local function clone_list (t )
427+ local o = {}
428+ for _ , v in ipairs (t or {}) do table.insert (o , v ) end
429+ return o
430+ end
431+
432+ local function project_key ()
433+ local root = vim .fn .getcwd ()
434+ return require (' quick-c.util' ).norm (root )
435+ end
436+
437+ -- Let user optionally customize compile command via Telescope/ui
438+ -- cb(argv_or_nil): when nil, use built-in cmd
439+ local function choose_user_compile_cmd_async (config , is_win , ft , sources , exe , builtin_cmd , cb )
440+ local cc_name = (choose_compiler (config , is_win , ft ))
441+ local cc = cc_name
442+ local ucfg = (config .compile and config .compile .user_cmd ) or {}
443+ if not ucfg .enabled then
444+ cb (nil )
445+ return
446+ end
447+ local tel = (ucfg .telescope or {})
448+ if tel .popup ~= true then
449+ cb (nil )
450+ return
451+ end
452+ local presets = ucfg .presets or {}
453+ local entries = {}
454+ table.insert (entries , { display = ' [Use built-in]' , kind = ' builtin' })
455+ table.insert (entries , { display = ' [Custom args...]' , kind = ' args' })
456+ for idx , p in ipairs (presets ) do
457+ local disp
458+ if type (p ) == ' table' then
459+ disp = table.concat (p , ' ' )
460+ else
461+ disp = tostring (p )
462+ end
463+ table.insert (entries , { display = disp , kind = ' preset' , value = p , idx = idx })
464+ end
465+ local function finalize (choice )
466+ if not choice then
467+ cb (nil )
468+ return
469+ end
470+ if choice .kind == ' builtin' then
471+ cb (clone_list (builtin_cmd ))
472+ return
473+ end
474+ if choice .kind == ' preset' then
475+ local tmpl = choice .value
476+ if type (tmpl ) ~= ' table' then
477+ -- string template unsupported for robust argv; fall back to builtin
478+ cb (clone_list (builtin_cmd ))
479+ return
480+ end
481+ local argv = expand_template_argv (tmpl , { sources = sources , out = exe , cc = cc or ' ' , ft = ft })
482+ cb (argv )
483+ return
484+ end
485+ if choice .kind == ' args' then
486+ local key = project_key ()
487+ local def_cfg = ucfg .default
488+ local def_from_cfg = ' '
489+ if type (def_cfg ) == ' table' then
490+ def_from_cfg = table.concat (def_cfg , ' ' )
491+ elseif type (def_cfg ) == ' string' then
492+ def_from_cfg = def_cfg
493+ end
494+ local def = ' '
495+ if ucfg .remember_last ~= false then
496+ def = (LAST_COMPILE_ARGS [key ] and LAST_COMPILE_ARGS [key ] ~= ' ' and LAST_COMPILE_ARGS [key ]) or def_from_cfg or ' '
497+ else
498+ def = def_from_cfg or ' '
499+ end
500+ local ui = vim .ui or {}
501+ if not ui .input then
502+ cb (clone_list (builtin_cmd ))
503+ return
504+ end
505+ ui .input ({ prompt = ' extra compile args: ' , default = def }, function (arg )
506+ if ucfg .remember_last ~= false then LAST_COMPILE_ARGS [key ] = arg or ' ' end
507+ if not arg or arg == ' ' then
508+ cb (clone_list (builtin_cmd ))
509+ return
510+ end
511+ local argv = clone_list (builtin_cmd )
512+ for a in string.gmatch (arg , " [^%s]+" ) do table.insert (argv , a ) end
513+ cb (argv )
514+ end )
515+ return
516+ end
517+ cb (nil )
518+ end
519+ local ok_t = pcall (require , ' telescope' )
520+ if ok_t then
521+ local pickers = require ' telescope.pickers'
522+ local finders = require ' telescope.finders'
523+ local conf = require (' telescope.config' ).values
524+ pickers
525+ .new ({}, {
526+ prompt_title = tel .prompt_title or ' Quick-c Compile' ,
527+ finder = finders .new_table {
528+ results = entries ,
529+ entry_maker = function (e )
530+ return { value = e , display = e .display , ordinal = e .display , kind = e .kind }
531+ end ,
532+ },
533+ sorter = conf .generic_sorter {},
534+ attach_mappings = function (bufnr , map )
535+ local actions = require ' telescope.actions'
536+ local action_state = require ' telescope.actions.state'
537+ local function choose (pbuf )
538+ local entry = action_state .get_selected_entry ()
539+ actions .close (pbuf )
540+ finalize (entry and entry .value or nil )
541+ end
542+ map (' i' , ' <CR>' , choose )
543+ map (' n' , ' <CR>' , choose )
544+ return true
545+ end ,
546+ })
547+ :find ()
548+ return
549+ end
550+ local ui = vim .ui or {}
551+ if ui .select then
552+ local items = {}
553+ for _ , e in ipairs (entries ) do table.insert (items , e .display ) end
554+ ui .select (items , { prompt = tel .prompt_title or ' Quick-c Compile' }, function (sel )
555+ if not sel then finalize (nil ) return end
556+ for _ , e in ipairs (entries ) do if e .display == sel then finalize (e ) return end end
557+ finalize (nil )
558+ end )
559+ return
560+ end
561+ cb (nil )
562+ end
563+
391564function B .build (config , notify , opts )
392565 opts = opts or {}
393566 local timeout_ms = (config .build and config .build .timeout_ms ) or 0
@@ -422,16 +595,18 @@ function B.build(config, notify, opts)
422595 end
423596 local is_win = U .is_windows ()
424597 local exe = resolve_out_path (config , sources , name )
425- local cmd = build_cmd (config , is_win , ft , sources , exe )
426- if not cmd then
598+ local builtin_cmd = build_cmd (config , is_win , ft , sources , exe )
599+ if not builtin_cmd then
427600 notify .err ' No available compiler found. Check PATH or set compile.prefer in setup()'
428601 if opts .on_exit then pcall (opts .on_exit , 1 , nil ) end
429602 done (1 )
430603 return
431604 end
432- local cmdline = table.concat (cmd , ' ' )
433- local all_stdout , all_stderr = {}, {}
434- job_id = vim .fn .jobstart (cmd , {
605+ choose_user_compile_cmd_async (config , is_win , ft , sources , exe , builtin_cmd , function (user_argv )
606+ local cmd = user_argv or builtin_cmd
607+ local cmdline = table.concat (cmd , ' ' )
608+ local all_stdout , all_stderr = {}, {}
609+ job_id = vim .fn .jobstart (cmd , {
435610 stdout_buffered = true ,
436611 stderr_buffered = true ,
437612 detach = false ,
@@ -480,10 +655,28 @@ function B.build(config, notify, opts)
480655 end
481656 if should_open () then
482657 if diagcfg .use_telescope then
483- local ok_tb , tb = pcall (require , ' telescope.builtin' )
484- if ok_tb then tb .quickfix () else vim .cmd ' copen' end
658+ local ok_qc , qct = pcall (require , ' quick-c.telescope' )
659+ if ok_qc and qct and qct .telescope_quickfix then
660+ pcall (qct .telescope_quickfix , config )
661+ else
662+ local ok_tb , tb = pcall (require , ' telescope.builtin' )
663+ if ok_tb and tb and tb .quickfix then
664+ pcall (tb .quickfix )
665+ else
666+ pcall (vim .cmd , ' copen' )
667+ end
668+ end
485669 else
486- vim .cmd ' copen'
670+ pcall (vim .cmd , ' copen' )
671+ end
672+ if not (pcall (require , ' telescope' )) then
673+ local info = vim .fn .getqflist ({ winid = 1 }) or {}
674+ local wid = info .winid or 0
675+ if wid ~= 0 then
676+ pcall (vim .api .nvim_win_set_option , wid , ' wrap' , true )
677+ pcall (vim .api .nvim_win_set_option , wid , ' linebreak' , true )
678+ pcall (vim .api .nvim_win_set_option , wid , ' breakindent' , true )
679+ end
487680 end
488681 end
489682 if should_jump () then
@@ -519,10 +712,11 @@ function B.build(config, notify, opts)
519712 done (code )
520713 end ,
521714 })
522- if (job_id or 0 ) <= 0 then
523- notify .err ' Failed to start build process'
524- done (1 )
525- end
715+ if (job_id or 0 ) <= 0 then
716+ notify .err ' Failed to start build process'
717+ done (1 )
718+ end
719+ end )
526720 end , default_override )
527721 end ,
528722 }
0 commit comments