Макросы для работы с описаниями файлов

Здесь выкладываются готовые к использованию макросы и скрипты.
User avatar
Smitis
Posts: 1709
Joined: Fri 18 Mar, 2005 12:51
Location: Питер
Has thanked: 23 times
Been thanked: 55 times

Макросы для работы с описаниями файлов

Post by Smitis »

Макросы для замены плагина DescSS

Плагин DescSS позволял выполнять некоторые действия с описаниями файлов, как с именами файлов, а именно:
- установка и снятия пометки по маске аналогично NumPad+ (Grey+) и NumPad- (Grey-), используя вместо имён файлов описания;
- быстрый поиск файлов аналогично Alt-символ в панелях (Quick Search, он же Fast Find), используя опять-таки описания вместо имён файлов.
Так как плагин DescSS не работает под FAR3, были написаны макросы для его замены.
  1. --[=[ ----------------------------------------------------------------------------------------------
  2.  
  3. Макросы для замены плагина DESCSS
  4.  
  5. v.1.06 (C) 2013-2016 Smitis
  6.  
  7. http://forum.farmanager.com/viewtopic.php?t=7846
  8.  
  9. --]=] ----------------------------------------------------------------------------------------------
  10.  
  11.  
  12.  
  13. ----------------------------------------------------------------------------------------------------
  14.  
  15. -- Настройки. Персональные настройки можно держать в файле DescSS.cfg (см. пример DescSS.example.cfg)
  16.  
  17. ----------------------------------------------------------------------------------------------------
  18.  
  19.  
  20.  
  21. local cfg = {}
  22.  
  23. -- Внимание! Используемый здесь AltSpace работает при наличие плагина XKeys.
  24.  
  25. -- ДЛЯ ОТКЛЮЧЕНИЯ МАКРОСОВ И ГОРЯЧИХ КЛАВИШ ОСТАВИТЬ СТРОКУ ПУСТОЙ!
  26.  
  27. cfg.sample = "" -- Пример: так отключать макросы
  28.  
  29.  
  30.  
  31. -- Макросы для установки/снятия пометки
  32.  
  33. cfg.dss_sel   = "AltShiftS" -- макрос Select
  34.  
  35. cfg.dss_unsel = "AltShiftU" -- макрос Unselect
  36.  
  37. cfg.dss_fill  = "AltShiftD" -- макрос Select with init
  38.  
  39. cfg.dss_post  = "* * Left" -- иницилизация маски для предыдущего макроса (макропоследовательность!)
  40.  
  41.  
  42.  
  43. -- Макросы быстрого поиска
  44.  
  45. cfg.dff_empty = "Alt," -- открыть пустой диалог
  46.  
  47. cfg.dff_fill  = "AltSpace" -- открыть непустой диалог
  48.  
  49. cfg.dff_text  = "*" -- иницилизация непустого диалога для предыдущего макроса (текст!)
  50.  
  51.  
  52.  
  53. -- Диалоговая процедура быстрого поиска.
  54.  
  55. -- Правые и левые модификаторы не проверяются для упрощения обработки!
  56.  
  57. -- Несколько комбинаций перечисляются через пробел, регэкспы не поддерживаются.
  58.  
  59. cfg.dff_next   = "CtrlEnter CtrlNumEnter CtrlDown" -- следующее совпадение
  60.  
  61. cfg.dff_prev   = "CtrlShiftEnter CtrlShiftNumEnter CtrlUp" -- предыдущее совпадение
  62.  
  63. cfg.dff_last   = "CtrlEnd" -- последнее совпадение
  64.  
  65. cfg.dff_first  = "CtrlHome" -- первое совпадение
  66.  
  67. cfg.dff_invert = "Ins" -- инвертировать пометку текущего файла/папки
  68.  
  69. cfg.dff_insert = "CtrlV ShiftIns" -- вставка
  70.  
  71. cfg.far    = "Esc CtrlY CtrlX CtrlC" -- отдать ФАРу
  72.  
  73. cfg.dummy  = "Left Right Ctrl Alt Shift" -- ничего не делать с этими хоткеями
  74.  
  75. cfg.search_empty = "Alt," -- выйти и открыть пустой Search
  76.  
  77. cfg.search_fill  = "AltSpace Alt." -- выйти и открыть непустой Search
  78.  
  79. cfg.search_text  = "*" -- иницилизация для непустого Search (текст!)
  80.  
  81.  
  82.  
  83. cfg.cyclic = true -- использовать циклический поиск
  84.  
  85.  
  86.  
  87. ----------------------------------------------------------------------------------------------------
  88.  
  89. -- Загрузка персональных настроек
  90.  
  91. ----------------------------------------------------------------------------------------------------
  92.  
  93. --do local f,m=loadfile(debug.getinfo(1,"S").source:match("^@(.+)%.")..".cfg")
  94.  
  95. do local f,m=loadfile((...):gsub("[^.]+$","cfg"))
  96.  
  97. if f then setfenv(f,{cfg=cfg}) if not pcall(f) then msgbox("DescSS","\nCONFIG ERROR\n ",1)
  98.  
  99. end end end
  100.  
  101.  
  102.  
  103. ----------------------------------------------------------------------------------------------------
  104.  
  105. -- Локализация
  106.  
  107. ----------------------------------------------------------------------------------------------------
  108.  
  109.  
  110.  
  111. local langs = { english = {}, russian = {} }
  112.  
  113.  
  114.  
  115. langs.english.dss_sel   = "Description Select"
  116.  
  117. langs.english.dss_unsel = "Description Unselect"
  118.  
  119. langs.english.dff_title = "Description"
  120.  
  121.  
  122.  
  123. langs.russian.dss_sel   = "Пометка по описанию"
  124.  
  125. langs.russian.dss_unsel = "Снятие пометки по описанию"
  126.  
  127. langs.russian.dff_title = "Описание"
  128.  
  129.  
  130.  
  131. ----------------------------------------------------------------------------------------------------
  132.  
  133. local F = far.Flags
  134.  
  135.  
  136.  
  137. ----------------------------------------------------------------------------------------------------
  138.  
  139. -- Выделение/снятие выделения по описаниям (Description Select/Unselect)
  140.  
  141. ----------------------------------------------------------------------------------------------------
  142.  
  143.  
  144.  
  145. local DescSSId = "5A71088D-CB13-4F43-A314-C2B4D65C3D59"
  146.  
  147. local DescSSIdB = win.Uuid(DescSSId)
  148.  
  149. far.Guids.DescriptionSelectUnselectId = DescSSId
  150.  
  151.  
  152.  
  153. local dss_recur = false
  154.  
  155. local dss_init = ""
  156.  
  157.  
  158.  
  159. -- замена mf.fmatch
  160.  
  161. local function dff_fmatch(fn,mask)
  162.  
  163.     --return mf.fmatch(fn,mask)==1
  164.  
  165.     return far.ProcessName(F.PN_CMPNAME,mask,fn)
  166.  
  167. end
  168.  
  169.  
  170.  
  171. -- Основная функция
  172.  
  173. local function descriptions_select( sel, init )
  174.  
  175.     if Area.Search then Keys "Esc" end
  176.  
  177.     local lang = langs[win.GetEnv("FARLANG"):lower()] or langs.english
  178.  
  179.     local diz
  180.  
  181.     local Title = (sel==1) and lang.dss_sel or lang.dss_unsel
  182.  
  183.     local HistName = "DSS"
  184.  
  185.     local Flags = F.FIB_ENABLEEMPTY + F.FIB_BUTTONS + (init and F.FIB_NOUSELASTHISTORY or 0)
  186.  
  187.     dss_init = init
  188.  
  189.     dss_recur = type(init)~="string"
  190.  
  191.     mask = far.InputBox(DescSSIdB,Title,"",HistName,"",nil,nil,Flags)
  192.  
  193.     if mask == nil or mask == "" then return end
  194.  
  195.     local sel_fold = cfg.selfold or Far.GetConfig("Panel.SelectFolders") -- использовать пометку папок
  196.  
  197.     for index=1,APanel.ItemCount do
  198.  
  199.         if sel_fold or band(Panel.Item(0,index,2),0x10)==0 then
  200.  
  201.             diz = Panel.Item(0,index,11)
  202.  
  203.             if diz:len() > 0 then
  204.  
  205.                 if dff_fmatch(diz,mask) then
  206.  
  207.                     Panel.Select(0,sel,1,index)
  208.  
  209.                 end
  210.  
  211.             end
  212.  
  213.         end
  214.  
  215.     end
  216.  
  217. end
  218.  
  219.  
  220.  
  221. if cfg.dss_post ~= "" and cfg.dss_fill ~= "" then
  222.  
  223.     Event { -- Установить строку иницилизации
  224.  
  225.         description="Description: Init string";
  226.  
  227.         group="DialogEvent";
  228.  
  229.         condition=function(event,param)
  230.  
  231.             if not dss_recur and event==F.DE_DLGPROCEND and param.Msg==F.DN_INITDIALOG then
  232.  
  233.                 local info = param.hDlg:send(F.DM_GETDIALOGINFO)
  234.  
  235.                 return info and info.Id==DescSSIdB
  236.  
  237.             end
  238.  
  239.         end;
  240.  
  241.         action=function(event,param)
  242.  
  243.             dss_recur = true -- исключить рекурсивный вход
  244.  
  245.             far.MacroPost('Keys("'..dss_init..'")')
  246.  
  247.         end;
  248.  
  249.     }
  250.  
  251. end
  252.  
  253.  
  254.  
  255. if cfg.dss_sel ~= "" then
  256.  
  257.     Macro { -- Выделить
  258.  
  259.         description="Description: Select";
  260.  
  261.         area="Shell Search";
  262.  
  263.         key=cfg.dss_sel;
  264.  
  265.         action=function()
  266.  
  267.             descriptions_select(1)
  268.  
  269.         end;
  270.  
  271.     }
  272.  
  273. end
  274.  
  275. if cfg.dss_fill ~= "" then
  276.  
  277.     Macro { -- Выделить с установкой начальной маски **
  278.  
  279.         description="Description: Select **";
  280.  
  281.         area="Shell Search";
  282.  
  283.         key=cfg.dss_fill;
  284.  
  285.         action=function()
  286.  
  287.             descriptions_select(1,"* * Left")
  288.  
  289.         end;
  290.  
  291.     }
  292.  
  293. end
  294.  
  295. if cfg.dss_unsel ~= "" then
  296.  
  297.     Macro { -- Снять выделение
  298.  
  299.         description="Description: Unselect";
  300.  
  301.         area="Shell Search";
  302.  
  303.         key=cfg.dss_unsel;
  304.  
  305.         action=function()
  306.  
  307.             descriptions_select(0)
  308.  
  309.         end;
  310.  
  311.     }
  312.  
  313. end
  314.  
  315.  
  316.  
  317. ----------------------------------------------------------------------------------------------------
  318.  
  319. -- Быстрый поиск по описаниям (Description Fast Find = Description Quick Search)
  320.  
  321. ----------------------------------------------------------------------------------------------------
  322.  
  323.  
  324.  
  325. local DFF_ID = "83689A78-99EA-4B01-98DE-ED8135140B20"
  326.  
  327. local DFF_GUID = win.Uuid(DFF_ID)
  328.  
  329. local dff_hdlg
  330.  
  331. local dff_mask = ""
  332.  
  333. local dff_focus = 2 -- фокус поля ввода
  334.  
  335.  
  336.  
  337. local item_property = 11
  338.  
  339.  
  340.  
  341. -- Установить текст маски в поле ввода
  342.  
  343. local function dff_print(text)
  344.  
  345.     far.SendDlgMessage(dff_hdlg,F.DM_SETTEXT,dff_focus,text)
  346.  
  347. end
  348.  
  349.  
  350.  
  351. -- Перерисовка диалога
  352.  
  353. local function dff_redraw()
  354.  
  355.     far.SendDlgMessage(dff_hdlg,F.DM_REDRAW,0,0)
  356.  
  357. end
  358.  
  359.  
  360.  
  361. -- Сравнение описания файла по маске
  362.  
  363. local function dff_match(mask,diz)
  364.  
  365.     -- При сравнении, в конец маски добавляем символ *, если его там нет
  366.  
  367.     -- Делаем фичу: непустая маска никогда не должна совпадать с пустым описанием, даже если маска *
  368.  
  369.     -- Короче, с пустым описанием может совпасть только пуская маска.
  370.  
  371.         return (diz ~= "" or mask == "" ) -- то же not (diz == "" and mask ~= "" )
  372.  
  373.     -- Заключаем всё в кавычки, что бы получить один регексп (особенность сравнения по маска mf.fmatch)
  374.  
  375.                 --and dff_fmatch(diz,'"'..((mask:sub(-1)~='*') and (mask..'*') or mask)..'"')
  376.  
  377.     -- Вариант без заключения маски в кавычки
  378.  
  379.                 and dff_fmatch(diz,(mask:sub(-1)~='*') and (mask..'*') or mask)
  380.  
  381. end
  382.  
  383.  
  384.  
  385. -- Сравнение описания файла с номером index по маске
  386.  
  387. local function dff_imatch(mask,index)
  388.  
  389.     return dff_match(mask,Panel.Item(0,index,11))
  390.  
  391. end
  392.  
  393.  
  394.  
  395. -- Поиск следующего совпадения.
  396.  
  397. -- При успехе возвращаем индекс найденного файла, иначе - 0.
  398.  
  399. local function dff_next(mask)
  400.  
  401.     local current = Panel.SetPosIdx(0,0)
  402.  
  403.     local diz
  404.  
  405.     -- со следующего и до конца
  406.  
  407.     for index=current+1, APanel.ItemCount do
  408.  
  409.         diz = Panel.Item(0,index,11)
  410.  
  411.         if diz:len() > 0 then
  412.  
  413.             if dff_match(mask,diz) then
  414.  
  415.                 return index
  416.  
  417.             end
  418.  
  419.         end
  420.  
  421.     end
  422.  
  423.     if not cfg.cyclic then return 0 end
  424.  
  425.     -- с первого до текущего
  426.  
  427.     for index=1, current do
  428.  
  429.         diz = Panel.Item(0,index,11)
  430.  
  431.         if diz:len() > 0 then
  432.  
  433.             if dff_match(mask,diz) then
  434.  
  435.                 return index
  436.  
  437.             end
  438.  
  439.         end
  440.  
  441.     end
  442.  
  443.     return 0
  444.  
  445. end
  446.  
  447.  
  448.  
  449. -- Поиск предыдущего совпадения.
  450.  
  451. -- При успехе возвращаем индекс найденного файла, иначе - 0.
  452.  
  453. local function dff_prev(mask)
  454.  
  455.     local current = Panel.SetPosIdx(0,0)
  456.  
  457.     local diz
  458.  
  459.     -- с предыдущего и до начала
  460.  
  461.     for index=current-1, 1, -1 do
  462.  
  463.         diz = Panel.Item(0,index,11)
  464.  
  465.         if diz:len() > 0 then
  466.  
  467.             if dff_match(mask,diz) then
  468.  
  469.                 return index
  470.  
  471.             end
  472.  
  473.         end
  474.  
  475.     end
  476.  
  477.     -- с последнего до текущего
  478.  
  479.     if not cfg.cyclic then return 0 end
  480.  
  481.     for index=APanel.ItemCount, current, -1 do
  482.  
  483.         diz = Panel.Item(0,index,11)
  484.  
  485.         if diz:len() > 0 then
  486.  
  487.             if dff_match(mask,diz) then
  488.  
  489.                 return index
  490.  
  491.             end
  492.  
  493.         end
  494.  
  495.     end
  496.  
  497.     return 0
  498.  
  499. end
  500.  
  501.  
  502.  
  503. -- Поиск последнего совпадения
  504.  
  505. local function dff_end(mask)
  506.  
  507.     local current = Panel.SetPosIdx(0,0)
  508.  
  509.     local diz
  510.  
  511.     for index=APanel.ItemCount, Panel.SetPosIdx(0,0), -1 do -- ??? Panel.SetPosIdx(0,0)+1
  512.  
  513.         diz = Panel.Item(0,index,11)
  514.  
  515.         if diz:len() > 0 then
  516.  
  517.             if dff_match(mask,diz) then
  518.  
  519.                 return index
  520.  
  521.             end
  522.  
  523.         end
  524.  
  525.     end
  526.  
  527.     return 0
  528.  
  529. end
  530.  
  531.  
  532.  
  533. -- Поиск первого совпадения
  534.  
  535. local function dff_home(mask)
  536.  
  537.     local diz
  538.  
  539.     for index=1, Panel.SetPosIdx(0,0) do -- ??? Panel.SetPosIdx(0,0)-1
  540.  
  541.         diz = Panel.Item(0,index,11)
  542.  
  543.         if diz:len() > 0 then
  544.  
  545.             if dff_match(mask,diz) then
  546.  
  547.                 return index
  548.  
  549.             end
  550.  
  551.         end
  552.  
  553.     end
  554.  
  555.     return 0
  556.  
  557. end
  558.  
  559.  
  560.  
  561. -- Добавление одного символа к маске
  562.  
  563. local function dff_char(char)
  564.  
  565.     local new_mask = dff_mask .. char
  566.  
  567.     local index
  568.  
  569.     if dff_imatch(new_mask,0) then
  570.  
  571.         -- Если маска совпадает с описанием текущего файла, никуда не перемещаемся
  572.  
  573.         dff_mask = new_mask
  574.  
  575.         dff_print(dff_mask)
  576.  
  577.     else
  578.  
  579.         index = dff_next(new_mask) -- следующее совпадение или 0
  580.  
  581.         if index > 0 then
  582.  
  583.             -- Если есть совпадение - переход,
  584.  
  585.             -- иначе символ никак не обрабатываем
  586.  
  587.             dff_mask = new_mask
  588.  
  589.             dff_print(dff_mask)
  590.  
  591.             Panel.SetPosIdx(0,index)
  592.  
  593.             dff_redraw()
  594.  
  595.         end
  596.  
  597.     end
  598.  
  599. end
  600.  
  601.  
  602.  
  603. -- Добавление нескольких символов к маске
  604.  
  605. local function dff_chars(chars)
  606.  
  607.     local new_mask = dff_mask
  608.  
  609.     local index
  610.  
  611.     for i=1, chars:len() do
  612.  
  613.         new_mask = new_mask .. chars:sub(i,i)
  614.  
  615.         if dff_imatch(new_mask,0) then
  616.  
  617.             -- Если маска совпадает с описанием текущего файла,
  618.  
  619.             -- никуда не перемещаемся
  620.  
  621.             dff_mask = new_mask
  622.  
  623.         else
  624.  
  625.             index = dff_next(new_mask)
  626.  
  627.             if index > 0 then
  628.  
  629.                 dff_mask = new_mask
  630.  
  631.                 Panel.SetPosIdx(0,index)
  632.  
  633.             else
  634.  
  635.                 -- если очередной символ добавить не удалось, заканчиваем вставку
  636.  
  637.                 break
  638.  
  639.             end
  640.  
  641.         end
  642.  
  643.     end
  644.  
  645.     dff_print(dff_mask)
  646.  
  647.     dff_redraw()
  648.  
  649.     return
  650.  
  651. end
  652.  
  653.  
  654.  
  655. -- Вниз
  656.  
  657. local function dff_down()
  658.  
  659.     if dff_mask:len() > 0 then
  660.  
  661.         -- При непустой маске ищем следующее совпадение
  662.  
  663.         index = dff_next(dff_mask)
  664.  
  665.         if index > 0 then
  666.  
  667.             Panel.SetPosIdx(0,index)
  668.  
  669.         end
  670.  
  671.     else
  672.  
  673.         -- При пустой маске просто перемещаемся на следующий файл
  674.  
  675.         if APanel.Eof then
  676.  
  677.             Panel.SetPosIdx(0,1)
  678.  
  679.         else
  680.  
  681.             Panel.SetPosIdx(0,Panel.SetPosIdx(0,0)+1)
  682.  
  683.         end
  684.  
  685.     end
  686.  
  687.     dff_redraw()
  688.  
  689. end
  690.  
  691.  
  692.  
  693. -- Вверх
  694.  
  695. local function dff_up()
  696.  
  697.     if dff_mask:len() > 0 then
  698.  
  699.         -- При непустой маске ищем предыдущее совпадение
  700.  
  701.         index = dff_prev(dff_mask)
  702.  
  703.         if index > 0 then
  704.  
  705.             Panel.SetPosIdx(0,index)
  706.  
  707.         end
  708.  
  709.     else
  710.  
  711.         -- При пустой маске просто перемещаемся на предыдущий файл
  712.  
  713.         if APanel.Bof then
  714.  
  715.             Panel.SetPosIdx(0,-1)
  716.  
  717.         else
  718.  
  719.             Panel.SetPosIdx(0,Panel.SetPosIdx(0,0)-1)
  720.  
  721.         end
  722.  
  723.     end
  724.  
  725.     dff_redraw()
  726.  
  727. end
  728.  
  729.  
  730.  
  731. -- Для поиска клавиши в строке клавиш
  732.  
  733. local function instr(s,k)
  734.  
  735.     return (" "..s:lower().." "):match(" "..k:lower().." ")
  736.  
  737. end
  738.  
  739.  
  740.  
  741. -- Создаём диалог
  742.  
  743. local function dff_dialog(dlg_init)
  744.  
  745.     local lang = langs[win.GetEnv("FARLANG"):lower()]
  746.  
  747.     if not lang then lang = langs.english end
  748.  
  749.     local dlg_wid = 20  -- ширина строки ввода
  750.  
  751.     local dlg_x1 = APanel.Left and 2 or PPanel.Width+2
  752.  
  753.     local dlg_x2 = dlg_x1 + dlg_wid + 2
  754.  
  755.     local dlg_y1 = APanel.Height - 1
  756.  
  757.     local dlg_y2 = dlg_y1 + 2
  758.  
  759.     local exit_key = false
  760.  
  761.     local exit_keys = false
  762.  
  763.  
  764.  
  765.     if Area.Search then Keys "Esc" end
  766.  
  767.  
  768.  
  769.     dff_mask = ""
  770.  
  771.     local dlg_items =
  772.  
  773.     {   -- X1,Y1,X2,Y2,_,sHistory,sMask,Flags,sData,...
  774.  
  775.         {F.DI_DOUBLEBOX,0,0,dlg_wid+1,2,0,0,0,0,lang.dff_title}, -- 01
  776.  
  777.         {F.DI_EDIT,     1,1,dlg_wid  ,1,0,0,0,0,dff_mask},       -- 02
  778.  
  779.     }
  780.  
  781.  
  782.  
  783.     -- Диалоговая процедура (thanks ZG за помощь)
  784.  
  785.     local function dlg_proc(hDlg,Msg,Param1,Param2)
  786.  
  787.         if Msg==F.DN_INITDIALOG then
  788.  
  789.             -- Фокус будет на единственном поле ввода
  790.  
  791.             dff_focus = far.SendDlgMessage(dff_hdlg,F.DM_GETFOCUS,0,0)
  792.  
  793.             -- Снимаем признак "неизменённый", что бы не было выделения цветом
  794.  
  795.             far.SendDlgMessage(dff_hdlg,F.DM_EDITUNCHANGEDFLAG,dff_focus,0)
  796.  
  797.             dff_chars(dlg_init) -- начальная иницилизация маски с переходом к ближайшему совпадению
  798.  
  799.             return false
  800.  
  801.  
  802.  
  803.         elseif Msg==F.DN_CONTROLINPUT and Param1==dff_focus and Param2.EventType==F.MOUSE_EVENT then
  804.  
  805.             -- отключаем события мыши, чтобы не перемещался курсор
  806.  
  807.             return true
  808.  
  809.  
  810.  
  811.         elseif Msg==F.DN_CONTROLINPUT and Param1==dff_focus and Param2.EventType==F.KEY_EVENT and Param2.KeyDown then
  812.  
  813.             local k = far.InputRecordToName(Param2) -- клавиша "as is"
  814.  
  815.             local a = k:gsub("[RL]Ctrl","Ctrl"):gsub("[RL]Alt","Alt") -- для упрощения проверки
  816.  
  817.             local mask = ""
  818.  
  819.             local index, clp
  820.  
  821.  
  822.  
  823.             if a:len()==1 then
  824.  
  825.                 -- Введён один символ
  826.  
  827.                 dff_char(a)
  828.  
  829.  
  830.  
  831.             elseif a=="Space" or a=="ShiftSpace" then
  832.  
  833.                 dff_char(" ")
  834.  
  835.  
  836.  
  837.             elseif a=="BackSlash" then
  838.  
  839.                 dff_char("\\")
  840.  
  841.  
  842.  
  843.             elseif a=="BS" then
  844.  
  845.                 -- Удаление последнего символа, перемещаться после этого не надо (совпадение уже проверенно)
  846.  
  847.                 if dff_mask:len() > 0 then
  848.  
  849.                     dff_mask = dff_mask:sub(1,-2)
  850.  
  851.                     dff_print(dff_mask)
  852.  
  853.                 end
  854.  
  855.  
  856.  
  857.             elseif instr(cfg.dff_next,a) then
  858.  
  859.                 -- Перемещение к следующему совпадению
  860.  
  861.                 dff_down()
  862.  
  863.  
  864.  
  865.             elseif instr(cfg.dff_prev,a) then
  866.  
  867.                 -- Перемещение к предыдущему совпадению
  868.  
  869.                 dff_up()
  870.  
  871.  
  872.  
  873.             elseif instr(cfg.dff_last,a) then
  874.  
  875.                 -- Перемещение к последнему совпадению
  876.  
  877.                 if dff_mask:len() > 0 then
  878.  
  879.                     index = dff_end(dff_mask)
  880.  
  881.                     if index > 0 then
  882.  
  883.                         Panel.SetPosIdx(0,index)
  884.  
  885.                     end
  886.  
  887.                 else
  888.  
  889.                     Panel.SetPosIdx(0,APanel.ItemCount)
  890.  
  891.                 end
  892.  
  893.                 dff_redraw()
  894.  
  895.  
  896.  
  897.             elseif instr(cfg.dff_first,a) then
  898.  
  899.                 -- Перемещение к первому совпадению
  900.  
  901.                 if dff_mask:len() > 0 then
  902.  
  903.                     index = dff_home(dff_mask)
  904.  
  905.                     if index > 0 then
  906.  
  907.                         Panel.SetPosIdx(0,index)
  908.  
  909.                     end
  910.  
  911.                 else
  912.  
  913.                     Panel.SetPosIdx(0,1)
  914.  
  915.                 end
  916.  
  917.                 dff_redraw()
  918.  
  919.  
  920.  
  921.             elseif instr(cfg.dff_invert,a) then
  922.  
  923.                 -- Выделить и перейти к следующему
  924.  
  925.                 Panel.Select(0,2,1)
  926.  
  927.                 dff_down()
  928.  
  929.  
  930.  
  931.             elseif instr(cfg.dff_insert,a) then
  932.  
  933.                 -- Вставка
  934.  
  935.                 clp = mf.clip(0)
  936.  
  937.                 if type(clp)=="string" and clp:len()>0 then
  938.  
  939.                     dff_chars(clp)
  940.  
  941.                 end
  942.  
  943.  
  944.  
  945.             elseif instr(cfg.far,a) then
  946.  
  947.                 -- для обработки возвращаем управление ФАРу
  948.  
  949.                 return false
  950.  
  951.  
  952.  
  953.             elseif instr(cfg.dummy,a) then
  954.  
  955.                 -- Ничего не делаем
  956.  
  957.  
  958.  
  959.             elseif instr(cfg.search_empty,a) then
  960.  
  961.                 -- Перейти к обычному Search
  962.  
  963.                 exit_keys = "Alt<" -- комбинация клавиш, вызывающая обычный Search
  964.  
  965.                 far.SendDlgMessage(hDlg,F.DM_CLOSE)
  966.  
  967.  
  968.  
  969.             elseif instr(cfg.search_fill,a) then
  970.  
  971.                 -- Перейти к Search
  972.  
  973.                 exit_keys = "Alt< " .. cfg.search_text
  974.  
  975.                 far.SendDlgMessage(hDlg,F.DM_CLOSE)
  976.  
  977.  
  978.  
  979.             else
  980.  
  981.                 exit_key = k
  982.  
  983.                 far.SendDlgMessage(hDlg,F.DM_CLOSE)
  984.  
  985.  
  986.  
  987.             end
  988.  
  989.             return true
  990.  
  991.         end
  992.  
  993.     end -- dlg_proc
  994.  
  995.  
  996.  
  997.     local dlg_flags = F.FDLG_KEEPCONSOLETITLE + F.FDLG_NODRAWSHADOW + F.FDLG_SMALLDIALOG
  998.  
  999.     dff_hdlg = far.DialogInit(DFF_GUID,dlg_x1,dlg_y1,dlg_x2,dlg_y2,"",dlg_items,dlg_flags,dlg_proc)
  1000.  
  1001.     far.DialogRun(dff_hdlg)
  1002.  
  1003.     far.DialogFree(dff_hdlg)
  1004.  
  1005.     if exit_keys then
  1006.  
  1007.         Keys(exit_keys)
  1008.  
  1009.     elseif exit_key then
  1010.  
  1011.         if eval(exit_key,2)==-2 then
  1012.  
  1013.             Keys(exit_key)
  1014.  
  1015.         end
  1016.  
  1017.     end
  1018.  
  1019. end
  1020.  
  1021.  
  1022.  
  1023. -- Макросы
  1024.  
  1025.  
  1026.  
  1027. if cfg.dff_empty ~= "" then
  1028.  
  1029.     Macro { -- Вызов диалога быстрого поиска
  1030.  
  1031.         description="Description: Fast Find";
  1032.  
  1033.         area="Shell Search";
  1034.  
  1035.         key=cfg.dff_empty;
  1036.  
  1037.         action=function() dff_dialog("") end;
  1038.  
  1039.     }
  1040.  
  1041. end
  1042.  
  1043. if cfg.dff_fill ~= "" then
  1044.  
  1045.     Macro { -- Вызов диалога быстрого поиска с начальной маской
  1046.  
  1047.         description="Description: Fast Find";
  1048.  
  1049.         area="Shell Search";
  1050.  
  1051.         key=cfg.dff_fill;
  1052.  
  1053.         action=function() dff_dialog(cfg.dff_text) end;
  1054.  
  1055.     }
  1056.  
  1057. end
  1058.  
  1059. ----------------------------------------------------------------------------------------------------
Пример файла конфигурации
  1. --[[ -----------------------------------------------------------------------------------------------
  2.  
  3.     Пример файла конфигурации для макросов DescSS.
  4.  
  5.     Файл должен лежать в той же папке, что и файл макросов, иметь тоже имя и расширение cfg.
  6.  
  7.     По умолчанию, если основной скрипт не переименован, имя должно быть DescSS.cfg
  8.  
  9.  
  10.  
  11.     Файл конфигурации представляет собой скрипт Lua. Если файл содержит синтаксические ошибки
  12.  
  13.     и не может быть обработам интерпретатором Lua, будет выдано сообщение:
  14.  
  15.  
  16.  
  17.     ╔═══ DescSS ═══╗
  18.  
  19.     ║              ║
  20.  
  21.     ║ CONFIG ERROR ║
  22.  
  23.     ║              ║
  24.  
  25.     ╟──────────────╢
  26.  
  27.     ║    { OK }    ║
  28.  
  29.     ╚══════════════╝
  30.  
  31.  
  32.  
  33.     Если файл конфигурации отсутствует или содержит ошибки, будут использованны значения по умолчанию,
  34.  
  35.     заданные в основном скрипте. В случае отсутствия каких-либо параметров (например, они будут
  36.  
  37.     закоментированы), вместо них также будут использованы значения по умолчанию.
  38.  
  39.  
  40.  
  41.     В диалоговой процедуре правые и левые модификаторы не проверяются для упрощения обработки,
  42.  
  43.     регэкспы не поддерживаются.
  44.  
  45.  
  46.  
  47.     Внимание! Используемый здесь AltSpace работает при наличие плагина XKeys.
  48.  
  49.  
  50.  
  51.     ДЛЯ ОТКЛЮЧЕНИЯ МАКРОСОВ И ГОРЯЧИХ КЛАВИШ ОСТАВИТЬ СТРОКУ В КОВЫЧКАХ ПУСТОЙ!
  52.  
  53.  
  54.  
  55. cfg.sample = "" -- Пример: так отключать макросы
  56.  
  57.  
  58.  
  59. --]] -----------------------------------------------------------------------------------------------
  60.  
  61.  
  62.  
  63. -- Макросы для установки/снятия пометки
  64.  
  65.  
  66.  
  67. cfg.dss_sel   = "AltShiftS" -- макрос Select
  68.  
  69. cfg.dss_unsel = "AltShiftU" -- макрос Unselect
  70.  
  71. cfg.dss_fill  = "AltShiftD" -- макрос Select with init
  72.  
  73. cfg.dss_post  = "* * Left" -- иницилизация маски для предыдущего макроса (макропоследовательность!)
  74.  
  75.  
  76.  
  77. -- Макросы быстрого поиска
  78.  
  79.  
  80.  
  81. cfg.dff_empty = "Alt," -- открыть пустой диалог
  82.  
  83. cfg.dff_fill  = "AltSpace Alt." -- открыть непустой диалог
  84.  
  85. cfg.dff_text  = "*" -- иницилизация непустого диалога для предыдущего макроса (текст!)
  86.  
  87.  
  88.  
  89. -- Диалоговая процедура быстрого поиска.
  90.  
  91. -- Правые и левые модификаторы не проверяются, регэкспы не поддерживаются!
  92.  
  93.  
  94.  
  95. cfg.dff_next   = "CtrlEnter CtrlNumEnter CtrlDown" -- следующее совпадение
  96.  
  97. cfg.dff_prev   = "CtrlShiftEnter CtrlShiftNumEnter CtrlUp" -- предыдущее совпадение
  98.  
  99. cfg.dff_last   = "CtrlEnd" -- последнее совпадение
  100.  
  101. cfg.dff_first  = "CtrlHome" -- первое совпадение
  102.  
  103. cfg.dff_invert = "Ins" -- инвертировать пометку текущего файла/папки
  104.  
  105. cfg.dff_insert = "CtrlV ShiftIns" -- вставка
  106.  
  107. cfg.far    = "Esc CtrlY CtrlX CtrlC" -- отдать ФАРу
  108.  
  109. cfg.dummy  = "Left Right Ctrl Alt Shift" -- ничего не делать с этими хоткеями
  110.  
  111. cfg.search_empty = "Alt," -- выйти и открыть пустой Search
  112.  
  113. cfg.search_fill  = "AltSpace Alt." -- выйти и открыть непустой Search
  114.  
  115. cfg.search_text  = "*" -- иницилизация для непустого Search (текст!)
  116.  
  117.  
  118.  
  119. -- прочее
  120.  
  121.  
  122.  
  123. cfg.cyclic = true -- использовать циклический поиск
  124.  
  125.  
  126.  
  127. ----------------------------------------------------------------------------------------------------
Прочие макросы для работы с описаниями.

Обычный CtrlZ, если есть отмеченные файлы/папки, выполняется поочерёдно для них всех. Сколько лет пользуюсь описаниями, ни разу не понадобилось такая "пакетная" обработка. Поэтому были написаны макросы для работы только с описанием текущего файла и сохраняющие пометку. Дополнительно, макросы сохраняют предыдущее непустое описание при изменении/удалении, которое может быть восстановлено.

С версии 1.03 макрос CtrlZ был переименован в DescriptionEdit. Не забудьте удалить старый CtrlZ.lua!
  1. ----------------------------------------------------------------------------------------------------
  2.  
  3. -- Работа с описаниями файлов
  4.  
  5. -- v.1.03 (C) 2013-2016 Smitis
  6.  
  7. ----------------------------------------------------------------------------------------------------
  8.  
  9.  
  10.  
  11. local F = far.Flags
  12.  
  13. local diz_prev = ""
  14.  
  15.  
  16.  
  17. ----------------------------------------------------------------------------------------------------
  18.  
  19. -- Замена стандартного диалога редактирования.
  20.  
  21. -- Редактируется описание только текущего элемента панелей, не зависимо от выделения.
  22.  
  23. -- Выделение сохраняется/восстанавливается через внутренний буфер. Откат через CtrlM теряется.
  24.  
  25. ----------------------------------------------------------------------------------------------------
  26.  
  27.  
  28.  
  29. local DescriptionEditId = "1B8B8080-09EE-4AB2-B723-1014C1C0A97E"
  30.  
  31. local DescriptionEditIdB = win.Uuid(DescriptionEditId)
  32.  
  33. --far.Guids.DescriptionEditId = DescriptionEditId
  34.  
  35.  
  36.  
  37. local diz_changed = false
  38.  
  39.  
  40.  
  41. local function diz_edit(init,changed)
  42.  
  43.     if Area.Search then Keys "Esc" end
  44.  
  45.  
  46.  
  47.     local selected = APanel.Selected
  48.  
  49.     local diz = Panel.Item(0,0,11)
  50.  
  51.     if init and type(init)=="string" then
  52.  
  53.         diz = init
  54.  
  55.     end
  56.  
  57.     diz_changed = changed
  58.  
  59.     local Title = "Describe file"
  60.  
  61.     local Prompt = "Enter description for " .. APanel.Current .. ":"
  62.  
  63.     local HistName = "DizText"
  64.  
  65.     local Flags = F.FIB_ENABLEEMPTY + F.FIB_BUTTONS + F.FIB_NOUSELASTHISTORY
  66.  
  67.     local diz_new = far.InputBox(DescriptionEditIdB,Title,Prompt,HistName,diz,nil,nil,Flags)
  68.  
  69.     if diz_new then
  70.  
  71.         diz_new = diz_new:gsub("^%s+",""):gsub("%s+$","") -- trim
  72.  
  73.         mf.clip(5,2)
  74.  
  75.         diz_prev = diz
  76.  
  77.         if selected then -- сохранить выделение
  78.  
  79.             Keys "CtrlShiftIns"
  80.  
  81.             Panel.Select(0,0)
  82.  
  83.         end
  84.  
  85.         Keys "CtrlZ"
  86.  
  87.         print(diz_new)
  88.  
  89.         Keys "Enter"
  90.  
  91.         if selected then -- восстановить выделение
  92.  
  93.             Panel.Select(0,1,2,mf.clip(0))
  94.  
  95.         end
  96.  
  97.     end
  98.  
  99. end
  100.  
  101. ----------------------------------------------------------------------------------------------------
  102.  
  103. Event { -- сделать поле ввода "изменённое" для некоторых операций
  104.  
  105.     description="Description: Make unchanged";
  106.  
  107.     group="DialogEvent";
  108.  
  109.     condition=function(event,param)
  110.  
  111.         return event == F.DE_DLGPROCINIT
  112.  
  113.                 and param.Msg == F.DN_DRAWDIALOGDONE
  114.  
  115.                 and diz_changed
  116.  
  117.                 and Dlg.Id == DescriptionEditId
  118.  
  119.     end;
  120.  
  121.     action=function(event,param)
  122.  
  123.         diz_changed = false -- исключить рекурсивный вход
  124.  
  125.         far.MacroPost('Keys("End")')
  126.  
  127.     end;
  128.  
  129. }
  130.  
  131. ----------------------------------------------------------------------------------------------------
  132.  
  133. Macro { --  Описание только одного файла
  134.  
  135.     description="Description: Edit";
  136.  
  137.     area="Shell Search";
  138.  
  139.     key="CtrlZ";
  140.  
  141.     action=function()
  142.  
  143.         diz_edit()
  144.  
  145.     end;
  146.  
  147. }
  148.  
  149. ----------------------------------------------------------------------------------------------------
  150.  
  151. Macro { --  Копирование описания в буфер обмена
  152.  
  153.     description="Description: Copy to clipboard";
  154.  
  155.     area="Shell Search";
  156.  
  157.     key="AltC";
  158.  
  159.     action=function()
  160.  
  161.         if Area.Search then Keys "Esc" end
  162.  
  163.         mf.clip(1,Panel.Item(0,0,11))
  164.  
  165.     end;
  166.  
  167. }
  168.  
  169. ----------------------------------------------------------------------------------------------------
  170.  
  171. Macro { --  Новое описание из буфера обмена
  172.  
  173.     description="Description: New from clipboard";
  174.  
  175.     area="Shell Search";
  176.  
  177.     key="AltZ";
  178.  
  179.     action=function()
  180.  
  181.         diz_edit(mf.clip(0),true)
  182.  
  183.     end;
  184.  
  185. }
  186.  
  187. ----------------------------------------------------------------------------------------------------
  188.  
  189. Macro { --  Добавить описание из буфера обмена к текущему описанию через пробел.
  190.  
  191.     description="Description: Append from clipboard";
  192.  
  193.     area="Shell Search";
  194.  
  195.     key="AltV";
  196.  
  197.     action=function()
  198.  
  199.         if Area.Search then Keys "Esc" end
  200.  
  201.         local diz = Panel.Item(0,0,11)
  202.  
  203.         if diz:len() > 0 then
  204.  
  205.             diz_edit(diz.." "..mf.clip(0),true)
  206.  
  207.         else
  208.  
  209.             diz_edit(mf.clip(0),true)
  210.  
  211.         end
  212.  
  213.     end;
  214.  
  215. }
  216.  
  217. ----------------------------------------------------------------------------------------------------
  218.  
  219. Macro { --  Удалить описание в буфер обмена
  220.  
  221.     description="Description: Cut to clipboard";
  222.  
  223.     area="Shell Search";
  224.  
  225.     key="AltX";
  226.  
  227.     action=function()
  228.  
  229.         if Area.Search then Keys "Esc" end
  230.  
  231.         local diz = Panel.Item(0,0,11)
  232.  
  233.         if diz:len() > 0 then
  234.  
  235.             mf.clip(1,diz)
  236.  
  237.             local selected = APanel.Selected
  238.  
  239.             mf.clip(5,2)
  240.  
  241.             if selected then
  242.  
  243.                 Keys "CtrlShiftIns"
  244.  
  245.                 Panel.Select(0,0)
  246.  
  247.             end
  248.  
  249.             Keys "CtrlZ CtrlY Enter"
  250.  
  251.             if selected then
  252.  
  253.                 Panel.Select(0,1,2,mf.clip(0))
  254.  
  255.             end
  256.  
  257.         end
  258.  
  259.     end;
  260.  
  261. }
  262.  
  263. ----------------------------------------------------------------------------------------------------
  264.  
  265. Macro { --  Удалить описание
  266.  
  267.     description="Description: Delete";
  268.  
  269.     area="Shell Search";
  270.  
  271.     key="AltD";
  272.  
  273.     action=function()
  274.  
  275.         if Area.Search then Keys "Esc" end
  276.  
  277.         local diz = Panel.Item(0,0,11)
  278.  
  279.         if diz:len() > 0 then
  280.  
  281.             diz_prev = diz
  282.  
  283.             local selected = APanel.Selected
  284.  
  285.             mf.clip(5,2)
  286.  
  287.             if selected then
  288.  
  289.                 Keys "CtrlShiftIns"
  290.  
  291.                 Panel.Select(0,0)
  292.  
  293.             end
  294.  
  295.             Keys "CtrlZ CtrlY Enter"
  296.  
  297.             if selected then
  298.  
  299.                 Panel.Select(0,1,2,mf.clip(0))
  300.  
  301.             end
  302.  
  303.         end
  304.  
  305.     end;
  306.  
  307. }
  308.  
  309. ----------------------------------------------------------------------------------------------------
  310.  
  311. Macro { --  Восстановить описание
  312.  
  313.     description="Description: Restore";
  314.  
  315.     area="Shell Search";
  316.  
  317.     key="AltShiftZ";
  318.  
  319.     action=function()
  320.  
  321.         diz_edit(diz_prev)
  322.  
  323.     end;
  324.  
  325. }
  326.  
  327. ----------------------------------------------------------------------------------------------------
Макросы DescriptionMultiEdit являются модификацией макросов DescriptionEdit с добавленной функцией редактирования во встроенном редакторе многострочных описаний, поддерживаемых Total Commander. Вызывается из диалога изменения описаний по F4. По поводу кривизны этих многострочных описаний я уже высказался в этой теме и смежной.
СОВМЕСТИМОСТЬ С TC ТОЛЬКО ДЛЯ ОПИСАНИЙ В ANSI КОДИРОВКЕ!
Эти макросы требуют для работы модуль DialogClass
Нумерация версий совпадает с DescriptionEdit.
  1. --[=[ ------------------------------------------------------------------------------------------------------------------
  2.  
  3. Работа с описаниями файлов, в том числе и с многострочными
  4.  
  5. v.1.03 (C) 2013-2016 Smitis
  6.  
  7. Приватная версия с дополнительным полем с именем файла.
  8.  
  9.  
  10.  
  11. - Замена стандартного диалога редактирования.
  12.  
  13. - Редактируется описание только текущего элемента панелей, не зависимо от выделения (Выделение сохраняется/восстанавливается через внутренний буфер. Восстановление предыдущего выделения через CtrlM теряется.)
  14.  
  15. - Возможность редактирования многострочных описаний.
  16.  
  17.  
  18.  
  19. Для работы требуется модуль DialogClass
  20.  
  21.     http://forum.farmanager.com/viewtopic.php?t=8523
  22.  
  23. Обсуждение макросов для работы с описаниями
  24.  
  25.     http://forum.farmanager.com/viewtopic.php?t=7846
  26.  
  27. Обсуждение многострочного редактора описаний
  28.  
  29.     http://forum.farmanager.com/viewtopic.php?t=285
  30.  
  31. --]=] ------------------------------------------------------------------------------------------------------------------
  32.  
  33.  
  34.  
  35. local F = far.Flags
  36.  
  37. local dialog = require 'DialogClass'
  38.  
  39.  
  40.  
  41. ------------------------------------------------------------------------------------------------------------------------
  42.  
  43.  
  44.  
  45. local DescriptionMultiEditId = "75CA1288-4C06-4621-870E-A4FDD9E7319E"
  46.  
  47. --far.Guids.DescriptionMultiEditId = DescriptionMultiEditId
  48.  
  49.  
  50.  
  51. local HistoryLimitLen = 80 -- описания длиней чем HistoryLimitLen в историю добавляться не будут
  52.  
  53. local DescriptionPrev = ""
  54.  
  55.  
  56.  
  57. ------------------------------------------------------------------------------------------------------------------------
  58.  
  59. -- Редактирование в окне с рамкой
  60.  
  61. local MultiEditId = "736B91DE-2525-4296-9529-F0BAD8503B57"
  62.  
  63. --far.Guids.MultiEditId = MultiEditId
  64.  
  65. local function MultiEdit(x1,y1,x2,y2,text,title)
  66.  
  67.     dialog.New {
  68.  
  69.         Guid = MultiEditId,
  70.  
  71.         X1=x1, Y1=y1, X2=x2, Y2=y2, Frame=2,
  72.  
  73.         DlgProc = function(hDlg,Msg,Param1,Param2,D,DI)
  74.  
  75.             local coord, hfile, tmpfile
  76.  
  77.             if Msg==F.DN_DRAWDIALOGDONE then
  78.  
  79.                 coord = D:Send(F.DM_GETDLGRECT,0,0)
  80.  
  81.                 tmpfile = far.MkTemp()
  82.  
  83.                 hfile = io.open(tmpfile,"w") hfile:write(text) hfile:close()
  84.  
  85.                 editor.Editor(tmpfile,title,coord.Left+4,coord.Top+2,coord.Right-4,coord.Bottom-2, bor(F.EF_DISABLEHISTORY,F.EF_DISABLESAVEPOS),0,0,65001)
  86.  
  87.                 hfile = io.open(tmpfile,"r") text = hfile:read("*a") hfile:close()
  88.  
  89.                 win.DeleteFile(tmpfile)
  90.  
  91.                 D:Send(F.DM_CLOSE)
  92.  
  93.             end
  94.  
  95.         end
  96.  
  97.     } ()
  98.  
  99.     return text
  100.  
  101. end
  102.  
  103. ------------------------------------------------------------------------------------------------------------------------
  104.  
  105. local idtc = win.Utf16ToUtf8(win.MultiByteToWideChar(unicode.ascii.char(0x04,0xC2),win.GetACP())) -- идентификатор TC в UTF-8
  106.  
  107. local function DescriptionEdit(init,changed)
  108.  
  109.     local Selected = APanel.Selected
  110.  
  111.     local Description = Panel.Item(0,0,11)
  112.  
  113.     local HistoryName = "DizText"
  114.  
  115.     local FileName = APanel.Current
  116.  
  117.  
  118.  
  119.     if Area.Search then Keys "Esc" end
  120.  
  121.  
  122.  
  123.     local D,DI = dialog.New {
  124.  
  125.         Guid = DescriptionMultiEditId,
  126.  
  127.         Title = "Describe file",
  128.  
  129.         W=76, H=8,
  130.  
  131.         DlgProc = function(hDlg,Msg,Param1,Param2,D,DI)
  132.  
  133.             if Msg==F.DN_INITDIALOG then
  134.  
  135.                 -- для некоторых макросов требуется, чтобы поле не было "неизменённое"
  136.  
  137.                 if changed then
  138.  
  139.                     DI.Description:Unchanged(0)
  140.  
  141.                 end
  142.  
  143.             elseif Msg==F.DN_CLOSE then
  144.  
  145.                 -- не записываем в историю пустые, слишком большие и многострочные описания
  146.  
  147.                 local text = DI.Description:GetText()
  148.  
  149.                 if text~="" and text:len()<=HistoryLimitLen and text:find('\n')==nil then
  150.  
  151.                     DI.Description:Send(F.DM_ADDHISTORY,text)
  152.  
  153.                 end
  154.  
  155.                 return true
  156.  
  157.             elseif Msg==F.DN_CONTROLINPUT and Param2.EventType==F.KEY_EVENT and Param2.KeyDown then
  158.  
  159.                 local k = far.InputRecordToName(Param2):gsub('[RL]Ctrl','Ctrl')
  160.  
  161.                 if k=="CtrlE" or k=="F4" then
  162.  
  163.                     local coord = D:Send(F.DM_GETDLGRECT,0,0)
  164.  
  165.                     --local text = DI.Description:GetText():gsub('\x02',''):gsub('\x03','\n')
  166.  
  167.                     local text = DI.Description:GetText()
  168.  
  169.                     if text:sub(-2)==idtc then -- проверка частичная, так как мы не знаем, из какой кодировки конвертировали в юникод
  170.  
  171.                         idsymbol = text:sub(-1) -- это то, во что был преобразован id после конвертирования ANSI->UNICODE
  172.  
  173.                         text = text:sub(1,-3):gsub('(\\*\\n)',
  174.  
  175.                             function(s)
  176.  
  177.                                 if s:sub(1,-3):len()%2==0 then
  178.  
  179.                                     return s:sub(1,-3)..'\n' -- перед \n чётное число или 0 символов \
  180.  
  181.                                 end
  182.  
  183.                                 return s
  184.  
  185.                             end
  186.  
  187.                         ):gsub('\\\\','\\')
  188.  
  189.                     end
  190.  
  191.                     local newtext = MultiEdit(coord.Left,coord.Top-5,coord.Right,coord.Bottom+5,text,"Description Edit")
  192.  
  193.                     if newtext ~= text then
  194.  
  195.                         if newtext:find('\n') then
  196.  
  197.                             newtext = newtext:gsub('\\','\\\\'):gsub('\n','\\n')..idtc
  198.  
  199.                         end
  200.  
  201.                         DI.Description:SetText(newtext)
  202.  
  203.                     end
  204.  
  205.                     return true
  206.  
  207.                 end
  208.  
  209.             end
  210.  
  211.         end,
  212.  
  213.         Items = {
  214.  
  215.             {"t+", Text="Description:"},
  216.  
  217.             {"emh+@", Name="Description", Text=init or Description, History=HistoryName},
  218.  
  219.             {"s+"},
  220.  
  221.             {"b=!+", Name="OK"},
  222.  
  223.             {"b=", Name="Cancel"},
  224.  
  225.         },
  226.  
  227.     }
  228.  
  229.     D()
  230.  
  231.     if D.Ret ~= -1 and D.Ret ~= DI.Cancel.Id then
  232.  
  233.         if DI.Description.Text ~= Description then
  234.  
  235.             DescriptionPrev = Description
  236.  
  237.             Description = DI.Description.Text:gsub("^%s+",""):gsub("%s+$","") -- trim
  238.  
  239.             mf.clip(5,2)
  240.  
  241.             if Selected then -- сохранить выделение
  242.  
  243.                 Keys "CtrlShiftIns"
  244.  
  245.                 Panel.Select(0,0)
  246.  
  247.             end
  248.  
  249.             Far.DisableHistory(-1) -- добавляются в DlgProc
  250.  
  251.             Keys "CtrlZ"
  252.  
  253.             print(Description)
  254.  
  255.             Keys "Enter"
  256.  
  257.             if Selected then -- восстановить выделение
  258.  
  259.                 Panel.Select(0,1,2,mf.clip(0))
  260.  
  261.             end
  262.  
  263.         end
  264.  
  265.     end
  266.  
  267. end
  268.  
  269. ------------------------------------------------------------------------------------------------------------------------
  270.  
  271. Macro { --  Описание
  272.  
  273.     description="Description";
  274.  
  275.     area="Shell Search";
  276.  
  277.     key="CtrlAltZ";
  278.  
  279.     action=function()
  280.  
  281.         Keys "CtrlZ"
  282.  
  283.     end;
  284.  
  285. }
  286.  
  287. ------------------------------------------------------------------------------------------------------------------------
  288.  
  289. Macro { --  Описание только одного файла
  290.  
  291.     description="Description: Edit";
  292.  
  293.     area="Shell Search";
  294.  
  295.     key="CtrlZ";
  296.  
  297.     action=function()
  298.  
  299.         DescriptionEdit()
  300.  
  301.     end;
  302.  
  303. }
  304.  
  305. ------------------------------------------------------------------------------------------------------------------------
  306.  
  307. Macro { --  Копирование описания в буфер обмена
  308.  
  309.     description="Description: Copy to clipboard";
  310.  
  311.     area="Shell Search";
  312.  
  313.     key="AltC";
  314.  
  315.     action=function()
  316.  
  317.         if Area.Search then Keys "Esc" end
  318.  
  319.         mf.clip(1,Panel.Item(0,0,11))
  320.  
  321.     end;
  322.  
  323. }
  324.  
  325. ------------------------------------------------------------------------------------------------------------------------
  326.  
  327. Macro { --  Новое описание из буфера обмена
  328.  
  329.     description="Description: New from clipboard";
  330.  
  331.     area="Shell Search";
  332.  
  333.     key="AltZ";
  334.  
  335.     action=function()
  336.  
  337.         if Area.Search then Keys "Esc" end
  338.  
  339.         local Clipboard = mf.clip(0)
  340.  
  341.         if type(Clipboard)=="string" then
  342.  
  343.             DescriptionEdit(Clipboard:gsub("[\r\n]+"," "),true)
  344.  
  345.         end
  346.  
  347.     end;
  348.  
  349. }
  350.  
  351. ------------------------------------------------------------------------------------------------------------------------
  352.  
  353. Macro { --  Добавить описание из буфера обмена к текущему описанию через пробел.
  354.  
  355.     description="Description: Append from clipboard";
  356.  
  357.     area="Shell Search";
  358.  
  359.     key="AltV";
  360.  
  361.     action=function()
  362.  
  363.         if Area.Search then Keys "Esc" end
  364.  
  365.         local Clipboard = mf.clip(0)
  366.  
  367.         if type(Clipboard)=="string" and Clipboard:len()>0 then
  368.  
  369.             local Description = Panel.Item(0,0,11)
  370.  
  371.             if Description:len() > 0 then
  372.  
  373.                 DescriptionEdit(Description.." "..Clipboard:gsub("[\r\n]+"," "),true)
  374.  
  375.             else
  376.  
  377.                 DescriptionEdit(Clipboard,true)
  378.  
  379.             end
  380.  
  381.         end
  382.  
  383.     end;
  384.  
  385. }
  386.  
  387. ------------------------------------------------------------------------------------------------------------------------
  388.  
  389. Macro { --  Удалить описание в буфер обмена. Это описание не будет помещено в DescriptionPrev
  390.  
  391.     description="Description: Cut to clipboard";
  392.  
  393.     area="Shell Search";
  394.  
  395.     key="AltX";
  396.  
  397.     action=function()
  398.  
  399.         if Area.Search then Keys "Esc" end
  400.  
  401.         local Description = Panel.Item(0,0,11)
  402.  
  403.         if Description:len() > 0 then
  404.  
  405.             Far.DisableHistory(-1) -- пустое описание не будет добавлено в историю
  406.  
  407.             mf.clip(1,Description)
  408.  
  409.             local selected = APanel.Selected
  410.  
  411.             mf.clip(5,2)
  412.  
  413.             if selected then
  414.  
  415.                 Keys "CtrlShiftIns"
  416.  
  417.                 Panel.Select(0,0)
  418.  
  419.             end
  420.  
  421.             Keys "CtrlZ CtrlY Enter"
  422.  
  423.             if selected then
  424.  
  425.                 Panel.Select(0,1,2,mf.clip(0))
  426.  
  427.             end
  428.  
  429.         end
  430.  
  431.     end;
  432.  
  433. }
  434.  
  435. ------------------------------------------------------------------------------------------------------------------------
  436.  
  437. Macro { --  Удалить описание. Это описание будет помещено в DescriptionPrev
  438.  
  439.     description="Description: Delete";
  440.  
  441.     area="Shell Search";
  442.  
  443.     key="AltD";
  444.  
  445.     action=function()
  446.  
  447.         if Area.Search then Keys "Esc" end
  448.  
  449.         local Description = Panel.Item(0,0,11)
  450.  
  451.         if Description:len() > 0 then
  452.  
  453.             Far.DisableHistory(-1) -- пустое описание не будет добавлено в историю
  454.  
  455.             DescriptionPrev = Description
  456.  
  457.             local selected = APanel.Selected
  458.  
  459.             mf.clip(5,2)
  460.  
  461.             if selected then
  462.  
  463.                 Keys "CtrlShiftIns"
  464.  
  465.                 Panel.Select(0,0)
  466.  
  467.             end
  468.  
  469.             Keys "CtrlZ CtrlY Enter"
  470.  
  471.             if selected then
  472.  
  473.                 Panel.Select(0,1,2,mf.clip(0))
  474.  
  475.             end
  476.  
  477.         end
  478.  
  479.     end;
  480.  
  481. }
  482.  
  483. ------------------------------------------------------------------------------------------------------------------------
  484.  
  485. Macro { --  Восстановить описание
  486.  
  487.     description="Description: Restore";
  488.  
  489.     area="Shell Search";
  490.  
  491.     key="AltShiftZ";
  492.  
  493.     action=function()
  494.  
  495.         DescriptionEdit(DescriptionPrev)
  496.  
  497.     end;
  498.  
  499. }
  500.  
  501. ------------------------------------------------------------------------------------------------------------------------
Attachments
descss.1.06.7z
DescSS 1.06
(5.72 KiB) Downloaded 139 times
DescriptionEdit.1.03.7z
DescriptionEdit (CtrlZ) 1.03
(1.53 KiB) Downloaded 152 times
DescriptionMultiEdit.1.03.7z
DescriptionMultiEdit 1.03
(2.85 KiB) Downloaded 138 times
Last edited by HaRT on Mon 26 Oct, 2020 20:53, edited 1 time in total.
Reason: Исправлены ошибки в правописании (кроме кода скриптов)
User avatar
Smitis
Posts: 1709
Joined: Fri 18 Mar, 2005 12:51
Location: Питер
Has thanked: 23 times
Been thanked: 55 times

Re: DescSS — поиск и выделение по описаниям файлов

Post by Smitis »

В принципе, плагин можно заменить и макросами.
Простейшие операции плагина - выделение и снятие выделения получаются просто:

Смущает одно - не знаю, как ФАР обновляет внутренюю информацию о файлах, и что будет если, например, где-то между строчками Panel.Item и Panel.Select изменится количество файлов и их описание (по закону подлости) и в момент select индекс проверяемого файла уже будет другим.

П.С.
С макрос для description search будет позамысловатее, но тоже возможен.

П.П.С.
Вроде, эксперимент показывает, что во время выполнения макроса информация не обновляется.
Разум когда-нибудь победит.
User avatar
Smitis
Posts: 1709
Joined: Fri 18 Mar, 2005 12:51
Location: Питер
Has thanked: 23 times
Been thanked: 55 times

Re: DescSS — поиск и выделение по описаниям файлов

Post by Smitis »

Тигрёнок wrote:Было бы здорово.
С наскока не получилось... :(
Разум когда-нибудь победит.
User avatar
Smitis
Posts: 1709
Joined: Fri 18 Mar, 2005 12:51
Location: Питер
Has thanked: 23 times
Been thanked: 55 times

Re: DescSS — поиск и выделение по описаниям файлов

Post by Smitis »

Вот такое вот... DescriptionFastFind в первом приближении. Куча недостатков, багов и пр. Любая критика принимается.
Думаю, что обработку клавиш лучше организовать не макросами, а через DlgProc диалога, но пока не получается.

П.С. Нет обработки всяких CtrlV, CtrlX, CtrlY и пр.
Разум когда-нибудь победит.
User avatar
Тигрёнок
Posts: 391
Joined: Wed 03 May, 2006 06:07
Location: Россия
Contact:

Re: DescSS — поиск и выделение по описаниям файлов

Post by Тигрёнок »

Я пока не всё вкурил, поэтому буду задавать мелкие вопросы по ходу (в т.ч. и по lua).
1) Зачем создавать maskx? Нельзя ли результат класть в mask (она же локальная для dss_match)?
2) Зачем объявлять через local индекс цикла for?
3) Как Вы надыбали такие чудесные конструкции как #diz для длины и dss_mask:sub(-1,-1) для подстроки? Они же не документированы...
4) local dlg_flags = F.FDLG_KEEPCONSOLETITLE + F.FDLG_NODRAWSHADOW + F.FDLG_SMALLDIALOG у меня прекрасно даёт диалог без тени. Единственное, я бы обрез ему габариты до размеров диалога поиска.
5) Что за странные клавиши в описании Macro { area="Dialog"; key="/.+/"; ?
Съешь мыша – стань настоящим клавишником!
User avatar
Smitis
Posts: 1709
Joined: Fri 18 Mar, 2005 12:51
Location: Питер
Has thanked: 23 times
Been thanked: 55 times

Re: DescSS — поиск и выделение по описаниям файлов

Post by Smitis »

Тигрёнок
1) mask это переданный параметр в функцию, а maskx это mask.."*" (что бы срабатывало условие mf.fmatch)
2) да как-то принято объявлять локальные переменные как локальные :)
3) это обычные конструкции Lua (встроенные)
4) Да, без тени, это что-то ночью меня глючило. И согласен, диалог надо обрезать (у себя уже обрезал), но сделал чуть длинее диалога Search
5) Это перехват ВСЕХ клавиш через регулярное выражение. Это то, что на данный момент мне очень не нравится.
Разум когда-нибудь победит.
Shmuel
Posts: 6819
Joined: Thu 23 Mar, 2006 21:36
Location: Israel
Has thanked: 41 times
Been thanked: 528 times

Re: DescSS — поиск и выделение по описаниям файлов

Post by Shmuel »

Тигрёнок wrote:Я пока не всё вкурил, поэтому буду задавать мелкие вопросы по ходу (в т.ч. и по lua).
1) Зачем создавать maskx? Нельзя ли результат класть в mask (она же локальная для dss_match)?
2) Зачем объявлять через local индекс цикла for?
3) Как Вы надыбали такие чудесные конструкции как #diz для длины и dss_mask:sub(-1,-1) для подстроки? Они же не документированы...
Ответы по Lua:
1) Можно.
2) Незачем. На самом деле, это получаются 2 разные, хоть и одноимённые, переменные.
3) Всё это документировано в мануале Lua.
-- #diz даёт длину diz в байтах. Чтобы получить длину в символах, нужно diz:len().
-- sub(-1,-1) - это то же самое, что sub(-1), то-есть, получение последнего символа.
User avatar
Smitis
Posts: 1709
Joined: Fri 18 Mar, 2005 12:51
Location: Питер
Has thanked: 23 times
Been thanked: 55 times

Re: DescSS — поиск и выделение по описаниям файлов

Post by Smitis »

Я Lua ещё сам изучаю. Совершенно забыл, что в for переменная локальная.
О # как-то не задумывался, пожалуй, len будет правильней.
Поправил размеры диалога. Добавил вставку CtrlV ShiftIns и пр.


Интересный визуальный глюк возникает, если из диалога выйти в режим Search

П.С. Выяснил, глюк возникает из-за плагина PanelTabs.
Разум когда-нибудь победит.
User avatar
Smitis
Posts: 1709
Joined: Fri 18 Mar, 2005 12:51
Location: Питер
Has thanked: 23 times
Been thanked: 55 times

Re: DescSS — поиск и выделение по описаниям файлов

Post by Smitis »

Подправил макрос в предыдущем посте. После выхода из диалога нажатая клавиша сначала выполняется как макрос через eval, а если такого макроса нет, передаётся дальше через Keys.
Разум когда-нибудь победит.
User avatar
zg
zero-gravity
Posts: 6016
Joined: Tue 15 Mar, 2005 17:36
Location: riga
Been thanked: 185 times
Contact:

Re: DescSS — поиск и выделение по описаниям файлов

Post by zg »

с диалоговой процедурой:
User avatar
Smitis
Posts: 1709
Joined: Fri 18 Mar, 2005 12:51
Location: Питер
Has thanked: 23 times
Been thanked: 55 times

Re: DescSS — поиск и выделение по описаниям файлов

Post by Smitis »

zg wrote:с диалоговой процедурой
Класс!
Разум когда-нибудь победит.
yms
Posts: 209
Joined: Sun 14 Jun, 2009 10:38
Been thanked: 2 times
Contact:

Re: DescSS — поиск и выделение по описаниям файлов

Post by yms »

В принципе я собирался плагин на 3.0 перевести...
так шо, уже неактуально? :)
User avatar
sToLp
Posts: 938
Joined: Thu 23 Jul, 2009 10:16
Has thanked: 114 times
Been thanked: 12 times

Re: DescSS — поиск и выделение по описаниям файлов

Post by sToLp »

yms wrote:В принципе я собирался плагин на 3.0 перевести...
Если есть возможность/время/желание — сделайте пожалуйста, а то пока ещё луа освоится...
User avatar
HaRT
Moderator
Posts: 10822
Joined: Tue 30 Aug, 2005 17:21
Has thanked: 221 times
Been thanked: 358 times

Re: DescSS — поиск и выделение по описаниям файлов

Post by HaRT »

yms wrote:В принципе я собирался плагин на 3.0 перевести...
Актуально, особенно если заодно добавите поддержку регулярных выражений, — конечно, если FAR API предоставляет такую возможность.
Фар есть инструмент, а не нянька. © 2009 DrKnS
User avatar
Smitis
Posts: 1709
Joined: Fri 18 Mar, 2005 12:51
Location: Питер
Has thanked: 23 times
Been thanked: 55 times

Re: DescSS — поиск и выделение по описаниям файлов

Post by Smitis »

yms wrote:В принципе я собирался плагин на 3.0 перевести...
так шо, уже неактуально? :)
Если плагин будет, это хорошо. А то количество макросов скоро зашкалит за все разумные пределы :)

А пока очередная серия версия с диалоговой процедурой от zg, с обработкой пробела (был забыт), отключением перемещения курсора при щёлканьи мышью по строке ввода, с выполнением макросов, после закрытия диалога и пр. и пр.

На этом фантазия пока закончилась...
Может только обработку каких клавиш пропустил
Разум когда-нибудь победит.
Post Reply

Return to “Полезные макросы и скрипты”