Ru-Board.club
← Вернуться в раздел «Тестирование»

» Far Manager - скрипты и плагины

Автор: VictorVG4
Дата сообщения: 06.05.2016 21:41
Тут обсуждаются технические вопросы разработки скриптов и плагинов для Far Manager которые нет смысла выносить в общую тему, а по итогам работы туда пишем пост содержащий краткую постановку задачи и её решение в виде нескольких строк в формате ЗАДАЧА :: РЕШЕНИЕ, да и то если данная задача оказалась статически востребованной достаточно большим числом пользователей.

Данная тема создана для того чтобы вынести процесс разработки из основной темы где он вызывает нарекания людей которым часто нужен конечный результат, а не несколько страниц обсуждения способа его получения.

Если ваша задача интересна только вам, то просьба обсуждать её в ПМ чтобы не вызывать недовольство окружающих.
Автор: Angel_Ka
Дата сообщения: 06.05.2016 22:06
Макрос от Alexyz21 "Select Duplicates FileName in Branch panel" Версия 10.1. Опробование на Бранче из 1 826 152 файлов.

Код: [x] Ignore full duplicates
mcs: 8950506 8897546 8651435

[ ] Ignore full duplicates
mcs: 13805848 14395049 14291816
Автор: Alexyz21
Дата сообщения: 06.05.2016 22:12
VictorVG4
Предлагаю переименовать в "FAR Manager - макросы, скрипты", вынеся эту тему из основной полностью, дабы не ранить тонкую душевную организацию эстетов-пуристов.
Автор: VictorVG4
Дата сообщения: 06.05.2016 22:18
Alexyz21
Angel_Ka

Давайте посмотрим какие вопросы будут обсуждаться в этой теме. Это название временное, а наберём статистику и все вместе уточним название по факту.
Автор: shmuz2
Дата сообщения: 06.05.2016 22:20
Это надо было проявить незаурядную изобретательность, чтобы создать тему
Специальные » Тестирование » Far Manager - специальные вопросы
Это ж какую дозу надо было перед этим принять.
Автор: Alexyz21
Дата сообщения: 06.05.2016 22:35
11.1 [more]
Код: local F = far.Flags
local ffi = require'ffi'
local C = ffi.C

local guid = "FE9B8874-9651-434C-8182-72329F2371A5"
local uGuid = win.Uuid(guid)
local BS,ts = string.byte("\\"),{nil,true,9999,true,true,false}
local freport = win.GetEnv("Temp").."\\Report.txt"

ffi.cdef[[
int strcmp(const char*, const char*);
int _stricmp(const char*, const char*);
int _strnicmp(const char*, const char*, size_t);
int strncmp(const char*, const char*, size_t);
char* strrchr(const char*, int);
size_t strlen(const char*);
int memcmp(const void*, const void*, size_t);
]]

local function StartAndLen(name)
local ptr = C.strrchr(name,BS)
name = ptr==nil and name or ptr+1
local len = tonumber(C.strlen(name))
if ts[2] then
if ts[3]==0 or ts[3]<=-len then
elseif ts[3]<0 then name,len = name+len+ts[3],-ts[3]
elseif ts[3]<len then name,len = name+ts[3],len-ts[3]
else name,len = name+len,0
end
end
return name,len
end

local Items = {
--[[01]] {F.DI_DOUBLEBOX, 3,1, 65,6, 0, 0,0, 0, "Select duplicates of FileName. Help: F1"},
--[[02]] {F.DI_CHECKBOX, 5,2, 26,2, 0, 0,0, 0, "Num&ber of symbols"},
--[[03]] {F.DI_EDIT, 27,2, 31,2, 0, 0,0, 0, ""},
--[[04]] {F.DI_CHECKBOX, 5,3, 20,3, 0, 0,0, 0, "Ignore &case"},
--[[05]] {F.DI_CHECKBOX, 37,3, 56,3, 0, 0,0, 0, "Ignore &full duplicates"},
--[[06]] {F.DI_CHECKBOX, 5,5, 15,5, 0, 0,0, 0, "Re&port"},
--[[07]] {F.DI_TEXT, -1,4, 0,0, 0, 0,0, F.DIF_SEPARATOR,""},
--[[08]] {F.DI_BUTTON, 0,5, 0,0, 0, 0,0, F.DIF_DEFAULTBUTTON+F.DIF_CENTERGROUP,"&Ok"},
--[[09]] {F.DI_BUTTON, 0,5, 0,0, 0, 0,0, F.DIF_CENTERGROUP,"Ca&ncel"}
}

local tts={}

local function DlgProc(hDlg,Msg,Param1,Param2)
if Msg==F.DN_INITDIALOG then
for i=2,#Items-3 do tts[i]=ts[i] end
hDlg:send(F.DM_SETTEXT,3,tts[3])
hDlg:send(F.DM_SETCHECK,2,tts[2] and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED)
hDlg:send(F.DM_SETCHECK,4,tts[4] and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED)
hDlg:send(F.DM_SETCHECK,5,tts[5] and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED)
hDlg:send(F.DM_SETCHECK,6,tts[6] and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED)
elseif Msg==F.DN_BTNCLICK and (Param1==2 or Param1>=4 and Param1<=6) then
tts[Param1] = Param2~=0
elseif Msg==F.DN_EDITCHANGE and Param1==3 then -- Number symbols
tts[3] = tonumber(hDlg:send(F.DM_GETTEXT,3)) or tts[3]
else
return
end
return true
end

Macro {
description="* Select Duplicates FileName in Branch panel"; name="SDFN"; area="Shell";
action=function()
if far.Dialog(uGuid,-1,-1,69,8,nil,Items,nil,DlgProc)==#Items-1 then
for i=2,#Items-3 do ts[i]=tts[i] end
local pBL=ffi.cast("BOOL*",1)
local pc=ffi.cast("struct PluginStartupInfo*",far.CPluginStartupInfo()).PanelControl
local pin=panel.GetPanelInfo(nil,1)
if bit.band(pin.Flags,F.PFLAGS_SELECTEDFIRST)>0 then Keys("ShiftF12") end
pc(PANEL_ACTIVE,"FCTL_SETNUMERICSORT",0,nil)
pc(PANEL_ACTIVE,"FCTL_SETCASESENSITIVESORT",ts[4] and 0 or 1,nil)
if ((ts[2] and ts[3]>=0) or not ts[2]) and pin.SortMode~=F.SM_NAME then panel.SetSortMode(nil,1,F.SM_NAME) end
local sid,sel,j,fn0,fn1,st0,ln0,st1,ln1,t0 = 0,{},0,"","",0,0,0,0,far.FarClock()
local function Proc(i)
if i>j then
pc(PANEL_ACTIVE,"FCTL_SETSELECTION",i-2,pBL)
table.insert(sel,{fn0,1})
sid=1
end
pc(PANEL_ACTIVE,"FCTL_SETSELECTION",i-1,pBL)
j,sid=i+1,sid+1
sel[#sel][2]=sid
end
pc(PANEL_ACTIVE,"FCTL_BEGINSELECTION",0,nil)
for i=1,pin.ItemsNumber do
fn0=fn1
st1,ln1=StartAndLen(panel.GetPanelItem(nil,1,i).FileName)
fn1=ffi.string(st1,ln1)
if ((not ts[2] or ts[3]<0) and not ts[4]) and (not(ts[5] and C.strcmp(fn1,fn0)==0) and C.strcmp(fn1,fn0)==0) then Proc(i)
elseif ((not ts[2] or ts[3]<0) and ts[4]) and (not(ts[5] and C._stricmp(fn1,fn0)==0) and C._stricmp(fn1,fn0)==0) then Proc(i)
elseif (ts[2] and ts[4]) and (not(ts[5] and C._stricmp(fn1,fn0)==0) and C._strnicmp(fn1,fn0,ts[3])==0) then Proc(i)
elseif (ts[2] and not ts[4]) and (not(ts[5] and C.strcmp(fn1,fn0)==0) and C.strncmp(fn1,fn0,ts[3])==0) then Proc(i)
end
end
pc(PANEL_ACTIVE,"FCTL_ENDSELECTION",0,nil)
pc(PANEL_ACTIVE,"FCTL_REDRAWPANEL",0,nil)
Keys("ShiftF12")
if ts[6] then
table.sort(sel,function(a,b) return a[2]<b[2] end)
local h = io.open(freport,"wb")
io.close(h)
h = io.open(freport,"ab")
h:write("Items: "..#sel.."\nExecution time: "..far.FarClock()-t0.." mcs\nNumber of symbols: "..(ts[2] and ts[3] or "all").."\nIgnore case: "..tostring(ts[4]).."\nIgnore full duplicates: "..tostring(ts[5]).."\n\n")
for i=#sel,1,-1 do h:write(sel[i][2].."\t"..sel[i][1].."\n") sel[i]=nil end
io.close(h)
far.Message("mcs: "..far.FarClock()-t0,"SDFN")
end
end
end;
}

Macro {
description = "SDFN - Help"; area = "Dialog"; key = "F1";
condition=function() return Area.Dialog and Dlg.Id==guid end;
action=function()
if Dlg.CurPos<=3 then far.Message("The number of first or last symbols to compare","Help: Number of symbols")
elseif Dlg.CurPos==4 then far.Message("Case of letters in FileName will be ignored","Help: Ignore case")
elseif Dlg.CurPos==5 then far.Message("Full duplicates of FileName will be ignored","Help: Ignore full duplicates")
elseif Dlg.CurPos==6 then far.Message("mcs - total time of execution in mcs\nReport will be saved to:\n"..freport,"Help: Report",nil,"l")
end
end;
}
Автор: shmuz2
Дата сообщения: 06.05.2016 23:07
(Не связано с названием данной темы).
Если возникнут ко мне вопросы, желательно задавать их в общей ветке Far Manager, поскольку читать больше одной ветки на этом форуме у меня врядли получится.
Автор: Alexyz21
Дата сообщения: 06.05.2016 23:19
shmuz2
об этом я и говорил - мониторить ещё одну тему затруднительно, не на одном же FARe свет клином сошёлся. Кроме него ещё куча тем уже мониторится и ещё одну тему по тому же направлению добавлять нецелесообразно. В результате без постоянной "тусы" тема глохнет.
Автор: Angel_Ka
Дата сообщения: 06.05.2016 23:22
Версия 11. Бранч из 1 826 152 файлов.

Код:
[x] Offset -34 [x] Number of symbols -34
[x] Ignore case
[x] Ignore full duplicates

Curr count: 66429590 mcs: 206647361 SDFN mcs: 9511263

Curr count: 39418366 mcs: 124026504 SDFN mcs: 9662437
Prev count: 66429590 mcs: 206647361
Difference:-27011224 mcs: -82620857

Curr count: 39418365 mcs: 124079483 SDFN mcs: 9565960
Prev count: 39418366 mcs: 124026504
Difference: -1 mcs: +52979
Автор: Alexyz21
Дата сообщения: 06.05.2016 23:23
Angel_Ka
следите за обновлениями - там уже 3 фикса было И без предварительной сортировки кастомом смысла в применении отрицательных смещений нет, так как они не будут последовательно отсортированы на панели!
Автор: shmuz2
Дата сообщения: 06.05.2016 23:23
Alexyz21
Ну это не я вас отделял. Хотя разумная пропорция в основной ветке безусловно была сильно нарушена, и исправлять это надо было.
Так или иначе, мониторить 2 ветки я не буду, поэтому ищите меня там.
Автор: Angel_Ka
Дата сообщения: 06.05.2016 23:27
Поскольку данный тест относительно продолжительный, то обнародую его результаты поэтапно. На этом этапе показаны результаты теста с отрицательным смещением (т.е. от конца файлов) и игнорированием полных дубликатов.

Как предполагается, на следующем этапе, на котором полные дубликаты будут учитываться время работы макроса увеличится примерно в 1,6 раза. Увидим.

Добавлено:
Alexyz21

Цитата:
следите за обновлениями - там уже 3 фикса было

У меня Сборный макрос версии от 19:18 01-05-2016. Вроде бы позже не было.
Автор: Alexyz21
Дата сообщения: 06.05.2016 23:34
Angel_Ka
Опять 25! - вы делаете бессмысленные манипуляции! Какие дубликаты вообще можно отобрать, если на панели они расположены не группами? - Отвечаю - никакие! Сначала сортировка, которая расположит фрагменты последовательно и лишь затем последовательный поиск и выделение групп.

Добавлено:

Цитата:
следите за обновлениями - там уже 3 фикса было

это про 11.1 - см. время последней модификации сообщения.
Автор: Angel_Ka
Дата сообщения: 06.05.2016 23:36

Цитата:
Внимание! Для сравнения последних символов, до применения этого макроса, панель должна быть отсортирована вручную макросом Panel.CustomSortByName.lua с таким же отрицательным смещением.

Я именно так и сделал, и это показал в сводке. Что-то не так? Подскажите, пожалуйста.
Автор: Alexyz21
Дата сообщения: 06.05.2016 23:38
А! Значит я на ручнике Кстати да, Ignore case нужно ставить одинаковым как при сортировке, так и при выделении.
Автор: Angel_Ka
Дата сообщения: 06.05.2016 23:41

Цитата:
это про 11.1 - см. время последней модификации сообщения

А! Семён Семёнович!

Цитата:
Сначала сортировка, которая расположит фрагменты последовательно и лишь затем последовательный поиск и выделение групп.

Дык у меня же именно так и сделано. Сначала сортировал по [x] Offset -34, потом выделял по [x] Number of symbols -34, потом снова сортировал, затем выделял, снова сортировал, потом выделял. И результаты показаны последовательно.
Автор: Alexyz21
Дата сообщения: 06.05.2016 23:54
И помимо одинакового Ignore case, на панели (должно быть?) отключено Numeric sort до применения кастома - советую сравнить конечные результаты найденных дубликатов с отключенным и включенным Numeric sort ДО кастома, т.е. в самом начале.

Добавлено:
С положительными значениями вижу косяк - в кастоме используется подстрока после офсета, а в выделяльщике до. Как тут правильно поступить?
Автор: Angel_Ka
Дата сообщения: 07.05.2016 00:24
C положительными значениями выскакивает ошибка:

Код: LuaMacro

...‚иОдноименныеВбранче(Alexyz21)she.lua:28: attempt to perform arithmetic on local 'name' (a string value)
Stack Traceback
===============
(1) Lua function '(anonymous)' at file 'W:\Far\Profile\Macros\scripts\she_lua\11.1_выделитьПочтиОдноименныеВбранче(Alexyz21)she.lua:94' (best guess)
Local variables:
pin = table: 0x1ca9e918 {ViewMode:4, SortMode:2, PanelType:0, PanelRect:table: 0x1d69b4c8, TopPanelItem:16 (more...)}
sid = number: 0
sel = table: 0x1c96e5c0 {}
j = number: 0
fn0 = string: ""
fn1 = string: ""
st0 = number: 0
ln0 = number: 0
st1 = number: 0
ln1 = number: 0
t0 = number: 1.03676e+09
Proc = Lua function 'Proc' (defined at line 81 of chunk ...�иОдноименныеВбранче(Alexyz21)she.lua)
(for index) = number: 1
(for limit) = number: 70
(for step) = number: 1
i = number: 1
Автор: VictorVG4
Дата сообщения: 07.05.2016 00:42
Alexyz21
shmuz2
Angel_Ka

Поправил явно неудачное название.
Автор: Alexyz21
Дата сообщения: 07.05.2016 01:06
Angel_Ka

Цитата:
C положительными значениями выскакивает ошибка:

Так я же прямо над эти написал -
Цитата:
С положительными значениями вижу косяк - в кастоме используется подстрока после офсета, а в выделяльщике до. Как тут правильно поступить?

Видимо правильнее будет сделать свой кастом для выделяльщика и автоматом его включать перед выделением.

Попугаев пока измерять смысла нет - надо сначала устаканить правильно

shmuz2
Так, эпитафий у нас уже есть, только он зашифрован 7z Можем в таком виде и поместить, если чего... Или в 7z слишком не ортодоксально? (инфернальный юмор за полночь)
Автор: shmuz2
Дата сообщения: 07.05.2016 01:13
Alexyz21
(Это мой последний ответ в данной ветке).
Сегодня измерял цикл получения 2700 файлов панели двумя способами: (1) FFI из упомянутого зашифрованного файла и (2) LuaFAR. Как это ни странно, второй способ оказался быстрее. Разбираться, в чём дело, я не стал.
Автор: Alexyz21
Дата сообщения: 07.05.2016 01:23
12.0 [more]
Код: local F = far.Flags
local ffi = require'ffi'
local C = ffi.C

local PanelMode,Desc1,Indi1 = 999,"Custom: by name","!?"
local guid = "FE9B8874-9651-434C-8182-72329F2371A5"
local uGuid = win.Uuid(guid)
local BS,ts = string.byte("\\"),{nil,true,9999,true,true,false}
local freport = win.GetEnv("Temp").."\\Report.txt"
local Flags = C.SORT_STRINGSORT

ffi.cdef[[
int strcmp(const char*, const char*);
int _stricmp(const char*, const char*);
int _strnicmp(const char*, const char*, size_t);
int strncmp(const char*, const char*, size_t);
char* strrchr(const char*, int);
size_t strlen(const char*);
int memcmp(const void*, const void*, size_t);
]]

local function GetStartAndLen(name)
local ptr = C.wcsrchr(name,BS)
name = ptr==nil and name or ptr+1
local len = tonumber(C.wcslen(name))
if ts[2] and ts[3]<0 and -ts[3]<len then
local res=ffi.new("wchar_t[?]",len+1)
ffi.copy(res,ffi.string(name+len+ts[3],-ts[3]*2)..ffi.string(name,(len+ts[3])*2))
return res,len
else
return name,len
end
end

local Compare = function(p1,p2)
local st1,ln1 = GetStartAndLen(p1.FileName)
local st2,ln2 = GetStartAndLen(p2.FileName)
return -2 + C.CompareStringW(C.LOCALE_USER_DEFAULT,Flags,st1,ln1,st2,ln2)
end

local function StartAndLen(name)
local ptr = C.strrchr(name,BS)
name = ptr==nil and name or ptr+1
local len = tonumber(C.strlen(name))
if ts[2] and ts[3]<0 and -ts[3]<len then
return name+len+ts[3],-ts[3],name,len
else
return name,len,name,len
end
end

local Items = {
--[[01]] {F.DI_DOUBLEBOX, 3,1, 65,6, 0, 0,0, 0, "Select duplicates of FileName. Help: F1"},
--[[02]] {F.DI_CHECKBOX, 5,2, 26,2, 0, 0,0, 0, "Num&ber of symbols"},
--[[03]] {F.DI_EDIT, 27,2, 32,2, 0, 0,0, 0, ""},
--[[04]] {F.DI_CHECKBOX, 5,3, 20,3, 0, 0,0, 0, "Ignore &case"},
--[[05]] {F.DI_CHECKBOX, 37,3, 56,3, 0, 0,0, 0, "Ignore &full duplicates"},
--[[06]] {F.DI_CHECKBOX, 5,5, 15,5, 0, 0,0, 0, "Re&port"},
--[[07]] {F.DI_TEXT, -1,4, 0,0, 0, 0,0, F.DIF_SEPARATOR,""},
--[[08]] {F.DI_BUTTON, 0,5, 0,0, 0, 0,0, F.DIF_DEFAULTBUTTON+F.DIF_CENTERGROUP,"&Ok"},
--[[09]] {F.DI_BUTTON, 0,5, 0,0, 0, 0,0, F.DIF_CENTERGROUP,"Ca&ncel"}
}

local tts={}

local function DlgProc(hDlg,Msg,Param1,Param2)
if Msg==F.DN_INITDIALOG then
for i=2,#Items-3 do tts[i]=ts[i] end
hDlg:send(F.DM_SETTEXT,3,tts[3])
hDlg:send(F.DM_SETCHECK,2,tts[2] and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED)
hDlg:send(F.DM_SETCHECK,4,tts[4] and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED)
hDlg:send(F.DM_SETCHECK,5,tts[5] and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED)
hDlg:send(F.DM_SETCHECK,6,tts[6] and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED)
elseif Msg==F.DN_BTNCLICK and (Param1==2 or Param1>=4 and Param1<=6) then
tts[Param1] = Param2~=0
elseif Msg==F.DN_EDITCHANGE and Param1==3 then -- Number symbols
tts[3] = tonumber(hDlg:send(F.DM_GETTEXT,3)) or tts[3]
else
return
end
return true
end

Macro {
description="* Select Duplicates FileName in Branch panel"; name="SDFN"; area="Shell";
action=function()
if far.Dialog(uGuid,-1,-1,69,8,nil,Items,nil,DlgProc)==#Items-1 then
local t0=far.FarClock()
for i=2,#Items-3 do ts[i]=tts[i] end
local pBL=ffi.cast("BOOL*",1)
local pc=ffi.cast("struct PluginStartupInfo*",far.CPluginStartupInfo()).PanelControl
local pin=panel.GetPanelInfo(nil,1)
if bit.band(pin.Flags,F.PFLAGS_SELECTEDFIRST)>0 then Keys("ShiftF12") end
pc(PANEL_ACTIVE,"FCTL_SETNUMERICSORT",0,nil)
pc(PANEL_ACTIVE,"FCTL_SETCASESENSITIVESORT",ts[4] and 0 or 1,nil)
if ((ts[2] and ts[3]>=0) or not ts[2]) then
pc(PANEL_ACTIVE,"FCTL_SETSORTMODE",F.SM_NAME,nil)
else
Flags = ts[4] and bit.bor(Flags,C.NORM_IGNORECASE) or bit.band(Flags,bit.bnot(C.NORM_IGNORECASE))
Panel.LoadCustomSortMode(PanelMode,{Description=Desc1;Indicator=Indi1;Compare=Compare})
Panel.SetCustomSortMode(PanelMode,0)
end
pc(PANEL_ACTIVE,"FCTL_SETSORTORDER",0,nil)
local sid,sel,j,fn0,fn1,fn2,fn3,st0,ln0,st1,ln1,st2,ln2,st3,ln3 = 0,{},0,"","","","",0,0,0,0,0,0,0,0
local function Proc(i,x)
if x then
if i>j then
pc(PANEL_ACTIVE,"FCTL_SETSELECTION",i-2,pBL)
table.insert(sel,{fn0,1})
sid=1
end
pc(PANEL_ACTIVE,"FCTL_SETSELECTION",i-1,pBL)
sid=sid+1
sel[#sel][2]=sid
end
j=i+1
end
pc(PANEL_ACTIVE,"FCTL_BEGINSELECTION",0,nil)
for i=1,pin.ItemsNumber do
fn0,fn2 = fn1,fn3
st1,ln1,st3,ln3=StartAndLen(panel.GetPanelItem(nil,1,i).FileName)
fn1,fn3 = ffi.string(st1,ln1),ffi.string(st3,ln3)
if ((not ts[2] or ts[3]<0) and not ts[4]) and C.strcmp(fn1,fn0)==0 then Proc(i,not(ts[5] and C.strcmp(fn3,fn2)==0))
elseif ((not ts[2] or ts[3]<0) and ts[4]) and C._stricmp(fn1,fn0)==0 then Proc(i,not(ts[5] and C._stricmp(fn3,fn2)==0))
elseif (ts[2] and ts[4]) and C._strnicmp(fn1,fn0,ts[3])==0 then Proc(i,not(ts[5] and C._stricmp(fn3,fn2)==0))
elseif (ts[2] and not ts[4]) and C.strncmp(fn1,fn0,ts[3])==0 then Proc(i,not(ts[5] and C.strcmp(fn3,fn2)==0))
end
end
pc(PANEL_ACTIVE,"FCTL_ENDSELECTION",0,nil)
pc(PANEL_ACTIVE,"FCTL_REDRAWPANEL",0,nil)
Keys("ShiftF12")
if ts[6] then
table.sort(sel,function(a,b) return a[2]<b[2] end)
local h = io.open(freport,"wb")
io.close(h)
h = io.open(freport,"ab")
h:write("Items: "..#sel.."\nExecution time: "..far.FarClock()-t0.." mcs\nNumber of symbols: "..(ts[2] and ts[3] or "all").."\nIgnore case: "..tostring(ts[4]).."\nIgnore full duplicates: "..tostring(ts[5]).."\n\n")
for i=#sel,1,-1 do h:write(sel[i][2].."\t"..sel[i][1].."\n") sel[i]=nil end
io.close(h)
far.Message("mcs: "..far.FarClock()-t0,"SDFN")
end
end
end;
}

Macro {
description = "SDFN - Help"; area = "Dialog"; key = "F1";
condition=function() return Area.Dialog and Dlg.Id==guid end;
action=function()
if Dlg.CurPos<=3 then far.Message("The number of first or last symbols to compare","Help: Number of symbols")
elseif Dlg.CurPos==4 then far.Message("Case of letters in FileName will be ignored","Help: Ignore case")
elseif Dlg.CurPos==5 then far.Message("Full duplicates of FileName will be ignored","Help: Ignore full duplicates")
elseif Dlg.CurPos==6 then far.Message("mcs - total time of execution in mcs\nReport will be saved to:\n"..freport,"Help: Report",nil,"l")
end
end;
}
Автор: Angel_Ka
Дата сообщения: 07.05.2016 14:51
Alexyz21

Цитата:
12.0

На отрицательных ошибки нет. Результаты вроде бы верные.
На положительных с отключённой опцией "игнорировать полные дубликаты" тоже.
На положительных с [x] Ignore full duplicates ошибка:

Код: LuaMacro

...‚иОдноименныеВбранче(Alexyz21)she.lua:116: attempt to index a nil value
Stack Traceback
===============
(1) Lua function '(anonymous)' at file 'W:\Far\Profile\Macros\scripts\she_lua\12.0_выделитьПочтиОдноименныеВбранче(Alexyz21)she.lua:127' (best guess)
Local variables:
t0 = number: 6.07821e+08
pin = table: 0x36991220 {ViewMode:4, SortMode:2, PanelType:0, PanelRect:table: 0x369cf4f0, TopPanelItem:1 (more...)}
sid = number: 1
sel = table: 0x36a01f20 {}
j = number: 15
fn0 = string: "72009 ГОСТ 12.0.005-84 Метрологическое обеспечение в области безопасности труда. Основные полож
ения.2001.pdf"
fn1 = string: "72009 ГОСТ 12.0.005-84 Метрологическое обеспечение в области безопасности труда. Основные полож
ения.переиздание1999.pdf"
fn2 = string: "72009 ГОСТ 12.0.005-84 Метрологическое обеспечение в области безопасности труда. Основные полож
ения.2001.pdf"
fn3 = string: "72009 ГОСТ 12.0.005-84 Метрологическое обеспечение в области безопасности труда. Основные полож
ения.переиздание1999.pdf"
st0 = number: 0
ln0 = number: 0
ln1 = number: 202
st2 = number: 0
ln2 = number: 0
ln3 = number: 202
Proc = Lua function 'Proc' (defined at line 107 of chunk ...�иОдноименныеВбранче(Alexyz21)she.lua)
(for index) = number: 15
(for limit) = number: 78
(for step) = number: 1
i = number: 15
Автор: Angel_Ka
Дата сообщения: 08.05.2016 06:51
Изъял из микротестовой сборки файл "72009 ГОСТ 12.0.005-84 Метрологическое обеспечение в области безопасности труда. Основные положения.переиздание1999.pdf" и ошибка ушла.

Сделал тестовый бранч на 546804 файла на базе сборки портабельного софта и возобновил опробование 12-ой версии макроса.


Код: [x] Number of symbols 9999
[x] Ignore case [ ] Ignore full duplicates

mcs: 20447585 mcs: 20622035 mcs: 20587732

[x] Number of symbols 9999
[ ] Ignore case [ ] Ignore full duplicates

mcs: 12554891 mcs: 12575750 mcs: 12529502

[x] Number of symbols 37
[x] Ignore case [ ] Ignore full duplicates

mcs: 20601037 mcs: 20610607 mcs: 20603966

[x] Number of symbols 37
[ ] Ignore case [ ] Ignore full duplicates

mcs: 15068851 mcs: 12562418 mcs: 12589486

[x] Number of symbols 37
[x] Ignore case [x] Ignore full duplicates

Ошибка:
LuaMacro

...‚иОдноименныеВбранче(Alexyz21)she.lua:116: attempt to index a nil value
Stack Traceback
===============
(1) Lua function '(anonymous)' at file 'W:\Far\Profile\Macros\scripts\she_lua\12.0_выделитьПочтиОдноименныеВбранче(Alexyz21)she.lua:127' (best guess)
Local variables:
t0 = number: 3.6801e+09
pin = table: 0x3640d9b0 {ViewMode:4, SortMode:2, PanelType:0, PanelRect:table: 0x34cd96f8, TopPanelItem:1 (more...)}
sid = number: 1
sel = table: 0x35a2d1a8 {}
j = number: 3360
fn0 = string: "_GUICtrlComboBox_GetDroppedControlRect.au3"
fn1 = string: "_GUICtrlComboBox_GetDroppedControlRectEx.au3"
fn2 = string: "_GUICtrlComboBox_GetDroppedControlRect.au3"
fn3 = string: "_GUICtrlComboBox_GetDroppedControlRectEx.au3"
st0 = number: 0
ln0 = number: 0
ln1 = number: 44
st2 = number: 0
ln2 = number: 0
ln3 = number: 44
Proc = Lua function 'Proc' (defined at line 107 of chunk ...�иОдноименныеВбранче(Alexyz21)she.lua)
(for index) = number: 3360
(for limit) = number: 546805
(for step) = number: 1
i = number: 3360
Автор: Alexyz21
Дата сообщения: 08.05.2016 07:55
12.2 [more]
Код: local F = far.Flags
local ffi = require'ffi'
local C = ffi.C

local PanelMode,Desc1,Indi1 = 999,"Custom: by name","!?"
local guid = "FE9B8874-9651-434C-8182-72329F2371A5"
local uGuid = win.Uuid(guid)
local BS,ts = string.byte("\\"),{nil,true,9999,true,true,false}
local freport = win.GetEnv("Temp").."\\Report.txt"
local Flags = C.SORT_STRINGSORT

ffi.cdef[[
int strcmp(const char*, const char*);
int _stricmp(const char*, const char*);
int _strnicmp(const char*, const char*, size_t);
int strncmp(const char*, const char*, size_t);
char* strrchr(const char*, int);
size_t strlen(const char*);
int memcmp(const void*, const void*, size_t);
]]

local function GetStartAndLen(name)
local ptr = C.wcsrchr(name,BS)
name = ptr==nil and name or ptr+1
local len = tonumber(C.wcslen(name))
if ts[2] and ts[3]<0 and -ts[3]<len then
local res=ffi.new("wchar_t[?]",len+1)
ffi.copy(res,ffi.string(name+len+ts[3],-ts[3]*2)..ffi.string(name,(len+ts[3])*2))
return res,len
else
return name,len
end
end

local Compare = function(p1,p2)
local st1,ln1 = GetStartAndLen(p1.FileName)
local st2,ln2 = GetStartAndLen(p2.FileName)
return -2 + C.CompareStringW(C.LOCALE_USER_DEFAULT,Flags,st1,ln1,st2,ln2)
end

local function StartAndLen(name)
local ptr = C.strrchr(name,BS)
name = ptr==nil and name or ptr+1
local len = tonumber(C.strlen(name))
if ts[2] and ts[3]<0 and -ts[3]<len then
return name+len+ts[3],-ts[3],name,len
elseif ts[2] and ts[3]>0 and ts[3]<len then
return name,ts[3],name,len
else
return name,len,name,len
end
end

local Items = {
--[[01]] {F.DI_DOUBLEBOX, 3,1, 65,6, 0, 0,0, 0, "Select duplicates of FileName. Help: F1"},
--[[02]] {F.DI_CHECKBOX, 5,2, 26,2, 0, 0,0, 0, "Num&ber of symbols"},
--[[03]] {F.DI_EDIT, 27,2, 32,2, 0, 0,0, 0, ""},
--[[04]] {F.DI_CHECKBOX, 5,3, 20,3, 0, 0,0, 0, "Ignore &case"},
--[[05]] {F.DI_CHECKBOX, 37,3, 56,3, 0, 0,0, 0, "Ignore &full duplicates"},
--[[06]] {F.DI_CHECKBOX, 5,5, 15,5, 0, 0,0, 0, "Re&port"},
--[[07]] {F.DI_TEXT, -1,4, 0,0, 0, 0,0, F.DIF_SEPARATOR,""},
--[[08]] {F.DI_BUTTON, 0,5, 0,0, 0, 0,0, F.DIF_DEFAULTBUTTON+F.DIF_CENTERGROUP,"&Ok"},
--[[09]] {F.DI_BUTTON, 0,5, 0,0, 0, 0,0, F.DIF_CENTERGROUP,"Ca&ncel"}
}

local tts={}

local function DlgProc(hDlg,Msg,Param1,Param2)
if Msg==F.DN_INITDIALOG then
for i=2,#Items-3 do tts[i]=ts[i] end
hDlg:send(F.DM_SETTEXT,3,tts[3])
hDlg:send(F.DM_SETCHECK,2,tts[2] and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED)
hDlg:send(F.DM_SETCHECK,4,tts[4] and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED)
hDlg:send(F.DM_SETCHECK,5,tts[5] and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED)
hDlg:send(F.DM_SETCHECK,6,tts[6] and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED)
elseif Msg==F.DN_BTNCLICK and (Param1==2 or Param1>=4 and Param1<=6) then
tts[Param1] = Param2~=0
elseif Msg==F.DN_EDITCHANGE and Param1==3 then -- Number symbols
tts[3] = tonumber(hDlg:send(F.DM_GETTEXT,3)) or tts[3]
else
return
end
return true
end

Macro {
description="* Select Duplicates FileName in Branch panel"; name="SDFN"; area="Shell";
action=function()
if far.Dialog(uGuid,-1,-1,69,8,nil,Items,nil,DlgProc)==#Items-1 then
local t0=far.FarClock()
for i=2,#Items-3 do ts[i]=tts[i] end
local pBL=ffi.cast("BOOL*",1)
local pc=ffi.cast("struct PluginStartupInfo*",far.CPluginStartupInfo()).PanelControl
local pin=panel.GetPanelInfo(nil,1)
if bit.band(pin.Flags,F.PFLAGS_SELECTEDFIRST)>0 then Keys("ShiftF12") end
pc(PANEL_ACTIVE,"FCTL_SETNUMERICSORT",0,nil)
pc(PANEL_ACTIVE,"FCTL_SETCASESENSITIVESORT",ts[4] and 0 or 1,nil)
if ((ts[2] and ts[3]>=0) or not ts[2]) then
pc(PANEL_ACTIVE,"FCTL_SETSORTMODE",F.SM_NAME,nil)
else
Flags = ts[4] and bit.bor(Flags,C.NORM_IGNORECASE) or bit.band(Flags,bit.bnot(C.NORM_IGNORECASE))
Panel.LoadCustomSortMode(PanelMode,{Description=Desc1;Indicator=Indi1;Compare=Compare})
Panel.SetCustomSortMode(PanelMode,0)
end
pc(PANEL_ACTIVE,"FCTL_SETSORTORDER",0,nil)
local sid,sel,fn0,fn1,fn2,fn3,st0,ln0,st1,ln1,st2,ln2,st3,ln3 = 0,{},"","","","",0,0,0,0,0,0,0,0
local function Comp(fn0,fn1)
if ts[4] then return C._stricmp(fn1,fn0)
elseif not ts[4] then return C.strcmp(fn1,fn0)
end
end
local function Proc(i)
if #sel>0 and Comp(sel[#sel][1],fn0)~=0 or #sel==0 then
pc(PANEL_ACTIVE,"FCTL_SETSELECTION",i-2,pBL)
table.insert(sel,{fn0,1})
sid=1
end
pc(PANEL_ACTIVE,"FCTL_SETSELECTION",i-1,pBL)
sid = sid+1
sel[#sel][2]=sid
end
pc(PANEL_ACTIVE,"FCTL_BEGINSELECTION",0,nil)
for i=1,pin.ItemsNumber do
fn0,fn2 = fn1,fn3
st1,ln1,st3,ln3=StartAndLen(panel.GetPanelItem(nil,1,i).FileName)
fn1,fn3 = ffi.string(st1,ln1),ffi.string(st3,ln3)
if ts[4] and C._stricmp(fn1,fn0)==0 and not(ts[5] and C._stricmp(fn3,fn2)==0) then Proc(i)
elseif not ts[4] and C.strcmp(fn1,fn0)==0 and not(ts[5] and C.strcmp(fn3,fn2)==0) then Proc(i)
end
end
pc(PANEL_ACTIVE,"FCTL_ENDSELECTION",0,nil)
pc(PANEL_ACTIVE,"FCTL_REDRAWPANEL",0,nil)
Keys("ShiftF12")
if ts[6] then
table.sort(sel,function(a,b) return a[2]<b[2] end)
local h = io.open(freport,"wb")
io.close(h)
h = io.open(freport,"ab")
h:write("Items: "..#sel.."\nExecution time: "..far.FarClock()-t0.." mcs\nNumber of symbols: "..(ts[2] and ts[3] or "all").."\nIgnore case: "..tostring(ts[4]).."\nIgnore full duplicates: "..tostring(ts[5]).."\n\n")
for i=#sel,1,-1 do h:write(sel[i][2].."\t"..sel[i][1].."\n") sel[i]=nil end
io.close(h)
far.Message("mcs: "..far.FarClock()-t0,"SDFN")
end
end
end;
}

Macro {
description = "SDFN - Help"; area = "Dialog"; key = "F1";
condition=function() return Area.Dialog and Dlg.Id==guid end;
action=function()
if Dlg.CurPos<=3 then far.Message("The number of first or last symbols to compare","Help: Number of symbols")
elseif Dlg.CurPos==4 then far.Message("Case of letters in FileName will be ignored","Help: Ignore case")
elseif Dlg.CurPos==5 then far.Message("Full duplicates of FileName will be ignored","Help: Ignore full duplicates")
elseif Dlg.CurPos==6 then far.Message("mcs - total time of execution in mcs\nReport will be saved to:\n"..freport,"Help: Report",nil,"l")
end
end;
}
Автор: Angel_Ka
Дата сообщения: 08.05.2016 08:01
Приступил к опробованию.
Автор: Alexyz21
Дата сообщения: 08.05.2016 08:07
Имхо сейчас логика наименее противоречивая. Опция игнора полных дубликатов вносит некоторый хаос в логику. Пример: имеем последовательность а,б в которой совпадает часть строки в пределах Number symbols - значит выделяем оба - логично? - логично. Идём дальше, к последовательности добавляется ещё одна б - а,б,б и тут оказывается, что б это полные дубликаты, которые надо игнорить, и а остаётся одна не пришей рукав, а если она одна, то выделение нужно сбросить, в итоге имея 3 похожих имени они все должны игнорироваться - ну не бред ли? А главное логика обработки всевозможных последовательностей становится мутной и медленной. В итоге пришёл к варианту 12.2.

Добавлено:
Angel_Ka
Теперь не требуется какая-либо предварительная сортировка панели - скрипт делает её сам. Нужно только сбрасывать выделение, автоматический сброс не делал, так как пользователь может хотеть что-то пометить специально. Каждый запуск скрипта добавляет выделение, но не сбрасывает его.

Добавлено:
Теперь считается время выполнения скрипта полностью, а не только цикла.
Автор: Angel_Ka
Дата сообщения: 08.05.2016 08:25
В позициях, на которых в предыдущей версии выскакивали ошибки, теперь ошибок нет.

Перехожу к попугаям.

Добавлено:

Код: [x] Number of symbols 37
[x] Ignore case [x] Ignore full duplicates

mcs: 22302543 mcs: 22204919 mcs: 19241480
Автор: Alexyz21
Дата сообщения: 08.05.2016 08:46
попугаи будут толще, так как: 1. теперь считается время выполнения скрипта целиком - с сортировкой панели, выделением, формированием и сохранением рапорта; 2. медленнее обработка с конца, но теперь она правильная; 3. несколько медленнее сам цикл, из-за более адекватной логики выделения.

Поэтому сравнивать "в лоб" попугаев бессмысленно, нужно в предыдущих версиях учитывать и время сортировки панелей (в том числе ручной!), плюс замерять время исполнения не голого цикла, а всего макроса (это можно сделать перенеся local t0=far.FarClock() в начало action()? как это сделано в 12.2).

Добавлено:
Субъективно больше времени уходит на получение результата, или нет?
Автор: Angel_Ka
Дата сообщения: 08.05.2016 08:56
Про бОльшую упитанность попугаев вполне понятно. Это мы раньше уже обсуждали, и пусть будет так как получается. Лишь бы результат был верным.


Цитата:
Субъективно больше времени уходит на получение результата, или нет?

Да, по ощущениям несколько дольше, чем раньше. И непривычно то, что сброс пометки происходит дольше. Но это всё равно всё гораздо быстрее, чем я предполагал вначале.

Очень и очень Вам БЛАГОДАРЕН!

Продолжу измерять попугаев. Мне самому интересно сопоставление скоростей обработки базы.

Код: [x] Number of symbols 37
[x] Ignore case [ ] Ignore full duplicates

mcs: 23789175 mcs: 20631144 mcs: 23698635

Number of symbols -7
[x] Ignore case [x] Ignore full duplicates

mcs: 311075292 mcs: 310280472 mcs: 306009337

[x] Number of symbols -7
[x] Ignore case [ ] Ignore full duplicates

mcs: 412268396 mcs: 412545659 mcs: 411739403

Страницы: 123456789101112

Предыдущая тема: кл


Форум Ru-Board.club — поднят 15-09-2016 числа. Цель - сохранить наследие старого Ru-Board, истории становления российского интернета. Сделано для людей.