Автор: 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;
}