Загрузить макросы из текущей директории

Здесь обсуждается всё, что касается макросов.
Post Reply
gotar
Posts: 412
Joined: Sun 06 Sep, 2009 12:34
Has thanked: 17 times
Been thanked: 3 times

Загрузить макросы из текущей директории

Post by gotar »

Наваял, может кому пригодится

Code: Select all

local gmeta = { __index=_G }

_G.loadlocalmacros=function()
      far.RecursiveSearch (".", "*.lua",
        function (FindData, FullPath)
          local f, msg = loadfile(FullPath)
          if not f then
           	far.Message(msg,"LoadLocalMacros",_,"w") return
          end
          local env = {Macro=mf.AddMacro,Event=mf.AddEvent}
          setmetatable(env,gmeta) 
          setfenv(f, env)
          AddMacro_filename = FullPath
          local ok, msg = pcall(f)
          if ok then
              env.Macro,env.Event,env.NoMacro,env.NoEvent = nil,nil,nil,nil
          else
            far.Message(msg,   "LoadLocalMacros",_,"w")
          end
        end,0)
end
а в %FARPROFILE%\Macros\scripts\_macroinit.lua

Code: Select all

mf.AddMacro=Macro
mf.AddEvent=Event

Правильный способ, конечно, файлы брать не из текущей директории а из шаблона, аналогичного package.path, но моих знаний пока не хватает, чтобы реализовать такую возможность
User avatar
John Doe
Бюрократ
Posts: 13807
Joined: Wed 27 Apr, 2005 20:42
Has thanked: 73 times
Been thanked: 426 times
Contact:

Re: Загрузить макросы из текущей директоррии

Post by John Doe »

gotar wrote:Правильный способ, конечно, файлы брать не из текущей директории а из шаблона, аналогичного package.path, но моих знаний пока не хватает, чтобы реализовать такую возможность
В чём именно затруднение?
Недостаточно итерации по package.path:gmatch?
User avatar
John Doe
Бюрократ
Posts: 13807
Joined: Wed 27 Apr, 2005 20:42
Has thanked: 73 times
Been thanked: 426 times
Contact:

Re: Загрузить макросы из текущей директории

Post by John Doe »

gotar wrote:Правильный способ, конечно, файлы брать не из текущей директории а из шаблона, аналогичного package.path, но моих знаний пока не хватает, чтобы реализовать такую возможность
В lua 5.2 есть готовая функция для этого - package.searchpath.
По идее она должна быть и в luajit, но в нашей сборке эта возможность наверно отключена.
Shmuel
Posts: 6820
Joined: Thu 23 Mar, 2006 21:36
Location: Israel
Has thanked: 41 times
Been thanked: 528 times

Re: Загрузить макросы из текущей директории

Post by Shmuel »

В нашей сборке она отсутствует, так как LuaFAR заменяет весь файл, который создаёт таблицу package с функциями на свой файл - для поддержки Юникода. А вообще данная функция элементарно пишется на Lua.
User avatar
John Doe
Бюрократ
Posts: 13807
Joined: Wed 27 Apr, 2005 20:42
Has thanked: 73 times
Been thanked: 426 times
Contact:

Re: Загрузить макросы из текущей директории

Post by John Doe »

Shmuel wrote:LuaFAR заменяет весь файл, который создаёт таблицу package с функциями на свой файл - для поддержки Юникода.
А есть ли такая необходимость в случае luajit?
http://luajit.org/extensions.html#library wrote:Non-ASCII characters are handled transparently by the Lua source code parser. This allows the use of UTF-8 characters in identifiers and strings. A UTF-8 BOM is skipped at the start of the source code.
Shmuel
Posts: 6820
Joined: Thu 23 Mar, 2006 21:36
Location: Israel
Has thanked: 41 times
Been thanked: 528 times

Re: Загрузить макросы из текущей директории

Post by Shmuel »

Не знаю. Не уверен, например, что require и package.loadlib будут корректно работать c любыми путями в UTF-8.

Ну и кроме того, предпочитаю, чтобы LuaFAR корректно работал и со стандартным Lua 5.1, а не только с LuaJIT.

Update:
Проверил require с путями на русском в UTF-8 на luajit.exe. Не работает. А LuaFAR работает.
gotar
Posts: 412
Joined: Sun 06 Sep, 2009 12:34
Has thanked: 17 times
Been thanked: 3 times

Re: Загрузить макросы из текущей директории

Post by gotar »

Переделал загрузчик на более корректный
  1. _G.loadlocalmacros=function(dir)
  2.  
  3.  
  4.  
  5.     dir=dir or "."
  6.  
  7.  
  8.  
  9.     F=far.Flags
  10.  
  11.     local scripts = win.GetEnv("farprofile").."\\Macros\\scripts"
  12.  
  13.     local linkdir=scripts.."\\temp"
  14.  
  15.     if( mf.fexist(linkdir) ) then error(linkdir .." already exist!!")  end
  16.  
  17.     dir = far.ConvertPath (dir)
  18.  
  19.  
  20.  
  21.     result=far.MkLink(dir,linkdir,F.LINK_JUNCTION,F.MLF_SHOWERRMSG)
  22.  
  23.     if ( result ~= true ) then error("MkLink error")  end
  24.  
  25.     far.MacroLoadAll()
  26.  
  27.     result,msg=win.RemoveDir(linkdir)
  28.  
  29.     if ( result == nil ) then error("RemoveDirectory: " .. msg)  end
  30.  
  31. end
  32.  
  33. _G.lload=loadlocalmacros

Code: Select all

lua:lload(<dir>)
загружает макросы из произвольного каталога и всех его подкаталогов. Одна проблема - неправильно запоминается имя файла, содержащего макрос. Может быть добавить вызов far.ConvertPath в код LoadOneFile для пути к файлу с макросом?
Shmuel
Posts: 6820
Joined: Thu 23 Mar, 2006 21:36
Location: Israel
Has thanked: 41 times
Been thanked: 528 times

Re: Загрузить макросы из текущей директории

Post by Shmuel »

Зачем показывать ffi-определения функций GetFullPathNameW, lstrlenW, GetFileAttributesW, если они нигде дальше не используются?

А единственная ffi-функция, которая используется (RemoveDirectoryW), видимо используется из-за того, что автор не знает о существовании win.RemoveDir?
gotar
Posts: 412
Joined: Sun 06 Sep, 2009 12:34
Has thanked: 17 times
Been thanked: 3 times

Re: Загрузить макросы из текущей директории

Post by gotar »

Спасибо. Подправил. А что насчет far.ConvertPath?
User avatar
SUSim
Posts: 1636
Joined: Thu 18 Feb, 2010 17:32
Has thanked: 9 times
Been thanked: 26 times

Re: Загрузить макросы из текущей директории

Post by SUSim »

а зачем и
_G.loadlocalmacros=function(dir)
и это
_G.lload=loadlocalmacros
? (может я чего-то не понимаю...)
SimSU ··· ·· -- ··· ··-
gotar
Posts: 412
Joined: Sun 06 Sep, 2009 12:34
Has thanked: 17 times
Been thanked: 3 times

Re: Загрузить макросы из текущей директории

Post by gotar »

loadlocalmacros у меня не хватет терпения набирать
User avatar
John Doe
Бюрократ
Posts: 13807
Joined: Wed 27 Apr, 2005 20:42
Has thanked: 73 times
Been thanked: 426 times
Contact:

Re: Загрузить макросы из текущей директории

Post by John Doe »

gotar wrote:Одна проблема - неправильно запоминается имя файла, содержащего макрос. Может быть добавить вызов far.ConvertPath в код LoadOneFile для пути к файлу с макросом?
Отладчик ZBS игнорирует скрипты, путь к которым не принадлежит к одному заданному корню проекта.
Впрочем, это проблема ZBS.
User avatar
citRiks
Posts: 1733
Joined: Fri 25 Oct, 2019 18:18
Has thanked: 610 times
Been thanked: 102 times

Загрузить макросы из текущей директории

Post by citRiks »

gotar wrote: Thu 25 Jun, 2020 18:12Я-то думал вызвать far.MacroLoadAll, но хотел бы посмотреть и Ваш код
мой код на основе вашего кода, отдаю должок :)

Code: Select all

<YOUR-MODULE-NAME-HERE>.fnc_load_macro_one = function(mcr_info, mcr_path)
	mcr_path = far.ConvertPath(mcr_path, 1)
--	CLEANING OLD VERSION OF THE MACRO FILE (PREVIOUSLY LODADED)
--	I WILL EXPLAIN fnc_clean_mcr_src_all(..) LATER ON
	<YOUR-MODULE-NAME-HERE>.fnc_clean_mcr_src_all(mcr_path)
	local	fnc, msg = loadfile(mcr_path)
	if not	fnc
	then	far.Message(msg, "Error loading macro file", nil, "w") return
	end
	local env_m = {
		Macro = function(srctable) mf.AddMacro(srctable, mcr_path) end, 
		Event = function(srctable) mf.AddMacro(srctable, mcr_path) end
			}
	setmetatable(env_m, mt_g)
	setfenv(fnc, env_m)
	local	ret, msg = pcall(fnc)
	if not	ret then
		far.Message(msg, "Error loading macro func", nil, "w")
	end
end

Code: Select all

-- HAVING ABOVE ROUTINE FOR SINGLE MACRO,
-- LOADING FROM ENTIRE DIRECTORY:
<YOUR-MODULE-NAME-HERE>.fnc_load_macro_dir = function(src_dir)
	far.RecursiveSearch(
		src_dir --[["." - current dir]], 
		"*.lua",
		<YOUR-MODULE-NAME-HERE>.fnc_load_macro_one, 
		0
			)
end
Самое главное иметь функцию для очистки от предыдущей версий
Но тут вещи немного усложняются, внутри моих функций вызываются другие,
которые в свою очередь обращаются к хитро вытащенным наружу внутренним обьектам плагина LuaMacro

Code: Select all

<YOUR-MODULE-NAME-HERE>.fnc_clean_mcr_src_all = function(mcr_src)
	<YOUR-MODULE-NAME-HERE>.fnc_clean_mcr_src_tbl(mcr_src, <YOUR-MODULE-NAME-HERE>.utils.LoadedMacros)
	for	ii_area, tbl_area in pairs(<YOUR-MODULE-NAME-HERE>.utils.Areas)
	do	for	ii_key, tbl_key in pairs(tbl_area)
		do	<YOUR-MODULE-NAME-HERE>.fnc_clean_mcr_src_tbl(mcr_src, tbl_key)
		end
	end
end

Code: Select all

<YOUR-MODULE-NAME-HERE>.fnc_clean_mcr_src_tbl = function(mcr_src, tbl_mcr)
	local mcr_cnt = #tbl_mcr
	local mcr_rem = 0
	local ii_mcr
	for	ii = 1, mcr_cnt - mcr_rem
	do	ii_mcr = tbl_mcr[ii]
		if	ii_mcr.FileName == mcr_src
		then	mcr_rem = mcr_rem + 1
		end
		if	mcr_rem > 0 
		then	tbl_mcr[ii] = tbl_mcr[ii + mcr_rem]
		end
	end
end
А те самые внутренние обьекты плагина LuaMacro добываются таким образом,
находясь в _macroinit.lua:

Code: Select all

local all_the_stuff = {}
for ii = 0, 1000 do
	local mcr_src, mcr_inf, LastWriteTime, tbl_locals, tbl_upvals, dbg_info = <YOUR-MODULE-NAME-HERE>.fnc_get_src_info(nil, ii, nil, 2, 2, false)
	if not dbg_info then break end
	if tbl_upvals.LoadedMacros then
		<YOUR-MODULE-NAME-HERE>.utils = tbl_upvals
		<YOUR-MODULE-NAME-HERE>.utils_locals  = tbl_locals
		break
	end
	all_the_stuff[ii] = {mcr_src = mcr_src, mcr_inf = mcr_inf, LastWriteTime = LastWriteTime, tbl_locals = tbl_locals, tbl_upvals = tbl_upvals, dbg_info = dbg_info}
end
Используем эту функцию, написанную в очередном приступе умопомрачения,
но полезную следующим поколениям умопомрачившихся:

Code: Select all

<YOUR-MODULE-NAME-HERE>.fnc_get_src_info = function(src_thr, src_lev, show_info, mode_locals, mode_upvals, with_nums, tbl_locals, tbl_upvals)
	if	type(src_thr) ~= "thread" and 
		type(src_thr) ~= "nil"
	then
		src_thr, src_lev, show_info, mode_locals, mode_upvals, tbl_locals, tbl_upvals = nil, 
		src_thr, src_lev, show_info, mode_locals, mode_upvals, tbl_locals, tbl_upvals
	end
	local dbg_info, LoadedMacros, mcr_src, mcr_inf
	if not tbl_upvals then tbl_upvals = {} end
	if not tbl_locals then tbl_locals = {} end
	local dbg_props = nil -- "nSlfu"
	local is_same_thr = not src_thr or coroutine.running() == src_thr

	if	is_same_thr 
	then	dbg_info = debug.getinfo(src_lev, dbg_props) -- "nSlfu" ?
	else	dbg_info = debug.getinfo(src_thr, src_lev, dbg_props) 
	end
	
	if	dbg_info
	then	local fnc_name, fnc_code, curr_line = <YOUR-MODULE-NAME-HERE>.fnc_guess_func_name(dbg_info)
		if not	dbg_info.name then
                	dbg_info.name = fnc_name
                end
		dbg_info.currentline_txt = curr_line
		dbg_info.source_code = fnc_code
		mcr_src = dbg_info.source:sub(2)
		mcr_inf = win.GetFileInfo(mcr_src)
		if	mode_upvals and mode_upvals > 0
		then	for	ii = 1, dbg_info.nups
			do	local n, v = debug.getupvalue(dbg_info.func, ii)
				if band(mode_upvals, 2) == 2 then 
					tbl_upvals[with_nums and "["..ii.."] "..n or n] = v or "<NIL>"
				end
			end
		end
		if	mode_locals and mode_locals > 0
		then	local	ii = 0
			while	true 
			do	ii = ii + 1
				local n, v
				if	is_same_thr
				then	n, v = debug.getlocal(src_lev, ii)
				else	n, v = debug.getlocal(src_thr, src_lev, ii)
				end
			        if not n then break end
				if band(mode_locals, 2) == 2 then 
					tbl_locals[with_nums and "["..ii.."] "..n or n] = v or "<NIL>"
				end
			end
		end
	elseif	type(src_lev) == "string"
	then	mcr_inf = win.GetFileInfo(src_lev)
		if mcr_inf then mcr_src = src_lev end
	end
	if mcr_src then mcr_src = far.ConvertPath(mcr_src, 1) end
	return mcr_src, mcr_inf, mcr_inf and mcr_inf.LastWriteTime, tbl_locals, tbl_upvals, dbg_info
end -- end of fnc_get_src_info
.. в которой функции в свою очередь используются такие (когда же это кончится):

Code: Select all

<YOUR-MODULE-NAME-HERE>.fnc_guess_func_name = function(dbg_info)
	local	line_str, line_def, line_cur, src_code
	local	src_code = ""
	if	type(dbg_info.source) == "string" and dbg_info.source:sub(1, 1) == "@" 
	then
		local	fileH, err = io.open(dbg_info.source:sub(2), "r")
		if not	fileH 
		then	return "?"
		end
		for	line_num = 1, dbg_info.lastlinedefined
		do 	line_str = fileH:read("*l")
			if not	line_str then break end
			if	line_num == dbg_info.linedefined 
			then	line_def = line_str
			end
			if	line_num == dbg_info.currentline 
			then	line_cur = line_str
			end
			if	line_num >= dbg_info.linedefined and 
				line_num <= dbg_info.lastlinedefined 
			then	src_code = src_code..line_str..string.char(10)..string.char(13)
			end
		end
		fileH:close()
	else	
		local	line_num = 0
		for	line_str in string.gmatch(dbg_info.source, "([^\n]+)\n-") 
		do	line_num = line_num + 1
			if	line_num == dbg_info.linedefined 
			then	line_def = line_str
			end
			if	line_num == dbg_info.currentline 
			then	line_cur = line_str
			end
			if	line_num >= dbg_info.linedefined and 
				line_num <= dbg_info.lastlinedefined 
			then	src_code = src_code..line_str..string.char(10)..string.char(13)
			end
		end
	end
	if src_code == "" then src_code = nil end
	return line_def and <YOUR-MODULE-NAME-HERE>.fnc_parse_fnc_def(line_def) or "?", src_code, line_cur
end -- end of fnc_guess_func_name

Code: Select all

<YOUR-MODULE-NAME-HERE>.fnc_parse_fnc_def = function(line)
	assert(type(line) == "string")
	local match = line:match("^%s*function%s+(%w+)")
	if match then
		return match
	end
	match = line:match("^%s*local%s+function%s+(%w+)")
	if match then
		return match
	end
	match = line:match("^%s*local%s+(%w+)%s+=%s+function")
	if match then
		return match
	end
	match = line:match("%s*function%s*%(")	-- this is an anonymous function
	if match then
		return "(anonymous)"
	end
	return "(anonymous)"
end -- end of fnc_parse_fnc_def
Кажется все.
Думаю теперь Вы поняли почему я так долго не мог собраться это показывать
Last edited by citRiks on Sun 12 Jul, 2020 18:41, edited 6 times in total.
Post Reply

Return to “Обсуждение макросов”