Code: Select all
local Info = Info or package.loaded.regscript or function(...) return ... end --luacheck: ignore 113/Info
local nfo = Info { _filename or ...,
name = "Local menu enhanced";
description = "";--todo
version = "0.3"; --http://semver.org/lang/ru/
author = "jd";
url = "";--todo
id = "10A7C574-2177-44E4-B928-5D9EAE9C2B67";
minfarversion = {3,0,0,5106,0};
help = function(nfo) far.Message(nfo.helpstr,nfo.name,nil,"l") end;
--disabled = false;
options = {
ShowMenuListKey = "CtrlShiftF2 ShiftF2:Hold",
MenusMask = "*.*",
LocalMask = "FarMenu*ini",
};
}
if not nfo or nfo.disabled then return end
local O = nfo.options
nfo.helpstr = [[
Традиционно местные (локальные) меню используются для того чтобы задать перечень команд,
актуальных только для данной конкретной папки.
Но как быть если те же команды требуются и во всех вложенных папках?
В зачаточной форме фар предусматривает определённые средства: переход по BS (Backspace)
в местное меню родительской папки.
Однако этого ещё не достаточно для функционирования задуманного,
и данный набор макросов призван восполнить пробелы.
• F2: (в панелях) открывает ближайший файл в текущей ветке папок.
(в меню) переключает между местным/главным меню.
• BS: (в меню) открывает меню из родительской папки (пустые пропускаются).
Если открыто какое-то подменю, то вызывает переход на уровень выше этого же меню
• Ctrl+Shift+F2 (в панелях), или Shift+F2 (в меню):
отображает список всех FarMenu.ini в текущей ветке папок, а также главное/глобальное меню.
Доступные действия: запустить, отредактировать, открыть на панели.
Дополнительно:
Благодаря mf.usermenu есть возможность вызывать меню из любого файла, поэтому
в этом же списке отображаются:
• все меню из папки Menus (маску можно задать)
• дополнительные меню из текущей папки (маску можно задать)
Ограничения:
Переход по BS не работает, если меню вызвано из файла с помощью mf.usermenu
https://bugs.farmanager.com/view.php?id=3570
Опции можно изменить в начале скрипта.
А чтобы после каждого обновления не приходилось вручную восстанавливать изменённые значения опций
рекомендуется использовать возможности cfgscript из пакета ScriptsBrowser.
]]
--if not panel.CheckPanelsExist() then return end --https://bugs.farmanager.com/view.php?id=2986
for _,mask in ipairs {O.MenusMask,O.LocalMask} do
assert(far.ProcessName ("PN_CHECKMASK",mask,nil,"PN_SHOWERRORMESSAGE"))--todo
end
local um = "FarMenu.ini"
local globalpath = win.GetEnv"FARHOME".."\\"
local global_um = globalpath..um
local userpath = win.GetEnv"FARPROFILE".."\\"
local user_um = userpath..um
local menus = userpath.."Menus"
local function exist(fullname)
local attr = win.GetFileAttr(fullname)
return attr and not attr:find"d" --and fullname
end
local function empty_local()
return Object.Empty and not Object.Title:find " %("
end
Macro { description="Local menu: open nearest"; --https://bugs.farmanager.com/view.php?id=3508
area="Shell Tree"; key="F2";
id="84B0CBF2-8790-44DC-A311-32104F03FE0F";
action=function()
mf.usermenu(1)
Keys"Right Enter"
if not exist(um) then
while empty_local() do
Keys"BS"
end
end
end;
}
Macro { description="Local menu: BS to close submenu (instead of calling parent menu file)";
area="UserMenu"; key="BS CtrlPgUp CtrlNum9 Ctrl9";
id="440A349A-5110-40EC-98C8-B16C48AE2850";
action=function()
if Object.Title:find " » " then
Keys"Esc"
else
repeat Keys"BS" until not empty_local()
end
end;
}
Macro { description="Local menu: F2 to switch local/main menus"; --https://bugs.farmanager.com/view.php?id=3507
area="UserMenu"; key="F2";
id="95BEC820-4F05-4A2C-B787-38C47D1339A0";
action=function()
Keys"ShiftF2"
end;
}
local function traverse(path)
return function(_,updir)
return updir:match"^(.+[\\/]).-[\\/]"
end,nil,path.."\\"
end
local function eq(name1,name2)
return name1:lower()==name2:lower()
end
local Items
local function newSection(name)
Items.section = {text=name,separator=true}
Items.sectionN = #Items
end
local function addItem(name,file,checked,grayed)
if not name then return end
if #Items==Items.sectionN then
table.insert(Items,Items.section)
end
table.insert(Items,{
text = name,
file = file,
checked = checked,
grayed = grayed,
})
end
local function makeMenuList(path)
Items = {}
local global,user = true,true
local function mark(fullname)
local checked
if eq(fullname,global_um) then
checked,global = "⌂",false
elseif eq(fullname,user_um) then
checked,user = "~",false
end
return checked
end
local local_um = path..um
addItem("Local menu",local_um,mark(local_um) or "►",not exist(local_um))
if O.LocalMask then
far.RecursiveSearch(path,O.LocalMask,function(Item,fullname)
if not (Item.FileAttributes:find"d" or eq(fullname,local_um)) then
addItem(Item.FileName,fullname)
end
end)
end
newSection()
for dir in traverse(path:sub(1,-2)) do
local fullname = dir..um
if exist(fullname) then
addItem(dir,fullname,mark(fullname))
end
end
if O.MenusMask then
local attr = win.GetFileAttr(menus)
if attr and attr:find"d" then
newSection("Menus")
far.RecursiveSearch(menus,O.MenusMask,function(Item,fullname)
if not Item.FileAttributes:find"d" then
addItem(Item.FileName,fullname)
end
end)
end
end
newSection()
addItem(user and "(User)",user_um,"~",not exist(user_um))
addItem(global and "(Global)",global_um,"⌂",not exist(global_um))
return Items
end
local props = {
Title="Choose user menu:",
Bottom="Enter, F4, Ctrl+PgDn, F1, F2",
Id=win.Uuid"5BB097BB-DC29-4B16-9D80-80C70EA71152",--MenuListId
}
local function showMenuList(idx)
props.SelectIndex = idx
local items = makeMenuList(far.GetCurrentDirectory().."\\")
local item,pos = far.Menu(props,items,"F1 F2 F4 AltF4 CtrlPgDn CtrlNum3") --todo ShiftF4 ask name
if not item then
--
elseif item.BreakKey then
assert(pos~=0)
local file = items[pos].file
if item.BreakKey=="F1" then
nfo.help(nfo)
elseif item.BreakKey=="AltF4" then
editor.Editor(file,nil,nil,nil,nil,nil,"EF_OPENMODE_BREAKIFOPEN")
elseif item.BreakKey=="F4" then
mf.usermenu(2+0x100,file)
elseif item.BreakKey=="F2" then
Keys"ShiftF10"--ifmenu??
mf.eval("F2",2)
return
else--if item.BreakKey=="CtrlPgDn" then
Keys"ShiftF10"--ifmenu??
local dir_file = "^(.+\\)(.-)$"
Panel.SetPath(0,file:match(dir_file))
return
end
else
Keys"ShiftF10"--ifmenu??
mf.usermenu(2,item.file)
return
end
mf.postmacro(showMenuList,pos)
end
local function showMenuList()
local function exit(f,...)
Keys(Area.UserMenu and "ShiftF10")
f(...)
end
repeat
local items = makeMenuList(far.GetCurrentDirectory().."\\")
local item,pos = far.Menu(props,items,"F1 F2 F4 AltF4 ShiftF4 CtrlPgDn CtrlNum3")
if not item then
--
elseif item.BreakKey then
assert(pos~=0)--todo
local file = items[pos].file
if item.BreakKey=="F1" then
nfo.help(nfo)
elseif item.BreakKey=="AltF4" then
editor.Editor(file,nil,nil,nil,nil,nil,"EF_OPENMODE_BREAKIFOPEN")
elseif item.BreakKey=="F4" then
mf.usermenu(2+0x100,file)
elseif item.BreakKey=="ShiftF4" then
--todo if LocalMask
local Id = win.Uuid"5D48B6C6-D1BA-4077-855B-C6D72ACFE80A"
local name = far.InputBox(Id,nfo.name,"Enter name","LocalMenuName",nil,nil,nil,"FIB_NONE")
--todo add path
if name then
if far.ProcessName("PN_CMPNAMELIST",O.LocalMask,Name,"PN_SKIPPATH") then
mf.usermenu(2+0x100,file)
else
--todo
end
end
elseif item.BreakKey=="F2" then
item = exit(mf.eval,"F2",2)
else--if item.BreakKey=="CtrlPgDn" then
local dir_file = "^(.+\\)(.-)$"
item = exit(Panel.SetPath,0,file:match(dir_file))
end
else
item = exit(mf.usermenu,2,item.file)
end
props.SelectIndex = pos
until not item
end
local function showMenu_List(idx)
props.SelectIndex = idx
local items = makeMenuList(far.GetCurrentDirectory().."\\")
local item,pos = far.Menu(props,items,"F1 F2 AltF4 CtrlPgDn CtrlNum3") --todo ShiftF4
if item then
while Area.UserMenu do Keys"Esc" end --todo
if not item.BreakKey then
mf.usermenu(2,item.file)
else
local file = items[pos].file
if item.BreakKey=="F1" then
mf.acall(nfo.help,nfo)
elseif item.BreakKey=="F2" then
mf.eval("F2",2)
elseif item.BreakKey=="AltF4" then
editor.Editor(file,nil,nil,nil,nil,nil,"EF_OPENMODE_BREAKIFOPEN")
mf.postmacro(showMenuList,pos)
else--if item.BreakKey=="CtrlPgDn" then
local dir_file = "^(.+\\)(.-)$"
Panel.SetPath(0,file:match(dir_file))
end
end
end
end
Macro { description="Local menu: show list (from UserMenu)";
area="UserMenu"; key="ShiftF2";
id="18BD5350-5279-4136-8B47-27D86374FE92";
action=showMenuList;
}
Macro { description="Local menu: show list (from Shell)";
area="Shell Tree"; key=O.ShowMenuListKey;
id="5022D5FE-6EC4-4635-BFC2-D3F71E7E16A6";
action=showMenuList;
}
--------------------------------------------
NoMacro { description="Local menu: open main";
area="Shell Tree"; key="CtrlAltF2";
id="ABE2DF8A-0AA4-48C2-8FD2-DB5086BAC96D";
action=function()
mf.usermenu(1); Keys"Enter"
end;
}
NoMacro { description="Local menu: Show current menu filename";
area="UserMenu"; key="ShiftF1";
id="2E5D0A60-7B5A-4AE9-9F7F-11391502922F";
action=function()
Keys"AltF4"
local file = Editor.FileName
Keys"Esc"
if type(file)=="string" then
far.Message(file,nfo.name)
end
end;
}
NoMacro { description="Local menu: Start from the beginning";
area="UserMenu"; key="CtrlHome CtrlNum7";
id="E54739B1-BC87-4C9C-88CF-73198F393F6C";
action=function()
Keys"ShiftF10"
if Area.Shell then mf.eval("F2",2) end
end;
}