diff --git a/plugins/luafarhistory/build/Makefile b/plugins/luafarhistory/build/Makefile index e8cf2e6..ba5a194 100644 --- a/plugins/luafarhistory/build/Makefile +++ b/plugins/luafarhistory/build/Makefile @@ -10,11 +10,11 @@ T_MESSAGE = $(path_plugin)\lfh_message.lua bootscript = $(path_plugin)\$(PROJECT).lua scripts = \ - $(path_plugin)\_globalinfo.lua \ - $(path_plugin)\lfh_message.lua \ - $(path_plugin)\config.lua + $(path_plugin)\_globalinfo.lua modules = \ + $(path_plugin)\lfh_message.lua \ + $(path_plugin)\lfh_config.lua \ $(path_share)*shmuz\serial.lua \ $(path_share)*far2\history.lua \ $(path_share)*far2\custommenu.lua \ diff --git a/plugins/luafarhistory/build/define.lua b/plugins/luafarhistory/build/define.lua index c6a59d6..fe34f33 100644 --- a/plugins/luafarhistory/build/define.lua +++ b/plugins/luafarhistory/build/define.lua @@ -1,7 +1,7 @@ -- Definitions VER_MAJOR = "3" -VER_MINOR = "11" -VER_MICRO = "2" +VER_MINOR = "12" +VER_MICRO = "0" MINFARVERSION = "{ 3, 0, 0, 3812 }" -- 3.0.0.4364 for non-embedded plugin build (-DRUN_LUAFAR_INIT) diff --git a/plugins/luafarhistory/config.lua b/plugins/luafarhistory/config.lua deleted file mode 100644 index 425aa74..0000000 --- a/plugins/luafarhistory/config.lua +++ /dev/null @@ -1,86 +0,0 @@ --- file created: 2010-03-16 - -local F = far.Flags -local sd = require "far2.simpledialog" -local DlgSend = far.SendDlgMessage - -local function ConfigDialog (aData, M, aDateFormats) - local offset = 5 + math.max(M.mBtnHighTextColor:len(), M.mBtnSelHighTextColor:len()) + 10 - local swid = M.mTextSample:len() - local Items = { - guid = "05d16094-0735-426c-a421-62dae2db6b1a"; - help = "PluginConfig"; - width = 66; - { tp="dbox"; text=M.mPluginTitle..": "..M.mSettings; }, - - { tp="text"; text=M.mMaxHistorySizes; }, - { tp="text"; text=M.mSizeCmd; x1=6; }, - { tp="fixedit"; x1=20; width=5; name="iSizeCmd"; ystep=0; }, - { tp="text"; text=M.mSizeView; x1=6; }, - { tp="fixedit"; x1=20; width=5; name="iSizeView"; ystep=0; }, - { tp="text"; text=M.mSizeFold; x1=6; }, - { tp="fixedit"; x1=20; width=5; name="iSizeFold"; ystep=0; }, - - { tp="text"; text=M.mWinProperties; x1=34; ystep=-3; }, - { tp="chbox"; text=M.mDynResize; x1=35; name="bDynResize"; }, - { tp="chbox"; text=M.mAutoCenter; x1=35; name="bAutoCenter"; }, - - { tp="sep"; text=M.mSepColors; centertext=1; ystep=2; }, - { tp="butt"; text=M.mBtnHighTextColor; btnnoclose=1; name="btnHighTextColor"; }, - { tp="text"; text=M.mTextSample; x1=offset; ystep=0; name="labHighTextColor"; width=swid; }, - { tp="butt"; text=M.mBtnSelHighTextColor; btnnoclose=1; name="btnSelHighTextColor"; }, - { tp="text"; text=M.mTextSample; x1=offset; ystep=0; name="labSelHighTextColor"; width=swid; }, - { tp="sep"; }, - - { tp="text"; text=M.mDateFormat; }, - { tp="combobox"; name="iDateFormat"; dropdown=1; list={}; width=24; }, - { tp="chbox"; text=M.mKeepSelectedItem; name="bKeepSelectedItem"; x1=35; ystep=-1; }, - { tp="sep"; ystep=2; }, - - { tp="butt"; text=M.mOk; centergroup=1; default=1; }, - { tp="butt"; text=M.mCancel; centergroup=1; cancel=1; }, - } - ------------------------------------------------------------------------------ - local dlg = sd.New(Items) - local Pos, Elem = dlg:Indexes() - - local time = os.time() - for _,fmt in ipairs(aDateFormats) do - local t = { Text = fmt and os.date(fmt, time) or M.mDontShowDates } - table.insert(Elem.iDateFormat.list, t) - end - - dlg:LoadData(aData) - - local hColor0 = aData.HighTextColor - local hColor1 = aData.SelHighTextColor - - Items.proc = function (hDlg, msg, param1, param2) - if msg == F.DN_BTNCLICK then - if param1 == Pos.btnHighTextColor then - local c = far.ColorDialog(hColor0) - if c then hColor0 = c; DlgSend(hDlg,F.DM_REDRAW); end - elseif param1 == Pos.btnSelHighTextColor then - local c = far.ColorDialog(hColor1) - if c then hColor1 = c; DlgSend(hDlg,F.DM_REDRAW); end - end - - elseif msg == F.DN_CTLCOLORDLGITEM then - if param1 == Pos.labHighTextColor then param2[1] = hColor0; return param2; end - if param1 == Pos.labSelHighTextColor then param2[1] = hColor1; return param2; end - end - end - - local out = dlg:Run() - if out then - dlg:SaveData(out, aData) - aData.iSizeCmd = tonumber(aData.iSizeCmd) - aData.iSizeView = tonumber(aData.iSizeView) - aData.iSizeFold = tonumber(aData.iSizeFold) - aData.HighTextColor = hColor0 - aData.SelHighTextColor = hColor1 - return true - end -end - -return ConfigDialog diff --git a/plugins/luafarhistory/doc/changelog.txt b/plugins/luafarhistory/doc/changelog.txt index 44869e8..bc4615b 100644 --- a/plugins/luafarhistory/doc/changelog.txt +++ b/plugins/luafarhistory/doc/changelog.txt @@ -2,6 +2,13 @@ Legend: [+] added; [-] deleted; [*] changed; [!] fixed; ------------------------------------------------------------------ +2023-11-04, v3.12.0 + [+] Configuration: add exclusion lists + [+] Most operations made available via Plugin.Call + [*] The macrofile lf_history.lua uses Plugin.Call rather than Plugin.Menu + [*] Full separation between configuration and data + [-] Remove switching between history windows of different types + 2023-07-11, v3.11.2 [!] Configuration dialog: fixes diff --git a/plugins/luafarhistory/lfh_config.lua b/plugins/luafarhistory/lfh_config.lua new file mode 100644 index 0000000..3a4380f --- /dev/null +++ b/plugins/luafarhistory/lfh_config.lua @@ -0,0 +1,204 @@ +-- file created: 2010-03-16 +-- luacheck: globals _Plugin + +local F = far.Flags +local sd = require "far2.simpledialog" +local M = require "lfh_message" +local DlgSend = far.SendDlgMessage +local main + +local function Init(data) + main = data +end + +local function ConfigDialog () + local aData = _Plugin.Cfg + local offset = 5 + math.max(M.mBtnHighTextColor:len(), M.mBtnSelHighTextColor:len()) + 10 + local swid = M.mTextSample:len() + local Items = { + guid = "05d16094-0735-426c-a421-62dae2db6b1a"; + help = "PluginConfig"; + width = 66; + { tp="dbox"; text=M.mPluginTitle..": "..M.mSettings; }, + + { tp="text"; text=M.mMaxHistorySizes; }, + { tp="text"; text=M.mSizeCmd; x1=6; }, + { tp="fixedit"; x1=20; width=5; name="iSizeCmd"; ystep=0; }, + { tp="text"; text=M.mSizeView; x1=6; }, + { tp="fixedit"; x1=20; width=5; name="iSizeView"; ystep=0; }, + { tp="text"; text=M.mSizeFold; x1=6; }, + { tp="fixedit"; x1=20; width=5; name="iSizeFold"; ystep=0; }, + + { tp="text"; text=M.mWinProperties; x1=34; ystep=-3; }, + { tp="chbox"; text=M.mDynResize; x1=35; name="bDynResize"; }, + { tp="chbox"; text=M.mAutoCenter; x1=35; name="bAutoCenter"; }, + + { tp="sep"; text=M.mSepColors; centertext=1; ystep=2; }, + { tp="butt"; text=M.mBtnHighTextColor; btnnoclose=1; name="btnHighTextColor"; }, + { tp="text"; text=M.mTextSample; x1=offset; ystep=0; name="labHighTextColor"; width=swid; }, + { tp="butt"; text=M.mBtnSelHighTextColor; btnnoclose=1; name="btnSelHighTextColor"; }, + { tp="text"; text=M.mTextSample; x1=offset; ystep=0; name="labSelHighTextColor"; width=swid; }, + { tp="sep"; }, + + { tp="text"; text=M.mDateFormat; }, + { tp="combobox"; name="iDateFormat"; dropdown=1; list={}; width=24; }, + { tp="chbox"; text=M.mKeepSelectedItem; name="bKeepSelectedItem"; x1=35; ystep=-1; }, + { tp="sep"; ystep=2; }, + + { tp="butt"; text=M.mOk; centergroup=1; default=1; }, + { tp="butt"; text=M.mCancel; centergroup=1; cancel=1; }, + } + ------------------------------------------------------------------------------ + local dlg = sd.New(Items) + local Pos, Elem = dlg:Indexes() + + local time = os.time() + for _,fmt in ipairs(main.DateFormats) do + local t = { Text = fmt and os.date(fmt, time) or M.mDontShowDates } + table.insert(Elem.iDateFormat.list, t) + end + + dlg:LoadData(aData) + Elem.iSizeCmd.val = aData.commands.iSize + Elem.iSizeView.val = aData.view.iSize + Elem.iSizeFold.val = aData.folders.iSize + + local hColor0 = aData.HighTextColor + local hColor1 = aData.SelHighTextColor + + Items.proc = function (hDlg, msg, param1, param2) + if msg == F.DN_BTNCLICK then + if param1 == Pos.btnHighTextColor then + local c = far.ColorDialog(hColor0) + if c then hColor0 = c; DlgSend(hDlg,F.DM_REDRAW); end + elseif param1 == Pos.btnSelHighTextColor then + local c = far.ColorDialog(hColor1) + if c then hColor1 = c; DlgSend(hDlg,F.DM_REDRAW); end + end + + elseif msg == F.DN_CTLCOLORDLGITEM then + if param1 == Pos.labHighTextColor then param2[1] = hColor0; return param2; end + if param1 == Pos.labSelHighTextColor then param2[1] = hColor1; return param2; end + end + end + + local out = dlg:Run() + if out then + if tonumber(out.iSizeCmd) then aData.commands.iSize = tonumber(out.iSizeCmd) end + if tonumber(out.iSizeView) then aData.view.iSize = tonumber(out.iSizeView) end + if tonumber(out.iSizeFold) then aData.folders.iSize = tonumber(out.iSizeFold) end + out.iSizeCmd, out.iSizeView, out.iSizeFold = nil,nil,nil + aData.HighTextColor = hColor0 + aData.SelHighTextColor = hColor1 + dlg:SaveData(out, aData) + main.SaveHistory() + end +end + +local function ExclusionDialog (aStr) + local title = aStr=="" and M.mExcludeDlgTitleAdd or M.mExcludeDlgTitleEdit + local Items = { + guid = "4F55D7A5-0CAA-4533-A440-840553845DB0"; + help = "ExclusionDialog"; + { tp="dbox"; text=title; }, + { tp="text"; text=M.mExcludeDlgPrompt; }, + { tp="edit"; text=aStr; name="pattern"; }, + { tp="sep"; }, + { tp="butt"; text=M.mOk; centergroup=1; default=1; }, + { tp="butt"; text=M.mCancel; centergroup=1; cancel=1; }, + } + + local retvalue = nil + Items.closeaction = function(_hDlg, _Par1, tOut) + if tOut.pattern ~= "" and pcall(regex.new, tOut.pattern) then + retvalue = tOut.pattern + else + far.Message(("%s: \"%s\"" ):format(M.mExcludeDlgError, tOut.pattern), M.mError, M.mOk, "w") + return 0 + end + end + + sd.New(Items):Run() + return retvalue +end + +local function ExclusionMenu (aData, aTitle) + local exclude = aData.exclude + local Props = { Title=aTitle; Bottom="Ins, Del, F4"; HelpTopic="ExclusionMenu"; } + local Items = {} + local Bkeys = "Ins Del F4" + local modif = false + + for i,v in ipairs(exclude) do Items[i] = v end + + while true do + local item, pos = far.Menu(Props, Items, Bkeys) + if item then Props.SelectIndex = pos end + + if not item then + if not modif then break end + local R = far.Message(M.mExcludeDlgSaveQuery, M.mPluginTitle, ";YesNoCancel", "w") + if R == 1 then + aData.exclude = Items + main.SaveHistory() + break + elseif R == 2 then + break + end + + elseif item.BreakKey == "Ins" then + local txt = ExclusionDialog("") + if txt then + modif = true + table.insert(Items, Items[pos] and pos or 1, { text=txt; }) + end + + elseif item.BreakKey == "Del" and Items[pos] then + modif = true + table.remove(Items, pos) + if not Items[pos] then Props.SelectIndex = pos-1 end + + elseif (item.BreakKey == "F4" or item.BreakKey == nil) and Items[pos] then + local txt = ExclusionDialog(Items[pos].text) + if txt then + modif = true + Items[pos].text = txt + end + + end + end +end + +local function ConfigMenu() + local Props = { Title=M.mPluginTitle; HelpTopic="ConfigMenu"; } + local Items = { + { tag="general"; data=M.mGeneralSettings; }, + { separator=true; }, + { tag="commands"; data=M.mMenuCommands .. ": " ..M.mExclusions; }, + { tag="view"; data=M.mMenuView .. ": " ..M.mExclusions; }, + { tag="folders"; data=M.mMenuFolders .. ": " ..M.mExclusions; }, + } + local j = 1 + for i,v in ipairs(Items) do + if v.separator==nil then + v.text = ("&%d. %s"):format(j, v.data) + j = j+1 + end + end + + while true do + local item,pos = far.Menu(Props,Items) + if not item then break end + Props.SelectIndex = pos + if item.tag == "general" then + ConfigDialog() + else + ExclusionMenu(_Plugin.Cfg[item.tag], item.data) + end + end +end + +return { + Init = Init; + ConfigMenu = ConfigMenu; +} diff --git a/plugins/luafarhistory/lfh_eng.hlf.mcr b/plugins/luafarhistory/lfh_eng.hlf.mcr index c54167d..3b756a5 100644 --- a/plugins/luafarhistory/lfh_eng.hlf.mcr +++ b/plugins/luafarhistory/lfh_eng.hlf.mcr @@ -36,9 +36,6 @@ title. There are 4 switchable filtering methods available: #Ctrl-Alt-X# Apply XLat conversion on filter and also switch the keyboard layout. #Ctrl-I# Inverse sort order. - #Alt-F8# Switch to Commands history. - #Alt-F11# Switch to View/Edit history. - #Alt-F12# Switch to Folders history. #Ins# Check the item (it protects from deleting by Ctrl-Del or Ctrl-F8) \3BCommands history\- @@ -94,3 +91,27 @@ $ #Plugin's Configuration Dialog# changes. ~Contents~@Contents@ + +@ConfigMenu +$ #Plugin's Configuration Menu# + Here you can choose what to configure: + #-# ~Plugin's Configuration Dialog~@PluginConfig@ + #-# Either of the three exclusion lists + + ~Contents~@Contents@ + +@ExclusionMenu +$ #Exclusion Menu# + #Ins# Add a new exclusion pattern to the list + #Del# Delete an exclusion pattern from the list + #F4# Edit an exclusion pattern + + ~Contents~@Contents@ + +@ExclusionDialog +$ #Edit exclusion pattern dialog# + Here you can add or edit a pattern (FAR regular expression). + If a history item will match this expression it will not be added to a history. + The history items that are already in history will not be affected. + + ~Contents~@Contents@ diff --git a/plugins/luafarhistory/lfh_lang.templ b/plugins/luafarhistory/lfh_lang.templ index eac9014..4c11bb3 100644 --- a/plugins/luafarhistory/lfh_lang.templ +++ b/plugins/luafarhistory/lfh_lang.templ @@ -22,29 +22,29 @@ mPluginTitle // plugin menu items mMenuCommands -"&1. Commands history" -"&1. История команд" -"&1. Historial comandos" +"Commands history" +"История команд" +"Historial comandos" mMenuView -"&2. View/Edit history" -"&2. История редактора/просмотра" -"&2. Historial Ver/Editar" +"View/Edit history" +"История редактора/просмотра" +"Historial Ver/Editar" mMenuFolders -"&3. Folders history" -"&3. История папок" -"&3. Historial carpetas" +"Folders history" +"История папок" +"Historial carpetas" mMenuConfig -"&4. Configuration" -"&4. Конфигурация" -"&4. Configuración" +"Configuration" +"Конфигурация" +"Configuración" mMenuLocateFile -"&5. Locate file" -"&5. Найти файл" -"&5. Localizar archivo" +"Locate file" +"Найти файл" +"Localizar archivo" // titles mTitleCommands @@ -192,3 +192,38 @@ mTimestampMissing "" "<Метка времени отсутствует>" upd: + +mGeneralSettings +"General Settings" +"Общие настройки" +upd: + +mExclusions +"exclusions" +"исключения" +upd: + +mExcludeDlgTitleAdd +"Add an exclusion list item" +"Добавить элемент списка исключений" +upd: + +mExcludeDlgTitleEdit +"Edit an exclusion list item" +"Редактировать элемент списка исключений" +upd: + +mExcludeDlgPrompt +"&Pattern (regular expression)" +"&Шаблон (регулярное выражение)" +upd: + +mExcludeDlgError +"Invalid pattern" +"Ошибка в шаблоне" +upd: + +mExcludeDlgSaveQuery +"The exclusion list has been changed. Save?" +"Список исключений был изменён. Сохранить?" +upd: diff --git a/plugins/luafarhistory/lfh_rus.hlf.mcr b/plugins/luafarhistory/lfh_rus.hlf.mcr index 472d242..f21241e 100644 --- a/plugins/luafarhistory/lfh_rus.hlf.mcr +++ b/plugins/luafarhistory/lfh_rus.hlf.mcr @@ -37,9 +37,6 @@ $ #LuaFAR History (версия #{VER_STRING}) - Содержание -# #Ctrl-Alt-X# Применить преобразование XLat в фильтре и одновременно переключить раскладку клавиатуры. #Ctrl-I# Инвертировать порядок сортировки. - #Alt-F8# Переключиться на историю команд. - #Alt-F11# Переключиться на историю просмотра/редактирования. - #Alt-F12# Переключиться на историю папок. #Ins# Пометить текущий пункт (не будет удаляться по Ctrl-Del и Ctrl-F8) \3BИстория команд\- @@ -97,3 +94,27 @@ $ #Диалог конфигурации плагина# значения фильтра. ~Содержание~@Contents@ + +@ConfigMenu +$ #Меню настроек плагина# + Меню позволяет выбрать для последующей настройки: + #-# ~Диалог конфигурации плагина~@PluginConfig@ + #-# Каждый из трёх списков исключений + + ~Содержание~@Contents@ + +@ExclusionMenu +$ #Меню исключений# + #Ins# Добавить новый шаблон исключения в список + #Del# Удалить шаблон исключения из списка + #F4# Редактировать шаблон исключения + + ~Содержание~@Contents@ + +@ExclusionDialog +$ #Диалог редактирования шаблона исключения# + Здесь можно добавить или отредактировать шаблон (регулярное выражение FAR). + Если элемент истории соответствует данному шаблону, он не будет добавлен в историю. + На существующие элементы истории этот механизм не влияет. + + ~Содержание~@Contents@ diff --git a/plugins/luafarhistory/lfhistory.lua b/plugins/luafarhistory/lfhistory.lua index 908f103..95399bf 100644 --- a/plugins/luafarhistory/lfhistory.lua +++ b/plugins/luafarhistory/lfhistory.lua @@ -3,11 +3,17 @@ far.ReloadDefaultScript = true package.loaded["far2.custommenu"] = nil +package.loaded["lfh_config"] = nil -local custommenu = require "far2.custommenu" +if not _Plugin then + package.path = far.PluginStartupInfo().ModuleDir .. "?.lua;" .. package.path +end + +local Custommenu = require "far2.custommenu" local Utils = require "far2.utils" local LibHistory = require "far2.history" -local M = Utils.RunInternalScript("lfh_message") +local Config = require "lfh_config" +local M = require "lfh_message" local F = far.Flags local FarId = ("\0"):rep(16) local PlugTitleCache = {} @@ -18,12 +24,42 @@ local DefaultCfg = { bShowDates = true, bKeepSelectedItem = false, bDirectSort = true, - iSizeCmd = 1000, - iSizeView = 1000, - iSizeFold = 1000, HighTextColor = 0x3A, SelHighTextColor = 0x0A, iDateFormat = 2, + view = { + iSize = 1000; + lastpattern = nil; + last_time = 0; + searchmethod = "dos"; + xlat = false; + exclude = {}; + }, + commands = { + iSize = 1000; + lastpattern = nil; + last_time = 0; + searchmethod = "dos"; + xlat = false; + exclude = {}; + }, + folders = { + iSize = 1000; + lastpattern = nil; + last_time = 0; + searchmethod = "dos"; + xlat = false; + exclude = {}; + }, + locatefile = { + iSize = nil; + lastpattern = nil; + last_time = nil; + searchmethod = "dos"; + xlat = false; + exclude = nil; + bDynResize = true; + }, } local cfgView = { @@ -35,9 +71,7 @@ local cfgView = { "CtrlEnter", "CtrlNumEnter", "RCtrlEnter", "RCtrlNumEnter", "ShiftEnter", "ShiftNumEnter", "CtrlPgUp", "RCtrlPgUp", "CtrlPgDn", "RCtrlPgDn", - "AltF8", "RAltF8", "AltF12", "RAltF12", }, - maxItemsKey = "iSizeView", } local cfgCommands = { @@ -47,9 +81,7 @@ local cfgCommands = { brkeys = { "CtrlEnter", "RCtrlEnter", "CtrlNumEnter", "RCtrlNumEnter", "ShiftEnter", "ShiftNumEnter", - "AltF11", "RAltF11", "AltF12", "RAltF12", }, - maxItemsKey = "iSizeCmd", } local cfgFolders = { @@ -59,19 +91,16 @@ local cfgFolders = { brkeys = { "CtrlEnter", "RCtrlEnter", "CtrlNumEnter", "RCtrlNumEnter", "ShiftEnter", "ShiftNumEnter", - "AltF8", "RAltF8", "AltF11", "RAltF11", }, - maxItemsKey = "iSizeFold", } local cfgLocateFile = { - PluginHistoryType = "locatefile", + PluginHistoryType = "locatefile", title = "mTitleLocateFile", brkeys = { "F3", "F4", "CtrlEnter", "RCtrlEnter", "CtrlNumEnter", "RCtrlNumEnter", }, - bDynResize = true, } local DateFormats = { @@ -124,7 +153,7 @@ local function TellFileIsDirectory (fname) far.Message(('%s:\n"%s"'):format(M.mFileIsDirectory, fname), M.mError, M.mOk, "w") end -local function LocateFile (fname) +local function FindFile (fname) local attr = GetFileAttrEx(fname) if attr and not attr:find"d" then local dir, name = fname:match("^(.*\\)([^\\]*)$") @@ -170,11 +199,36 @@ local function SortListItems (list, bDirectSort, hDlg) end end -local function GetListKeyFunction (HistTypeConfig, HistObject) +local function ShowItemInfo (aItem, aConfig) + local strTime = GetTimeString(aItem.time) + if strTime then + local sd = require "far2.simpledialog" + local data = aConfig==cfgView and "File:" + or aConfig==cfgCommands and "Command:" + or aConfig==cfgFolders and "Folder:" + or "Data:" + local arr = {} + arr[#arr+1] = {tp="dbox"; text="Information"; } + arr[#arr+1] = {tp="text"; text=data; } + arr[#arr+1] = {tp="edit"; text=aItem.text; readonly=1; } + arr[#arr+1] = {tp="text"; text="Time:"; } + arr[#arr+1] = {tp="edit"; text=strTime; readonly=1; } + if aItem.extra then + arr[#arr+1] = {tp="text"; text="Directory:"; } + arr[#arr+1] = {tp="edit"; text=aItem.extra; readonly=1; } + end + arr[#arr+1] = {tp="sep"; } + arr[#arr+1] = {tp="butt"; text=M.mOk; default=1; centergroup=1; } + + sd.New(arr):Run() + end +end + +local function GetListKeyFunction (aConfig, aData) return function (self, hDlg, key, Item) ----------------------------------------------------------------------------------------------- if key=="CtrlI" or key=="RCtrlI" then - if HistTypeConfig==cfgCommands or HistTypeConfig==cfgView or HistTypeConfig==cfgFolders then + if aConfig==cfgCommands or aConfig==cfgView or aConfig==cfgFolders then SortListItems(self, not _Plugin.Cfg.bDirectSort, hDlg) end return "done" @@ -182,9 +236,9 @@ local function GetListKeyFunction (HistTypeConfig, HistObject) if not Item then return "done" end - if HistTypeConfig==cfgView or HistTypeConfig==cfgLocateFile then - local fname = HistTypeConfig==cfgView and Item.text or Item.text:sub(2) - if HistTypeConfig==cfgLocateFile then + if aConfig==cfgView or aConfig==cfgLocateFile then + local fname = aConfig==cfgView and Item.text or Item.text:sub(2) + if aConfig==cfgLocateFile then if not fname:find("[\\/]") then local Name = self.items.PanelDirectory and self.items.PanelDirectory.Name if Name and Name ~= "" then @@ -211,18 +265,15 @@ local function GetListKeyFunction (HistTypeConfig, HistObject) end ----------------------------------------------------------------------------------------------- elseif key == "F7" then - if HistTypeConfig ~= cfgLocateFile then + if aConfig ~= cfgLocateFile then if Item then - local timestring = GetTimeString(Item.time) - if timestring then - far.Message(Item.text, timestring, ";Ok") - end + ShowItemInfo(Item, aConfig) end end return "done" ----------------------------------------------------------------------------------------------- elseif key == "CtrlF8" or key == "RCtrlF8" then - if HistTypeConfig == cfgFolders or HistTypeConfig == cfgView then + if aConfig == cfgFolders or aConfig == cfgView then far.Message(M.mPleaseWait, "", "") self:DeleteNonexistentItems(hDlg, function(t) return t.text:find("^%w%w+:") -- some plugin's prefix @@ -234,12 +285,12 @@ local function GetListKeyFunction (HistTypeConfig, HistObject) return "done" ----------------------------------------------------------------------------------------------- elseif key == "F9" then - local s = HistObject:getfield("lastpattern") + local s = aData.lastpattern if s and s ~= "" then self:ChangePattern(hDlg,s) end return "done" ----------------------------------------------------------------------------------------------- elseif key=="CtrlDel" or key=="RCtrlDel" or key=="CtrlNumDel" or key=="RCtrlNumDel" then - if HistTypeConfig ~= cfgLocateFile then + if aConfig ~= cfgLocateFile then self:DeleteNonexistentItems(hDlg, function(t) return t.checked end, function(n) return 1 == far.Message((M.mDeleteItemsQuery):format(n), @@ -249,13 +300,13 @@ local function GetListKeyFunction (HistTypeConfig, HistObject) return "done" ----------------------------------------------------------------------------------------------- elseif key=="ShiftDel" or key=="ShiftNumDel" then - if HistTypeConfig == cfgLocateFile then return "done" end + if aConfig == cfgLocateFile then return "done" end ----------------------------------------------------------------------------------------------- elseif key=="Enter" or key=="NumEnter" or key=="ShiftEnter" or key=="ShiftNumEnter" then if not Item then return "done" end - if HistTypeConfig==cfgView then + if aConfig==cfgView then local attr = GetFileAttrEx(Item.text) if not attr then TellFileNotExist(Item.text) @@ -268,21 +319,21 @@ local function GetListKeyFunction (HistTypeConfig, HistObject) ----------------------------------------------------------------------------------------------- end - for _,v in ipairs(HistTypeConfig.brkeys) do + for _,v in ipairs(aConfig.brkeys) do if key == v then return "break" end end end end -function cfgView.CanClose (self, item, breakkey) - if item and (IsCtrlPgUp(breakkey) or IsCtrlPgDn(breakkey)) and not LocateFile(item.text) then +function cfgView.CanClose (_list, item, breakkey) + if item and (IsCtrlPgUp(breakkey) or IsCtrlPgDn(breakkey)) and not FindFile(item.text) then TellFileNotExist(item.text) return false end return true end -function cfgFolders.CanClose (self, item, breakkey) +function cfgFolders.CanClose (_list, item, breakkey) if not item then return true end @@ -292,10 +343,6 @@ function cfgFolders.CanClose (self, item, breakkey) return true end ---------------------------------------------------------------------------- - if breakkey=="AltF8" or breakkey=="RAltF8" or breakkey=="AltF11" or breakkey=="RAltF11" then - return true - end - ---------------------------------------------------------------------------- if item.PluginId then if far.FindPlugin("PFM_GUID", item.PluginId) then panel.SetPanelDirectory(nil, breakkey==nil and 1 or 0, item.PanelDir) @@ -335,57 +382,56 @@ function cfgFolders.CanClose (self, item, breakkey) end end -local function MakeMenuParams (aHistTypeConfig, aHistTypeData, aItems, aHistObject) +local function MakeMenuParams (aConfig, aData, aItems) local Cfg = _Plugin.Cfg local dateformat = DateFormats[Cfg.iDateFormat] + local menuProps = { DialogId = win.Uuid("d853e243-6b82-4b84-96cd-e733d77eeaa1"), Flags = {FMENU_WRAPMODE=1}, HelpTopic = "Contents", - Title = M[aHistTypeConfig.title], + Title = M[aConfig.title], SelectIndex = #aItems, } + local listProps = { --- debug = true, + ----debug = true, autocenter = Cfg.bAutoCenter, - resizeW = ConfigValue(aHistTypeConfig, "bDynResize"), - resizeH = ConfigValue(aHistTypeConfig, "bDynResize"), + resizeW = ConfigValue(aData, "bDynResize"), + resizeH = ConfigValue(aData, "bDynResize"), resizeScreen = true, col_highlight = Cfg.HighTextColor, col_selectedhighlight = Cfg.SelHighTextColor, selalign = "bottom", selignore = not Cfg.bKeepSelectedItem, - searchmethod = aHistTypeData.searchmethod or "dos", + searchmethod = aData.searchmethod or "dos", filterlines = true, - xlat = aHistTypeData.xlat, - showdates = aHistTypeConfig ~= cfgLocateFile and dateformat, + xlat = aData.xlat, + showdates = aConfig ~= cfgLocateFile and dateformat, dateformat = dateformat, } - local list = custommenu.NewList(listProps, aItems) - list.keyfunction = GetListKeyFunction(aHistTypeConfig, aHistObject) - list.CanClose = aHistTypeConfig.CanClose + local list = Custommenu.NewList(listProps, aItems) + list.keyfunction = GetListKeyFunction(aConfig, aData) + list.CanClose = aConfig.CanClose return menuProps, list end -local function GetMaxItems (aConfig) - return _Plugin.Cfg[aConfig.maxItemsKey] -end - -local function DelayedSaveHistory (hist, delay) - far.Timer(delay, function(h) +local function SaveHistory (hist) + far.Timer(200, function(h) h:Close() - hist:save() + if hist then + hist:save() + end _Plugin.History:save() -- _Plugin.Cfg.bDirectSort end) end -local function get_history (aConfig, obj) +local function get_history (aConfig, aData) local menu_items, map = {}, {} -- add plugin database items local hst = LibHistory.newsettings(nil, aConfig.PluginHistoryType, "PSL_LOCAL") local plugin_items = hst:field("items") - local settings = hst:field("settings") for _,v in ipairs(plugin_items) do if v.text and not map[v.text] then table.insert(menu_items, v) @@ -394,7 +440,20 @@ local function get_history (aConfig, obj) end -- add Far database items - local last_time = settings.last_time or 0 + local exclude = {} + for _,v in ipairs(aData.exclude) do + if v.text ~= "" then + local ok, rx = pcall(regex.new, v.text) + if ok then table.insert(exclude, rx) end + end + end + local function IsExclusion(name) + for _,rx in ipairs(exclude) do + if rx:match(name) then return true; end + end + end + + local last_time = aData.last_time or 0 local far_settings = assert(far.CreateSettings("far")) local function AddFarItems (aFarHistoryType, aType) @@ -409,8 +468,8 @@ local function get_history (aConfig, obj) item.typ = aType end else - if v.Time >= last_time then - item = { text=v.Name, time=v.Time, typ=aType } + if v.Time >= last_time and not IsExclusion(v.Name) then + item = { text=v.Name, time=v.Time, extra=v.Param, typ=aType } table.insert(menu_items, item) map[v.Name] = item end @@ -433,7 +492,7 @@ local function get_history (aConfig, obj) item.time = v.Time item.typ = aType end - else + elseif not IsExclusion(text) then item = { PluginId = v.PluginId; PanelDir = v; @@ -449,7 +508,7 @@ local function get_history (aConfig, obj) end end end - settings.last_time = win.GetSystemTimeAsFileTime() + aData.last_time = win.GetSystemTimeAsFileTime() if aConfig == cfgView then AddFarItems(F.FSSF_HISTORY_VIEW, "V") @@ -460,14 +519,13 @@ local function get_history (aConfig, obj) end far_settings:Free() - local maxitems = GetMaxItems(aConfig) - if #menu_items > maxitems then + if #menu_items > aData.iSize then -- sort menu items: oldest records go first table.sort(menu_items, function(a,b) return (a.time or 0) < (b.time or 0) end) -- remove excessive items; leave checked items; local i = 1 - while (#menu_items >= i) and (#menu_items > maxitems) do + while (#menu_items >= i) and (#menu_items > aData.iSize) do if menu_items[i].checked then i = i+1 -- leave the item else table.remove(menu_items, i) -- remove the item end @@ -475,18 +533,16 @@ local function get_history (aConfig, obj) end -- execute the menu - local menuProps, list = MakeMenuParams(aConfig, settings, menu_items, hst) - list.pattern = obj.pattern + local menuProps, list = MakeMenuParams(aConfig, aData, menu_items) SortListItems(list, _Plugin.Cfg.bDirectSort, nil) - local item, itempos = custommenu.Menu(menuProps, list) - obj.pattern = list.pattern - settings.searchmethod = list.searchmethod - settings.xlat = list.xlat + local item, itempos = Custommenu.Menu(menuProps, list) + aData.searchmethod = list.searchmethod + aData.xlat = list.xlat hst:setfield("items", list.items) if item and list.pattern ~= "" then - hst:setfield("lastpattern", list.pattern) + aData.lastpattern = list.pattern end - DelayedSaveHistory(hst, 200) + SaveHistory(hst) if item then return menu_items[itempos], item.BreakKey end @@ -498,12 +554,8 @@ local function IsCmdLineAvail() ar==F.MACROAREA_QVIEWPANEL or ar==F.MACROAREA_TREEPANEL end -local function commands_history(obj) - local item, key = get_history(cfgCommands, obj) - - if key=="AltF11" or key=="RAltF11" then return "view" end - if key=="AltF12" or key=="RAltF12" then return "folders" end - +local function commands_history() + local item, key = get_history(cfgCommands, _Plugin.Cfg.commands) if item and IsCmdLineAvail() then if IsCtrlEnter(key) then panel.SetCmdLine(nil, item.text) @@ -513,11 +565,8 @@ local function commands_history(obj) end end -local function folders_history(obj) - local item, key = get_history(cfgFolders, obj) - - if key=="AltF8" or key=="RAltF8" then return "commands" end - if key=="AltF11" or key=="RAltF11" then return "view" end +local function folders_history() + get_history(cfgFolders, _Plugin.Cfg.folders) end local function CallViewer (fname, disablehistory) @@ -530,11 +579,8 @@ local function CallEditor (fname, disablehistory) editor.Editor(fname, nil, nil, nil, nil, nil, flags) end -local function view_history(obj) - local item, key = get_history(cfgView, obj) - - if key=="AltF8" or key=="RAltF8" then return "commands" end - if key=="AltF12" or key=="RAltF12" then return "folders" end +local function view_history() + local item, key = get_history(cfgView, _Plugin.Cfg.view) if not item then return end local fname = item.text @@ -555,7 +601,7 @@ local function view_history(obj) return key end -local function LocateFile2() +local function LocateFile() local info = panel.GetPanelInfo(nil,1) if not (info and info.PanelType==F.PTYPE_FILEPANEL) then return end @@ -566,19 +612,17 @@ local function LocateFile2() items[k] = {text=prefix..v.FileName} end - local hst = LibHistory.newsettings(nil, cfgLocateFile.PluginHistoryType, "PSL_ROAMING") - local settings = hst:field("settings") - - local menuProps, list = MakeMenuParams(cfgLocateFile, settings, items, hst) + local aData = _Plugin.Cfg.locatefile + local menuProps, list = MakeMenuParams(cfgLocateFile, aData, items) list.searchstart = 2 - local item, itempos = custommenu.Menu(menuProps, list) - settings.searchmethod = list.searchmethod - settings.xlat = list.xlat + local item, itempos = Custommenu.Menu(menuProps, list) + aData.searchmethod = list.searchmethod + aData.xlat = list.xlat if item and list.pattern ~= "" then - hst:setfield("lastpattern", list.pattern) + aData.lastpattern = list.pattern end - DelayedSaveHistory(hst, 200) + SaveHistory(nil) if item then if item.BreakKey then @@ -596,7 +640,7 @@ end local PluginMenuGuid1 = win.Uuid("181fa8c3-fd3f-44a8-9c16-e3ca753c4ccb") local PluginConfigGuid1 = win.Uuid("688f9ee4-d0ac-49d0-b66b-8dbaa989f22c") -local function export_GetPluginInfo() +function export.GetPluginInfo() return { CommandPrefix = "lfh", Flags = bit64.bor(F.PF_EDITOR, F.PF_VIEWER), @@ -607,49 +651,51 @@ local function export_GetPluginInfo() } end -local function export_Configure() - local ConfigDialog = Utils.RunInternalScript("config") - if ConfigDialog and ConfigDialog(_Plugin.Cfg, M, DateFormats) then - _Plugin.History:save() - end -end - -local function RunCycle (op) - - local obj_commands = { func=commands_history; pattern=""; } - local obj_view = { func=view_history; pattern=""; } - local obj_folders = { func=folders_history; pattern=""; } - - while op do - if op == "commands" then op = obj_commands:func() - elseif op == "view" then op = obj_view:func() - elseif op == "folders" then op = obj_folders:func() - else break - end - end +function export.Configure() + Config.ConfigMenu() end -local function export_Open (From, Guid, Item) +function export.Open (From, Guid, Item) local userItems, commandTable = Utils.LoadUserMenu("_usermenu.lua") ------------------------------------------------------------------------------ - if From == F.OPEN_FROMMACRO then - return Utils.OpenMacro(Item, commandTable, nil) - elseif From == F.OPEN_COMMANDLINE then + if From == F.OPEN_COMMANDLINE then return Utils.OpenCommandLine(Item, commandTable, nil) - end - ------------------------------------------------------------------------------ - if From==F.OPEN_PLUGINSMENU or From==F.OPEN_EDITOR or From==F.OPEN_VIEWER then - --------------------------------------------------------------------------- + + elseif From == F.OPEN_FROMMACRO then + if Item[1] == "own" then + if Item[2] == "commands" then commands_history() + elseif Item[2] == "view" then view_history() + elseif Item[2] == "folders" then folders_history() + elseif Item[2] == "locate" then LocateFile() + elseif Item[2] == "config" then export.Configure() + end + else + return Utils.OpenMacro(Item, commandTable, nil) + end + + elseif From==F.OPEN_PLUGINSMENU or From==F.OPEN_EDITOR or From==F.OPEN_VIEWER then local properties = { Title=M.mPluginTitle, HelpTopic="Contents", Flags="FMENU_WRAPMODE", } - local items = { - { text=M.mMenuCommands, run_cycle=true; param="commands" }, - { text=M.mMenuView, run_cycle=true; param="view" }, - { text=M.mMenuFolders, run_cycle=true; param="folders" }, - { text=M.mMenuConfig, action=export_Configure }, - { text=M.mMenuLocateFile, action=LocateFile2 }, + local allitems = { + { text=M.mMenuCommands; action=commands_history; areas="p"; }, + { text=M.mMenuView; action=view_history; areas="epv"; }, + { text=M.mMenuFolders; action=folders_history; areas="p"; }, + { text=M.mMenuConfig; action=export.Configure; areas="epv"; }, + { text=M.mMenuLocateFile; action=LocateFile; areas="p"; }, } + + local items = {} + for _,v in ipairs(allitems) do + if From==F.OPEN_PLUGINSMENU and v.areas:find("p") or + From==F.OPEN_EDITOR and v.areas:find("e") or + From==F.OPEN_VIEWER and v.areas:find("v") + then + table.insert(items, v) + v.text = "&"..#items..". "..v.text + end + end + local numInternalItems = #items Utils.AddMenuItems(items, From==F.OPEN_PLUGINSMENU and userItems.panels or @@ -659,9 +705,7 @@ local function export_Open (From, Guid, Item) local item, pos = far.Menu(properties, items) if item then if pos <= numInternalItems then - if item.run_cycle then RunCycle(item.param) - elseif item.action then item.action() - end + item.action() else Utils.RunUserItem(item, item.arg) end @@ -669,18 +713,45 @@ local function export_Open (From, Guid, Item) end end -local function SetExportFunctions() - export.Configure = export_Configure - export.GetPluginInfo = export_GetPluginInfo - export.Open = export_Open +local function FillDefaults (trg, src, guard) + guard = guard or {} -- handle cyclic references + for k,v in pairs(src) do + if trg[k] == nil then + if type(v) == "table" then + if guard[v] then + trg[k] = guard[v] + else + local t = {} + trg[k] = t + guard[v] = t + FillDefaults(t, v, guard) + end + else + trg[k] = v + end + elseif type(trg[k]) == "table" then + if type(v)=="table" and guard[v]==nil then + guard[v] = trg[k] + FillDefaults(trg[k], v, guard) + end + end + end +end + +local function InitConfigModule() + Config.Init { + SaveHistory = SaveHistory; + DateFormats = DateFormats; + } end do if not _Plugin then - _Plugin = Utils.InitPlugin() + _Plugin = {} _Plugin.History = LibHistory.newsettings(nil, "config", "PSL_ROAMING") _Plugin.Cfg = _Plugin.History:field("config") - setmetatable(_Plugin.Cfg, {__index = DefaultCfg}) end - SetExportFunctions() + FillDefaults(_Plugin.Cfg, DefaultCfg) + InitConfigModule() + export.OnError = Utils.OnError end diff --git a/plugins/luafarhistory/macros/lf_history.lua b/plugins/luafarhistory/macros/lf_history.lua index 87725f1..93d1b44 100644 --- a/plugins/luafarhistory/macros/lf_history.lua +++ b/plugins/luafarhistory/macros/lf_history.lua @@ -1,27 +1,33 @@ local LFHistory = "a745761d-42b5-4e67-83da-f07af367ae86" -local function LFH_exist() return Plugin.Exist(LFHistory) end -local function LFH_run(key) if Plugin.Menu(LFHistory) then Keys(key) end end + +local function condition() return Plugin.Exist(LFHistory) end + +local function LFH_run(cmd) Plugin.Call(LFHistory, "own", cmd) end Macro { description="LuaFAR History: commands"; area="Shell Info QView Tree"; key="AltF8"; - condition=LFH_exist; action=function() LFH_run"1" end; + condition=condition; + action=function() LFH_run"commands" end; } Macro { description="LuaFAR History: view/edit"; area="Shell Editor Viewer"; key="AltF11"; - condition=LFH_exist; action=function() LFH_run"2" end; + condition=condition; + action=function() LFH_run"view" end; } Macro { description="LuaFAR History: folders"; area="Shell"; key="AltF12"; - condition=LFH_exist; action=function() LFH_run"3" end; + condition=condition; + action=function() LFH_run"folders" end; } Macro { description="LuaFAR History: locate file"; area="Shell"; key="CtrlSpace"; - condition=LFH_exist; action=function() LFH_run"5" end; + condition=condition; + action=function() LFH_run"locate" end; }