@@ -21,7 +21,7 @@ vim.opt.packpath:prepend(vim.fs.joinpath(data_dir, 'site'))
2121vim .g .strim_loaded = 0
2222
2323local DEFAULT_SETTINGS = {
24- max_concurrent_tasks = if_nil (vim .g .strive_max_concurrent_tasks , 5 ),
24+ max_concurrent_tasks = if_nil (vim .g .strive_max_concurrent_tasks , 10 ),
2525 auto_install = if_nil (vim .g .strive_auto_install , true ),
2626 log_level = if_nil (vim .g .strive_log_level , ' warn' ),
2727 git_timeout = if_nil (vim .g .strive_git_timeout , 60000 ),
@@ -557,7 +557,7 @@ function Plugin.new(spec)
557557 -- Extract plugin name from repo
558558 local name = vim .fs .normalize (spec .name )
559559 if vim .startswith (name , vim .env .HOME ) then
560- spec .dev = true
560+ spec .is_local = true
561561 end
562562 local parts = vim .split (name , ' /' , { trimempty = true })
563563 local plugin_name = parts [# parts ]:gsub (' %.git$' , ' ' )
@@ -568,8 +568,9 @@ function Plugin.new(spec)
568568 name = name , -- Full repo name (user/repo)
569569 plugin_name = plugin_name , -- Just the repo part (for loading)
570570 is_remote = not name :find (vim .env .HOME ), -- Is it a remote or local plugin
571- is_dev = spec .dev or false , -- Development mode flag
571+ is_local = spec .is_local or false , -- Development mode flag
572572 is_lazy = false , -- Whether to lazy load
573+ load_path = nil , -- Loacal path to load
573574
574575 -- States
575576 status = STATUS .PENDING , -- Current plugin status
@@ -582,7 +583,7 @@ function Plugin.new(spec)
582583 keys = {}, -- Keys to trigger loading
583584
584585 -- Configuration
585- setup_opts = spec .setup or nil , -- Options for plugin setup()
586+ setup_opts = spec .setup or {} , -- Options for plugin setup()
586587 init_opts = spec .init , -- Options for before load plugin
587588 config_opts = spec .config , -- Config function to run after loading
588589 after_fn = spec .after , -- Function to run after dependencies load
@@ -600,11 +601,10 @@ end
600601
601602-- Get the plugin installation path
602603function Plugin :get_path ()
603- if not self .is_dev then
604+ if not self .is_local then
604605 return vim .fs .joinpath (self .is_lazy and OPT_DIR or START_DIR , self .plugin_name )
605606 end
606- return vim .g .strive_dev_path and vim .fs .joinpath (vim .g .strive_dev_path , self .plugin_name )
607- or self .name
607+ return vim .fs .joinpath (self .load_path , self .plugin_name ) or self .name
608608end
609609
610610-- Check if plugin is installed (async version)
629629function Plugin :packadd ()
630630 -- If it's a lazy-loaded plugin, add it
631631 if self .is_lazy then
632- if not self .is_dev then
632+ if not self .is_local then
633633 vim .cmd .packadd (self .plugin_name )
634634 else
635635 vim .opt .rtp :append (self :get_path ())
@@ -664,9 +664,7 @@ function Plugin:load()
664664
665665 self :packadd ()
666666
667- if self .setup_opts then
668- self :call_setup ()
669- end
667+ self :call_setup ()
670668
671669 load_opts (self .config_opts )
672670
@@ -745,23 +743,57 @@ function Plugin:cmd(commands)
745743 self .commands = type (commands ) ~= ' table' and { commands } or commands
746744
747745 for _ , cmd_name in ipairs (self .commands ) do
748- -- Create a user command that loads the plugin and then executes the real command
749746 api .nvim_create_user_command (cmd_name , function (cmd_args )
750- self :load ()
751-
752- -- Execute the original command with the arguments
747+ pcall (api .nvim_del_user_command , cmd_name )
753748 local args = cmd_args .args ~= ' ' and ' ' .. cmd_args .args or ' '
754749 local bang = cmd_args .bang and ' !' or ' '
750+ Async .async (function ()
751+ if not self .loaded then
752+ self :load ()
753+
754+ local plugin_path = self :get_path ()
755+ local plugin_dir = vim .fs .joinpath (plugin_path , ' plugin' )
756+
757+ local stat = uv .fs_stat (plugin_dir )
758+ if stat and stat .type == ' directory' then
759+ local handle = uv .fs_scandir (plugin_dir )
760+ if handle then
761+ while true do
762+ local name , type = uv .fs_scandir_next (handle )
763+ if not name then
764+ break
765+ end
766+
767+ if type == ' file' and (name :match (' %.lua$' ) or name :match (' %.vim$' )) then
768+ local file_path = vim .fs .joinpath (plugin_dir , name )
769+ vim .schedule (function ()
770+ vim .cmd (' source ' .. vim .fn .fnameescape (file_path ))
771+ end )
772+ end
773+ end
774+ end
775+ end
755776
756- vim .cmd (cmd_name .. bang .. args )
777+ vim .schedule (function ()
778+ if vim .fn .exists (' :' .. cmd_name ) == 2 then
779+ local ok , err = pcall (vim .cmd , cmd_name .. bang .. args )
780+ if not ok then
781+ vim .notify (
782+ string.format (' execute %s wrong: %s' , cmd_name , err ),
783+ vim .log .levels .ERROR
784+ )
785+ end
786+ end
787+ end )
788+ end
789+ end )()
757790 end , {
758791 nargs = ' *' ,
759792 bang = true ,
760793 complete = function (_ , cmd_line , _ )
761- -- If the plugin has a completion function, load the plugin first
762- self :load ()
763-
764- -- Try to use the original command's completion
794+ if not self .loaded then
795+ self :load ()
796+ end
765797 local ok , result = pcall (function ()
766798 return vim .fn .getcompletion (cmd_line , ' cmdline' )
767799 end )
@@ -809,8 +841,9 @@ function Plugin:keys(mappings)
809841end
810842
811843-- Mark plugin as a development plugin
812- function Plugin :dev ()
813- self .is_dev = true
844+ function Plugin :load_path (path )
845+ self .is_local = true
846+ self .load_path = vim .fs .normalize (path )
814847 self .is_remote = false
815848 return self
816849end
@@ -872,13 +905,6 @@ function Plugin:call_setup()
872905 end
873906end
874907
875- function Plugin :load_rtp (callback )
876- local path = self :get_path ()
877- vim .opt .rtp :append (path )
878- self :call_setup ()
879- callback ()
880- end
881-
882908function Plugin :build (action )
883909 assert (type (action ) == ' string' )
884910 self .build_action = action
901927
902928-- Install the plugin
903929function Plugin :install ()
904- if self .is_dev or not self .is_remote then
930+ if self .is_local or not self .is_remote then
905931 return Async .wrap (function (cb )
906932 cb (true )
907933 end )()
@@ -914,7 +940,7 @@ function Plugin:install()
914940 local cmd = { ' git' , ' clone' , ' --progress' , url , path }
915941
916942 -- Ensure parent directory exists
917- vim .fn .mkdir (vim .fs .dirname (path ), ' p' )
943+ -- vim.fn.mkdir(vim.fs.dirname(path), 'p')
918944
919945 -- Update status
920946 self .status = STATUS .INSTALLING
@@ -949,9 +975,8 @@ function Plugin:install()
949975
950976 -- Run build command if specified
951977 if self .build_action then
952- self :load_rtp (function ()
953- vim .cmd (self .build_action )
954- end )
978+ self :load ()
979+ vim .cmd (self .build_action )
955980 end
956981 else
957982 self .status = STATUS .ERROR
967992
968993function Plugin :has_updates ()
969994 return Async .wrap (function (callback )
970- if self .is_dev or not self .is_remote then
995+ if self .is_local or not self .is_remote then
971996 callback (false )
972997 return
973998 end
@@ -993,7 +1018,7 @@ function Plugin:has_updates()
9931018end
9941019
9951020function Plugin :update ()
996- if self .is_dev or not self .is_remote then
1021+ if self .is_local or not self .is_remote then
9971022 return Async .wrap (function (cb )
9981023 cb (true , ' skip' )
9991024 end )()
@@ -1085,7 +1110,7 @@ function Plugin:update()
10851110end
10861111
10871112function Plugin :install_with_retry ()
1088- if self .is_dev or not self .is_remote then
1113+ if self .is_local or not self .is_remote then
10891114 return Async .wrap (function (cb )
10901115 cb (true )
10911116 end )()
@@ -1141,9 +1166,8 @@ function Plugin:install_with_retry()
11411166
11421167 -- Run build command if specified
11431168 if self .build_action then
1144- self :load_rtp (function ()
1145- vim .cmd (self .build_action )
1146- end )
1169+ self :load ()
1170+ vim .cmd (self .build_action )
11471171 end
11481172 else
11491173 self .status = STATUS .ERROR
@@ -1180,6 +1204,8 @@ function M.log(level, message)
11801204 end
11811205end
11821206
1207+ local called_installer = false
1208+
11831209-- Register a plugin
11841210function M .use (spec )
11851211 local plugin = Plugin .new (spec )
@@ -1202,30 +1228,14 @@ function M.get_plugin(name)
12021228 return plugin_map [name ]
12031229end
12041230
1205- -- Set up auto-install
1206- local function setup_auto_install ()
1207- api .nvim_create_autocmd (' UIEnter' , {
1208- group = api .nvim_create_augroup (' strive_auto_install' , { clear = true }),
1209- callback = function ()
1210- -- We're already in a UIEnter event, so we should be careful about recursion
1211- -- We want to install plugins but not trigger another UIEnter event
1212- -- Use vim.schedule to avoid nesting too deep
1213- vim .schedule (function ()
1214- M .install ()
1215- end )
1216- end ,
1217- once = true , -- Only trigger once to avoid recursion
1218- })
1219- end
1220-
12211231-- Install all plugins
12221232function M .install ()
12231233 Async .async (function ()
12241234 local plugins_to_install = {}
12251235
12261236 -- Find plugins that need installation
12271237 for _ , plugin in ipairs (plugins ) do
1228- if plugin .is_remote and not plugin .is_dev then
1238+ if plugin .is_remote and not plugin .is_local then
12291239 local result = Async .try_await (plugin :is_installed ())
12301240
12311241 if result .success and not result .value then
@@ -1301,7 +1311,7 @@ function M.update()
13011311
13021312 -- Find plugins that need updating with proper error handling
13031313 for _ , plugin in ipairs (plugins ) do
1304- if plugin .is_remote and not plugin .is_dev then
1314+ if plugin .is_remote and not plugin .is_local then
13051315 local result = Async .try_await (plugin :is_installed ())
13061316
13071317 if result .success and result .value then
@@ -1466,28 +1476,6 @@ function M.clean()
14661476 end )()
14671477end
14681478
1469- local function create_commands ()
1470- local t = { install = 1 , update = 2 , clean = 3 }
1471- api .nvim_create_user_command (' Strive' , function (args )
1472- if t [args .args ] then
1473- M [args .args ]()
1474- end
1475- end , {
1476- desc = ' Install plugins' ,
1477- nargs = ' +' ,
1478- complete = function ()
1479- return vim .tbl_keys (t )
1480- end ,
1481- })
1482- end
1483-
1484- -- Setup auto-install if enabled
1485- if DEFAULT_SETTINGS .auto_install then
1486- setup_auto_install ()
1487- end
1488-
1489- create_commands ()
1490-
14911479ffi .cdef ([[
14921480 typedef long time_t;
14931481 typedef int clockid_t;
@@ -1497,17 +1485,62 @@ ffi.cdef([[
14971485 } timespec;
14981486 int clock_gettime(clockid_t clk_id, struct timespec *tp);
14991487]] )
1500- local CLOCK_PROCESS_CPUTIME_ID = vim .uv .os_uname ().sysname :match (' Darwin' ) and 12 or 2
15011488
1502- api .nvim_create_autocmd (' UIEnter' , {
1503- callback = function ()
1504- if vim .g .strive_startup_time ~= nil then
1505- return
1506- end
1489+ local CLOCK_PROCESS_CPUTIME_ID = uv .os_uname ().sysname :match (' Darwin' ) and 12 or 2
15071490
1508- local t = assert (ffi .new (' timespec[?]' , 1 ))
1509- ffi .C .clock_gettime (CLOCK_PROCESS_CPUTIME_ID , t )
1510- vim .g .strive_startup_time = tonumber (t [0 ].tv_sec ) * 1e3 + tonumber (t [0 ].tv_nsec ) / 1e6
1491+ local function startuptime ()
1492+ if vim .g .strive_startup_time ~= nil then
1493+ return
1494+ end
1495+
1496+ local t = assert (ffi .new (' timespec[?]' , 1 ))
1497+ ffi .C .clock_gettime (CLOCK_PROCESS_CPUTIME_ID , t )
1498+ vim .g .strive_startup_time = tonumber (t [0 ].tv_sec ) * 1e3 + tonumber (t [0 ].tv_nsec ) / 1e6
1499+ end
1500+
1501+ -- Set up auto-install with better event handling
1502+ local function setup_auto_install ()
1503+ -- Check if Neovim startup is already complete
1504+ -- When using strive in plugin folder
1505+ if vim .v .vim_did_enter == 1 then
1506+ -- UI has already initialized, schedule installation directly
1507+ vim .schedule (function ()
1508+ M .log (' debug' , ' UI already initialized, installing plugins now' )
1509+ M .install ()
1510+ end )
1511+ startuptime ()
1512+ return
1513+ end
1514+
1515+ -- UI has not initialized yet, register for UIEnter event
1516+ api .nvim_create_autocmd (' UIEnter' , {
1517+ group = api .nvim_create_augroup (' strive_auto_install' , { clear = true }),
1518+ callback = function ()
1519+ vim .schedule (function ()
1520+ M .log (' debug' , ' UIEnter triggered, installing plugins' )
1521+ M .install ()
1522+ end )
1523+ startuptime ()
1524+ end ,
1525+ once = true , -- Only trigger once to avoid recursion
1526+ })
1527+ end
1528+
1529+ -- Setup auto-install if enabled
1530+ if DEFAULT_SETTINGS .auto_install then
1531+ setup_auto_install ()
1532+ end
1533+
1534+ local t = { install = 1 , update = 2 , clean = 3 }
1535+ api .nvim_create_user_command (' Strive' , function (args )
1536+ if t [args .args ] then
1537+ M [args .args ]()
1538+ end
1539+ end , {
1540+ desc = ' Install plugins' ,
1541+ nargs = ' +' ,
1542+ complete = function ()
1543+ return vim .tbl_keys (t )
15111544 end ,
15121545})
15131546
0 commit comments