├── moon2lua.lua
├── Editor.Reload.lua
├── Panel.CustomSortOther.lua
├── HTML-XML.OneLine-MultiLine.lua
├── Panel.SelectFolders.lua
├── CommandLineF4.lua
├── Panel.LYNX-motion.lua
├── Panel.Files2HEX_ffi.lua
├── Editor.SearchLinesWithMinMaxLength.lua
├── iptv.lua
├── btpolicy.xml.lua
├── RESearch.Grep.lua
├── Panel.ShiftF[56].lua
├── ansicolors.lua
├── Editor.LatCyrMixHighlighting.moon
├── Editor.CyrSpaceHighlighting.moon
├── FarExit.lua
├── Panel.SelectBOM.lua
├── Editor.TagGoto.lua
├── Panel.VisualCompare.lua
├── MessageX.lua
├── Panel.CustomSortByAttributes.lua
├── Editor.FilterDuplicatesFileNames.lua
├── FarUpdate.lua
├── ChessKnight.lua
├── Dialog.Maximize.moon
├── Panel.SelectDuplicatesFileNames.lua
├── Panel.CustomSortByName.lua
└── ChessKnight.c
/moon2lua.lua:
--------------------------------------------------------------------------------
1 | -- moon2lua.lua
2 | -- v1.0
3 | -- author Shmuel, 28.05.2020
4 | -- copy to folder included Moonscript files and run it: lua:@moon2lua.lua
5 | -- all Moonscript files will be deleted after convert!
6 |
7 | local to_lua = (require"moonscript.base").to_lua
8 | far.RecursiveSearch(far.GetCurrentDirectory(),"*.moon",
9 | function(item,fullpath)
10 | local fp = assert(io.open(fullpath))
11 | local str = fp:read("*all")
12 | fp:close()
13 | local newpath = fullpath:sub(1,-5).."lua"
14 | fp = assert(io.open(newpath,"w"))
15 | str = assert(to_lua(str))
16 | fp:write(str,"\n")
17 | fp:close()
18 | --win.DeleteFile(fullpath)
19 | end,
20 | "FRS_RECUR"
21 | )
22 |
--------------------------------------------------------------------------------
/Editor.Reload.lua:
--------------------------------------------------------------------------------
1 | -- Editor.Reload.lua
2 | -- v1.0
3 | -- Url: http://forum.ru-board.com/topic.cgi?forum=5&topic=31718&start=7640#7
4 |
5 | local F = far.Flags
6 |
7 | Macro {
8 | area="Editor"; key="CtrlR"; flags=""; description="Editor: Reload";
9 | action=function()
10 | local rl=true
11 | local f=editor.GetInfo(-1).FileName
12 | if bit64.band(far.AdvControl(F.ACTL_GETWINDOWINFO).Flags,F.WIF_MODIFIED)==F.WIF_MODIFIED then
13 | local ans=far.Message("File has been modified. Save?","Editor",";YesNoCancel","w")
14 | if ans==1 then
15 | if not editor.SaveFile(-1) then
16 | rl=false
17 | far.Message("File is not saved - blocked? Reload canceled.","Warning!")
18 | end
19 | elseif ans<=0 or ans==3 then rl=false
20 | end
21 | end
22 | if rl then
23 | editor.Quit(-1)
24 | editor.Editor(f,_,_,_,_,_,bit64.bor(F.EF_NONMODAL,F.EF_IMMEDIATERETURN,F.EF_OPENMODE_USEEXISTING),1,1)
25 | end
26 | end;
27 | }
28 |
--------------------------------------------------------------------------------
/Panel.CustomSortOther.lua:
--------------------------------------------------------------------------------
1 | -- Panel.CustomSortOther.lua
2 | -- v1.0.0.1
3 | -- Custom panel file sorts: by Name with StrCmpLogicalW, by FullPath length
4 | -- Keys: CtrlShiftF3 or from Menu "Sort by"
5 |
6 | local ffi=require'ffi'
7 | local C=ffi.C
8 | local Key="CtrlShiftF3"
9 |
10 | local desc111="Custom: by FullPath length"
11 | Panel.LoadCustomSortMode (100111, {
12 | Description=desc111; Indicator="lL";
13 | Compare=function(p1,p2)
14 | local l=C.wcslen(p1.FileName)-C.wcslen(p2.FileName)
15 | return l<0 and -1 or l>0 and 1 or 0
16 | end;
17 | })
18 |
19 | Macro {
20 | description=desc111; area="Shell"; key=Key;
21 | action=function() Panel.SetCustomSortMode(100111,0) end;
22 | }
23 |
24 | local shlwapi=ffi.load("shlwapi")
25 | local desc112="Custom: by Name with StrCmpLogicalW"
26 | Panel.LoadCustomSortMode (100112, {
27 | Description=desc112;
28 | Compare=function(pi1,pi2)
29 | return shlwapi.StrCmpLogicalW(pi1.FileName, pi2.FileName)
30 | end;
31 | Indicator="bB";
32 | })
33 |
34 | Macro {
35 | description=desc112; area="Shell"; key=Key;
36 | action=function() Panel.SetCustomSortMode(100112,0) end;
37 | }
38 |
--------------------------------------------------------------------------------
/HTML-XML.OneLine-MultiLine.lua:
--------------------------------------------------------------------------------
1 | -- HTML-XML.OneLine-MultiLine.lua
2 | -- v1.0.1.1
3 | -- Visual improvement of HTML-XML code (pretty print), creates a new file name~2.ext
4 | -- Keys: launch from Macro Browser alt.
5 |
6 | local string=string
7 | local srep = string.rep
8 |
9 | Macro {
10 | description="HTML-XML.OneLine->MultiLine"; area="Shell Editor";
11 | action = function()
12 | local eol,tab,fin = "\n","\t",""
13 | if Area.Shell then fin=APanel.Path0.."\\"..APanel.Current
14 | elseif Area.Editor then fin=Editor.FileName
15 | end
16 | local fname,fext = fin:match("^(.*)(%.[^%.\\]*)$")
17 | local fout = fext and fname.."~2"..fext or fin.."~2"
18 | local w=io.open(fout,"wb") w:write("") w:close()
19 | local r=io.open(fin, "rb")
20 | local a=io.open(fout,"ab")
21 |
22 | -- <(/?).+?(/?)>
23 | local i,t,p,m10,m20,v0 = 0,{},-1,"",""
24 | for l in r:lines() do
25 | l=l:gsub("^[%s%c]+",""):gsub("[%s%c]+$","")
26 | if l=="" then a:write(eol) if v0 then v0="" end
27 | else
28 | local z=true
29 | for m0,m1,v,m2,s in l:gmatch("(<([/!%?%[]?)(%[?[%w_%-:]+)[^>]-([/!%?%-%]]?)>)([^<]*)") do
30 | if m1=="/" then for j=i,1,-1 do if t[j][1]==v then p=t[j][2] i=j-1 break end end
31 | else if m10=="" and m20=="" then p=p+1 end if m2~="/" then i=i+1 t[i]={v,p} end
32 | end
33 | if v0 and (v~=v0 or (m1==m10 or m1=="")) then a:write(eol..srep(tab,p)) end
34 | a:write(m0..s)
35 | v0,m10,m20,z = v,m1,m2,false
36 | end
37 | if z then a:write(eol..srep(tab,p)..l) if v0 then v0="" end end
38 | end
39 | end
40 | a:close()
41 | r:close()
42 | end
43 | }
44 |
--------------------------------------------------------------------------------
/Panel.SelectFolders.lua:
--------------------------------------------------------------------------------
1 | -- Panel.SelectFolders.lua
2 | -- v1.0.0.1
3 | -- Extend Select Folders/Files Dialog
4 | -- 
5 | -- Keys: Grey+ Grey- CtrlF
6 |
7 | local F = far.Flags
8 | local Grey = {plus="29C03C36-9C50-4F78-AB99-F5DC1A9C67CD",minus="34614DDB-2A22-4EA9-BD4A-2DC075643F1B",cfg="A204FF09-07FA-478C-98C9-E56F61377BDE"}
9 | local uGrey = {plus=win.Uuid(Grey.plus),minus=win.Uuid(Grey.minus),cfg=win.Uuid(Grey.cfg)}
10 | local key,desc,mask,cmd,hDlg = "CtrlF","Extend Select Folders/Files Dialog"
11 |
12 | Macro {
13 | area="Dialog"; key=key; description=desc.." Macro";
14 | condition = function() return hDlg and (Dlg.Id==Grey.plus or Dlg.Id==Grey.minus) end;
15 | action = function()
16 | local gkey=Dlg.Id==Grey.plus
17 | far.SendDlgMessage(hDlg,F.DM_CLOSE,-1,0) far.DialogFree(hDlg) hDlg=nil
18 | cmd=panel.GetCmdLine(nil)
19 | panel.SetCmdLine(nil,"@far:config")
20 | mf.postmacro(Keys,"Enter")
21 | mf.postmacro(Menu.Select,"Panel.SelectFolders",1)
22 | mf.postmacro(Keys,"Enter Esc "..(gkey and "ADD" or "SUBTRACT"))
23 | end;
24 | }
25 |
26 | return Event({
27 | group="DialogEvent",
28 | description=desc.." Event",
29 | action = function(event,param)
30 | if event==F.DE_DLGPROCINIT and param.Msg==F.DN_INITDIALOG then
31 | local id = far.SendDlgMessage(param.hDlg,F.DM_GETDIALOGINFO)
32 | id = id and id.Id or ""
33 | if id==uGrey.plus or id==uGrey.minus then
34 | hDlg=param.hDlg
35 | far.SendDlgMessage(hDlg,F.DM_SETTEXT,1,(id==uGrey.plus and "Select" or "Deselect").." ["..(Far.GetConfig("Panel.SelectFolders") and "x" or " ").."] Folders [ "..key.." ]")
36 | if mask then far.SendDlgMessage(hDlg,F.DM_SETTEXT,2,mask) end
37 | end
38 | elseif event==F.DE_DLGPROCEND and param.Msg==F.DN_CLOSE then
39 | local id = far.SendDlgMessage(param.hDlg,F.DM_GETDIALOGINFO)
40 | id = id and id.Id or ""
41 | if id==uGrey.cfg then far.DialogFree(param.hDlg) panel.SetCmdLine(nil,cmd or "")
42 | elseif id==uGrey.plus or id==uGrey.minus then mask=tostring(far.SendDlgMessage(param.hDlg,F.DM_GETTEXT,2))
43 | end
44 | end
45 | end
46 | })
47 |
--------------------------------------------------------------------------------
/CommandLineF4.lua:
--------------------------------------------------------------------------------
1 | -- CommandLineF4.lua
2 | -- v1.1.2
3 | -- Editing command line content in the editor
4 | -- Keys: F4 in Panel with not empty command line, F2 in editor for save text to command line
5 |
6 | local function fwrite(s,f) local x,h = nil,io.open(f,"wb") if h then x=h:write(s or "") io.close(h) end return x end
7 |
8 | local F = far.Flags
9 | local name = "far.xxxxxx.cmd"
10 |
11 | local ffi = require'ffi'
12 | local C = ffi.C
13 | local table = table
14 | local tinsert = table.insert
15 |
16 | Macro {
17 | area="Shell"; key="F4"; flags="NotEmptyCommandLine"; description="Command Line -> Editor";
18 | action = function()
19 | local pc=ffi.cast("struct PluginStartupInfo*",far.CPluginStartupInfo()).PanelControl
20 | local l,x = "",panel.GetCmdLinePos(-1)
21 | local ln=pc(PANEL_ACTIVE,"FCTL_GETCMDLINE",0,nil)
22 | local cl=ffi.new("wchar_t[?]",ln)
23 | pc(PANEL_ACTIVE,"FCTL_GETCMDLINE",ln,cl)
24 | local cw=ffi.string(cl,(ln-1)*2)
25 | local f = win.GetEnv("TEMP").."\\"..name
26 | fwrite(cw,f)
27 | cw=ffi.string(cl,x*2)
28 | local _,y = regex.gsubW(cw,"\n","\n")
29 | cw=regex.matchW(cw,"(?:^|\n)(.+?)$")
30 | if cw then x=#cw/2 else x=1 end
31 | editor.Editor(f,nil,0,0,-1,-1,bit64.bor(F.EF_NONMODAL,F.EF_IMMEDIATERETURN,F.EF_OPENMODE_USEEXISTING),y+1,x,1200)
32 | end;
33 | }
34 |
35 | Macro {
36 | area="Editor"; key="F2"; description="Command Line <- Editor";
37 | condition = function() return editor.GetFileName():match("[^\\]+$")==name end;
38 | action = function()
39 | local text,len,nw,x,l = "",0,"\10\0" -- win.Utf8ToUtf16("\n")
40 | local pc=ffi.cast("struct PluginStartupInfo*",far.CPluginStartupInfo()).PanelControl
41 | local ec=ffi.cast("struct PluginStartupInfo*",far.CPluginStartupInfo()).EditorControl
42 | local ei=ffi.new("struct EditorInfo")
43 | ei.StructSize=ffi.sizeof(ei)
44 | if ec(-1,"ECTL_GETINFO",0,ei) then
45 | local y=tonumber(ei.CurLine)
46 | x=tonumber(ei.CurPos)
47 | l=tonumber(ei.TotalLines)-1
48 | local t,ln = {}
49 | local egs=ffi.new("struct EditorGetString")
50 | egs.StructSize=ffi.sizeof(egs)
51 | for i=0,l do
52 | if i==y then x=x+len/2+y end
53 | egs.StringNumber=i
54 | if ec(-1,"ECTL_GETSTRING",0,egs) then
55 | ln=egs.StringLength*2
56 | len=len+ln
57 | tinsert(t,ffi.string(egs.StringText,ln))
58 | end
59 | end
60 | text=table.concat(t,nw)
61 | end
62 | editor.Quit(-1)
63 | local cl=ffi.new("wchar_t[?]",len/2+l+1)
64 | ffi.copy(cl,text)
65 | pc(PANEL_ACTIVE,"FCTL_SETCMDLINE",0,cl)
66 | pc(PANEL_ACTIVE,"FCTL_SETCMDLINEPOS",x,nil)
67 | end;
68 | }
69 |
--------------------------------------------------------------------------------
/Panel.LYNX-motion.lua:
--------------------------------------------------------------------------------
1 | -- Panel.LYNX-motion.lua
2 | -- v1.0
3 | -- Extended lynx-motion style
4 | -- Very convenient navigation in panels with elevators through empty subfolders and etc.
5 | -- Keys: Left Right Enter
6 |
7 | Macro {
8 | area="Shell"; key="Left"; flags="EmptyCommandLine EnableOutput "; description="LYNX-style motion";
9 | condition = function() return APanel.Visible and APanel.ColumnCount==1 end;
10 | action = function()
11 | Keys('CtrlPgUp')
12 | end;
13 | }
14 |
15 | Macro {
16 | area="Shell"; key="Right"; flags="EmptyCommandLine EnableOutput"; description="LYNX-style motion";
17 | condition = function() return APanel.Visible and APanel.ColumnCount==1 end;
18 | action = function()
19 | Keys('CtrlPgDn')
20 | if Area.Current=="Shell" and APanel.Current==".." and panel.GetPanelInfo(nil,1).ItemsNumber>1 then Panel.SetPosIdx(0,2) end
21 | end;
22 | }
23 |
24 | Macro {
25 | area="Shell"; key="Enter"; flags="EmptyCommandLine EnableOutput"; description="LYNX-style motion";
26 | condition = function() return APanel.Visible end;
27 | action = function()
28 | if APanel.Current==".." then
29 | Keys('CtrlPgUp')
30 | while Area.Current=="Shell" and panel.GetPanelItem(nil,1,1).FileName==".." do
31 | if panel.GetPanelInfo(nil,1).ItemsNumber<=2 and not APanel.Path:match("^[\\/]?$") then Keys('CtrlPgUp') else break end
32 | end
33 | if APanel.Current==".." and panel.GetPanelInfo(nil,1).ItemsNumber>1 then Panel.SetPosIdx(0,2) end
34 | elseif panel.GetCurrentPanelItem(nil,1).FileAttributes:find("d") then
35 | Keys('CtrlPgDn')
36 | while Area.Current=="Shell" do
37 | if APanel.Current==".." and panel.GetPanelInfo(nil,1).ItemsNumber>1 then Panel.SetPosIdx(0,2) end
38 | if panel.GetPanelInfo(nil,1).ItemsNumber<=2 and APanel.Current~=".." and panel.GetCurrentPanelItem(nil,1).FileAttributes:find("d") then Keys('CtrlPgDn') else break end
39 | end
40 | else
41 | Keys('Enter')
42 | end
43 | end;
44 | }
45 |
46 | Macro {
47 | area="Disks"; key="Right"; flags="EmptyCommandLine EnableOutput"; description="LYNX-style motion";
48 | condition = function() return APanel.Visible end;
49 | action = function() Keys('Enter') end;
50 | }
51 |
52 | Macro {
53 | area="Disks"; key="Left"; flags="EmptyCommandLine EnableOutput"; description="LYNX-style motion";
54 | condition = function() return APanel.Visible end;
55 | action = function() end;
56 | }
57 |
58 | Macro {
59 | area="Dialog"; key="Right"; flags="EmptyCommandLine EnableOutput"; description="LYNX-style motion";
60 | condition = function() return APanel.Visible and Dlg.Owner=="3106D308-A685-415C-96E6-84C8EBB361FE" and Dlg.Id=="3731617B-3037-6363-632D-353933332D34" end;
61 | action = function()
62 | Keys('Esc CtrlPgDn')
63 | if Area.Current=="Shell" and APanel.Current==".." and panel.GetPanelInfo(nil,1).ItemsNumber>1 then Panel.SetPosIdx(0,2) end
64 | end;
65 | }
66 |
--------------------------------------------------------------------------------
/Panel.Files2HEX_ffi.lua:
--------------------------------------------------------------------------------
1 | -- Panel.Files2HEX_ffi.lua
2 | -- v1.0.0.2
3 | -- (un)HEX selected files, VERY FAST!
4 | -- Keys: launch from Macro Browser alt.
5 | -- author Shmuel, co-author AleXH
6 |
7 | local buf_size=0x10000
8 |
9 | local ffi=require 'ffi'
10 | local C=ffi.C
11 | ffi.cdef[[
12 | typedef struct {int a;} FILE;
13 | size_t fread(void*,size_t,size_t,FILE*);
14 | size_t fwrite(const void*,size_t,size_t,FILE*);
15 | FILE* _wfopen(const wchar_t*,const wchar_t*);
16 | int fclose(FILE*);
17 | ]]
18 |
19 | local b=bit
20 | local lshift,rshift = b.lshift,b.rshift
21 |
22 | Macro {
23 | area="Shell"; flags="NoPluginPanels NoFolders"; description="(un)HEX Files ffi";
24 | action=function()
25 | local t1=Far.UpTime
26 | if not APanel.Selected then Panel.Select(0,1,1,0) end
27 | while APanel.Selected do
28 | Panel.SetPosIdx(0,1,1)
29 | local fname = APanel.Path0.."\\"..APanel.Current
30 | local hex = fname:match("%.hex$") and true or false
31 | local name_in = win.Utf8ToUtf16(fname).."\0"
32 | fname = hex and fname:gsub("%.hex$","") or fname..".hex"
33 | local name_out = win.Utf8ToUtf16(fname).."\0"
34 | local mode_in,mode_out = "\114\0\98\0\0","\119\0\98\0\0" -- win.Utf8ToUtf16("rb").."\0", win.Utf8ToUtf16("wb").."\0"
35 | local f_in =assert(C._wfopen(ffi.cast("wchar_t*", name_in), ffi.cast("wchar_t*", mode_in)))
36 | local f_out=assert(C._wfopen(ffi.cast("wchar_t*", name_out), ffi.cast("wchar_t*", mode_out)))
37 | if hex
38 | then
39 | -- unHEX
40 | local ibuf,obuf = ffi.new("unsigned char[?]",buf_size*2),ffi.new("unsigned char[?]",buf_size)
41 | while true do
42 | local n = tonumber(C.fread(ibuf,1,ffi.sizeof(ibuf),f_in))
43 | if n==0 then break end
44 | for i=0,n/2-1 do
45 | local high = ibuf[i+i]
46 | local low = ibuf[i+i+1]
47 | high = high<65 and high-48 or high-55
48 | low = low<65 and low-48 or low-55
49 | obuf[i] = lshift(high,4)+low
50 | end
51 | C.fwrite(obuf,1,n/2,f_out)
52 | end
53 | else
54 | -- HEX
55 | local ibuf,obuf = ffi.new("unsigned char[?]",buf_size),ffi.new("unsigned char[?]",buf_size*2)
56 | while true do
57 | local n = tonumber(C.fread(ibuf,1,ffi.sizeof(ibuf),f_in))
58 | if n==0 then break end
59 | for i=0,n-1 do
60 | local low = ibuf[i]%16 --bit.band(ibuf[i],0xf)
61 | local high = rshift(ibuf[i],4)
62 | obuf[i+i] = high<10 and high+48 or high+55
63 | obuf[i+i+1] = low<10 and low+48 or low+55
64 | end
65 | C.fwrite(obuf,1,n+n,f_out)
66 | end
67 | end
68 | C.fclose(f_out)
69 | C.fclose(f_in)
70 | Panel.Select(0,0,1,0)
71 | end
72 | panel.UpdatePanel(nil,1)
73 | panel.RedrawPanel(nil,1)
74 | far.Message("Time: "..(Far.UpTime-t1).." ms","(un)HEX Files")
75 | end;
76 | }
77 |
--------------------------------------------------------------------------------
/Editor.SearchLinesWithMinMaxLength.lua:
--------------------------------------------------------------------------------
1 | -- Editor.SearchLinesWithMinMaxLength.lua
2 | -- v1.3.2.1
3 | -- Search for lines with minimum and maximum length, excluding the first and last lines, they are often empty
4 | -- 
5 | -- Press the [ Min ] or [ Max ] button for to go to this line
6 | -- Required: MessageX.lua in the modules folder
7 | -- Keys: F3
8 |
9 | local MessageX=require'MessageX'
10 |
11 | local e=editor
12 | local GetInfo,GetStringW,SetPosition = e.GetInfo,e.GetStringW,e.SetPosition
13 |
14 | local w=win
15 | local Utf16ToUtf8,WideCharToMultiByte = w.Utf16ToUtf8,w.WideCharToMultiByte
16 |
17 | Macro {
18 | description="Search Lines with MinMax Lengths";
19 | area="Editor"; key="F3";
20 | action=function()
21 | local ttime=far.FarClock()
22 | local MinText,MaxText,LineInfo,StringNumber,MinNumber,MaxNumber,MinSymbols,MaxSymbols = "","",{},1,0,0,math.huge,0
23 | local EGI=GetInfo()
24 | local EditorID,CodePage,TotalLines = EGI.EditorID,EGI.CodePage,EGI.TotalLines
25 | while true do
26 | LineInfo=GetStringW(EditorID,StringNumber,0)
27 | if LineInfo then
28 | local Symbols=LineInfo.StringLength
29 | if Symbols1 and StringNumberMaxSymbols then MaxText,MaxNumber,MaxSymbols = LineInfo.StringText,StringNumber,Symbols
31 | end
32 | StringNumber=StringNumber+1
33 | else break
34 | end
35 | end
36 | local MaxLen,MinPf,MaxPf,MinBytes,MaxBytes = 2000,"",""
37 | if MinSymbols>MaxLen then MinText=MinText:sub(0,MaxLen) MinPf=">" end
38 | if MaxSymbols>MaxLen then MaxText=MaxText:sub(0,MaxLen) MaxPf=">" end
39 | if CodePage>=1200 and CodePage<=1201
40 | then MinBytes,MaxBytes,MinPf,MaxPf = MinSymbols*2,MaxSymbols*2,"",""
41 | else MinBytes,MaxBytes = #WideCharToMultiByte(MinText,CodePage),#WideCharToMultiByte(MaxText,CodePage)
42 | end
43 | MinText=Utf16ToUtf8(MinText)
44 | MaxText=Utf16ToUtf8(MaxText)
45 | local spc='\194\183'
46 | local tab='\26'
47 | local function show(s)
48 | s=s:gsub('%d+%.?%d*','<#2s>%1<#rs>')
49 | s=s:gsub(' +','<#1s>%1<#rs>')
50 | s=s:gsub(' ',spc)
51 | s=s:gsub('\t+','<#1s>%1<#rs>')
52 | s=s:gsub('\t',tab)
53 | return s
54 | end
55 | MinText=show(MinText)
56 | MaxText=show(MaxText)
57 | ttime=far.FarClock()-ttime
58 | local res=MessageX(
59 | ' MinLine: <#1s>'..MinNumber..'<#rs> Symbols: <#1s>'..MinSymbols..'<#rs> Bytes: <#1s>'..MinPf..MinBytes..'<#rs>\n'..MinText..' \n\n'..
60 | ' MaxLine: <#1s>'..MaxNumber..'<#rs> Symbols: <#1s>'..MaxSymbols..'<#rs> Bytes: <#1s>'..MaxPf..MaxBytes..'<#rs>\n'..MaxText..' \n\nTime: <#9s>'..ttime..'<#rs> mcs',
61 | 'Search Lines with MinMax Lengths',
62 | 'Min;Max;Cancel','c'
63 | )
64 | if res==1 then SetPosition(EditorID,{CurLine=MinNumber})
65 | elseif res==2 then SetPosition(EditorID,{CurLine=MaxNumber})
66 | end
67 | end
68 | }
69 |
--------------------------------------------------------------------------------
/iptv.lua:
--------------------------------------------------------------------------------
1 | -- iptv.lua
2 | -- v1.0.5
3 | -- Combining free, frequently updated iptv sheets into one My.m3u, duplicate links removed
4 | -- Launch: in cmdline Far.exe: lua:@iptv.lua, or lfjit.exe iptv.lua, or lflua.exe iptv.lua
5 |
6 | -- replace the path with your own
7 | local dir=win.GetEnv('APPDATA')..'\\IP-TV Player\\'
8 | --local dir=win.GetEnv('TEMP')..'\\'
9 | local fname=dir..'My.m3u'
10 | -- list of links to free playlists
11 | local urls={
12 | --"http://help.a1.by/_files/TelecomTV/TelecomTVpacket/TVPACKET2.m3u",
13 | "https://iptvm3u.ru/hdlist.m3u",
14 | "http://iptvm3u.ru/onelist.m3u",
15 | "https://smarttvnews.ru/apps/iptvchannels.m3u",
16 | "https://smarttvnews.ru/apps/AutoIPTV.m3u",
17 | "https://smarttvnews.ru/apps/freeiptv.m3u",
18 | "https://webarmen.com/my/iptv/auto.nogrp.q.m3u"
19 | }
20 |
21 | local function fread(f) local x,h = nil,io.open(f,"rb") if h then x=h:read("*all") io.close(h) end return x end
22 | local function fwrite(f,s) local x,h = nil,io.open(f,"wb") if h then x=h:write(s or "") io.close(h) end return x end
23 | local function GetPage(x)
24 | local s=""
25 | if x then
26 | if panel then panel.GetUserScreen() end
27 | s=io.popen("curl.exe "..x,"rb"):read("*all")
28 | if panel then panel.SetUserScreen() end
29 | end
30 | return s
31 | end
32 |
33 | local pgm,head = {},'#EXTM3U\n#EXTINF:-1,-= Update: '..os.date("%d.%m.%Y %H:%M")..' =-\nhttp://127.0.0.1/logo.png\n'
34 | for j=1,#urls do
35 | local i,s = 1,','..j..': '
36 | local l=GetPage(urls[j]):gsub("#EXTGRP:[^\n]-\n",""):gsub(", +",",")
37 | local name=urls[j]:match("/([^/]+)$")
38 | fwrite(dir..name,l) -- save individual playlists
39 | head=head..'#EXTINF:-1 '..s..name..'\nhttp://127.0.0.1/pls'..j..'.png\n'
40 | for h,u in (l.."\n"):gmatch("(#EXTINF:[^\r\n]-)\r?\n(%w%w-://[^\r\n]-)\r?\n") do -- get channel's headers and urls
41 | if h and u then table.insert(pgm,{i=i,h=h:gsub(' *,',s),u=u}) i=i+1 end
42 | end
43 | end
44 |
45 | -- Adult filter
46 | for i=#pgm,1,-1 do
47 | local s=pgm[i].h:match(", -%d+: (.+)$")
48 | if s then
49 | local l=s:gsub("[ |]+"," "):gsub("^Q%d ",""):lower()
50 | if l:find("18%+") or l:find("adult") or l:find("sex") or l:find("xxx") or l:find("porn") or l:find("traffic") then table.remove(pgm,i) end
51 | end
52 | end
53 |
54 | table.sort(pgm,function(a,b) return a.u Top
58 | local i,s = x:match(", -(%d+): (.+)$")
59 | local p,q,l = "1","5",""
60 | if i and s then
61 | l=s:gsub("[ |]+"," "):gsub("^Q%d ",""):lower()..i
62 | if l:find(" 4k") then q="0"
63 | elseif l:find("uhd") then q="1"
64 | elseif l:find("qhd") then q="2"
65 | elseif l:find("fhd") then q="3"
66 | elseif l:find("hd") then q="4"
67 | end
68 | end
69 | return p..q..l
70 | end
71 | table.sort(pgm,function(a,b) return comp(a.h)\n\n\n\n\n'
55 | local tp2={}
56 | for i=1,#tp do if i>1 and tp[i][6]<=tp[i-1][7]+1 then if tp[i][7]>tp[i-1][7] then tp2[#tp2][2]=tp[i][9] end else tinsert(tp2,{tp[i][8],tp[i][9]}) end end
57 | for i=1,#tp2 do txt=txt..'\n' end
58 | txt=txt..'\n'
59 | local src=AppData..'\\uTorrent\\btpolicy.xml'
60 | local old=fread(src)
61 | local size=old and #old/2 or 6000
62 | local new=ssub(txt,291,-1)~=ssub(old,291,-1)
63 | if not old then
64 | fwrite(txt,src)
65 | --far.MkLink(src ,tmp.."btpolicy.xml" ,F.LINK_SYMLINKFILE,F.MLF_SHOWERRMSG+F.MLF_HOLDTARGET)
66 | win.system('ln.exe -s '..src..' '..tmp..'btpolicy.xml')
67 | elseif old and new and #txt>=size then
68 | --far.CopyToClipboard(txt)
69 | fwrite(txt,src)
70 | --far.MkLink(src ,tmp.."btpolicy.xml" ,F.LINK_SYMLINKFILE,F.MLF_SHOWERRMSG+F.MLF_HOLDTARGET)
71 | win.system('ln.exe -s '..src..' '..tmp..'btpolicy.xml')
72 | local src0=AppData..'btpolicy0.xml'
73 | fwrite(old,src0)
74 | --far.MkLink(src0,tmp.."btpolicy0.xml",F.LINK_SYMLINKFILE,F.MLF_SHOWERRMSG+F.MLF_HOLDTARGET)
75 | win.system('ln.exe -s '..src0..' '..tmp..'btpolicy0.xml')
76 | elseif old and not new then io.write('\nWithout changes\n')
77 | elseif #txt=1
82 | then table.insert(t,{y,s})
83 | else
84 | local f=GetFileName(l)
85 | if f then
86 | if #t>1 then FileSave(t) t={} break end
87 | t[1]={f,nil}
88 | end
89 | end
90 | end
91 | if #t>1 then FileSave(t) end
92 | end;
93 | }
94 |
95 | Macro {
96 | area="Editor"; key=MacroKey; flags=""; description="Grep: Save all lines in all files"; filemask=FileMask;
97 | action=function()
98 | local t={}
99 | for j=1,GetInfo(-1).TotalLines do
100 | local l=GetString(-1,j).StringText
101 | local y,s = l:match(LinePattern)
102 | if y and s and #t>=1
103 | then table.insert(t,{y,s})
104 | else
105 | local f=GetFileName(l)
106 | if f then
107 | if #t>1 then FileSave(t) t={} end
108 | t[1]={f,nil}
109 | end
110 | end
111 | end
112 | if #t>1 then FileSave(t) end
113 | end;
114 | }
115 |
--------------------------------------------------------------------------------
/Panel.ShiftF[56].lua:
--------------------------------------------------------------------------------
1 | -- Panel.ShiftF[56].lua
2 | -- v1.3.4.0
3 | -- Extend Panel (Shift)?F[56] Dialog
4 | -- Hint: Press CtrlR and set replace [x] data for copy the source file to the target file with multiple hardlinks
5 | -- Required: FAR3 build >= 5467
6 | -- Keys: none, to use put in the scripts folder
7 |
8 | local repkey,desc,repdata,Act,pSIN,hDlg = "CtrlR","Replace data for Copy/Move Dialog",false,""
9 | local TDlg={
10 | far.Guids.CopyFilesId, -- "F5"
11 | far.Guids.MoveFilesId, -- "F6"
12 | far.Guids.CopyCurrentOnlyFileId, -- "SF5"
13 | far.Guids.MoveCurrentOnlyFileId, -- "SF6"
14 | far.Guids.CopyOverwriteId -- Warning
15 | }
16 | local TGuid={
17 | [win.Uuid(TDlg[1])]="F5",
18 | [win.Uuid(TDlg[2])]="F6",
19 | [win.Uuid(TDlg[3])]="SF5",
20 | [win.Uuid(TDlg[4])]="SF6"
21 | }
22 | local wDlg=win.Uuid(TDlg[5])
23 | local btnOK=18 -- dialog execution button
24 | local btnOverwrite=10 -- dialog overwrite button
25 |
26 | local lng,key,btn,wrn
27 | local lang={
28 | English={re=regex.new("^(Copy|Clone|Rename or move|Rename|Move)"),
29 | Copy="Copy",Clone="Clone",Move="Move",Rename="Rename",
30 | MsgHdr="Warning!",MsgTXT="Path or file name don't specified"},
31 | Russian={re=regex.new("^(Копировать|Клонировать|Переименовать или перенести|Переименовать|Переместить)"),
32 | Copy="Копировать",Clone="Клонировать",Move="Переместить",Rename="Переименовать",
33 | MsgHdr="Внимание!",MsgTXT="Путь или имя файла не заданы"}
34 | }
35 |
36 | local F=far.Flags
37 |
38 | local Proc=function(hDlg,PF,txt)
39 | local ret
40 | if txt:find(":$") or PF==txt:gsub(":%s*$","") then ret=true else ret=txt:find("[\\/]") end
41 | Act,pSIN = ""
42 | if key.F5 or key.F6 then
43 | pSIN=panel.GetPanelInfo(nil,1).SelectedItemsNumber
44 | if pSIN>1 then repdata=false end
45 | end
46 | if key.F5 then Act=(ret or pSIN>1) and lang[lng].Copy or lang[lng].Clone
47 | elseif key.F6 then Act=(ret or pSIN>1) and lang[lng].Move or lang[lng].Rename
48 | elseif key.SF5 then pSIN=1 Act=ret and lang[lng].Copy or lang[lng].Clone
49 | elseif key.SF6 then pSIN=1 Act=ret and lang[lng].Move or lang[lng].Rename
50 | end
51 | hDlg:send(F.DM_SETTEXT,1,(key.F5 or key.F6) and Act or "[Shift] "..Act)
52 | txt=hDlg:send(F.DM_GETTEXT,2)
53 | hDlg:send(F.DM_SETTEXT,2,lang[lng].re:gsub(txt,Act))
54 | hDlg:send(F.DM_SETTEXT,btnOK,(lng=="English" and (key.F6 or key.SF6)) and Act:sub(1,-2).."&e" or "&"..Act)
55 | return ret
56 | end
57 |
58 | Event {
59 | group="DialogEvent";
60 | description="Extend Panel (Shift)?F[56] Dialog";
61 | condition=function(Event,Param)
62 | if Event==F.DE_DLGPROCINIT then
63 | local id=Param.hDlg:send(F.DM_GETDIALOGINFO)
64 | id=id and id.Id or ""
65 | btn=TGuid[id]
66 | wrn=wDlg==id
67 | if btn and pSIN==1 then
68 | hDlg=Param.hDlg
69 | far.SendDlgMessage(hDlg,F.DM_SETTEXT,1,Act.." and replace ["..(repdata and "x" or " ").."] data [ "..repkey.." ]")
70 | end
71 | lng=Far.GetConfig('Language.Main')
72 | return Area.Dialog and btn and (lng=='English' or lng=='Russian') or wrn
73 | end
74 | end;
75 | action=function(Event,Param)
76 | if btn then
77 | key={F5=false,F6=false,SF5=false,SF6=false}
78 | key[btn]=true
79 | end
80 | local PF,PP,AP,AC = PPanel.Format,PPanel.Path,APanel.Path,APanel.Current
81 | if btn and Param.Msg==F.DN_INITDIALOG then
82 | repdata=false
83 | if PP:find("^[A-Za-z]:$") then PP=PP.."\\" end
84 | local txt=PF=="" and PP or PF..":"
85 | Param.hDlg:send(F.DM_SETTEXT,3,Proc(Param.hDlg,PF,txt) and txt or AC)
86 | elseif btn and Param.Msg==F.DN_EDITCHANGE and Param.Param1==3 then
87 | Proc(Param.hDlg,PF,Param.hDlg:send(F.DM_GETTEXT,3))
88 | elseif btn and Param.Msg==F.DN_CLOSE and Param.Param1==btnOK and Param.hDlg:send(F.DM_GETTEXT,3)=="" then
89 | far.Message(lang[lng].MsgTXT,lang[lng].MsgHdr,nil,"w")
90 | Param.hDlg:send(F.DM_SETFOCUS,3)
91 | return 0
92 | elseif wrn and repdata and Param.Msg==F.DN_CLOSE and Param.Param1==btnOverwrite then
93 | local source=AP..(AP:sub(-1,-1)=="\\" and "" or "\\")..AC
94 | local target=PP..(PP:sub(-1,-1)=="\\" and "" or "\\")..AC
95 | if key.F5 or key.SF5 then win.CopyFile(source,target)
96 | elseif key.F6 or key.SF6 then win.CopyFile(source,target) win.DeleteFile(source)
97 | end
98 | return 1
99 | end
100 | return false
101 | end
102 | }
103 |
104 | Macro {
105 | area="Dialog"; key=repkey; description=desc.." Macro";
106 | condition = function() return hDlg and (Dlg.Id==TDlg[1] or Dlg.Id==TDlg[2] or Dlg.Id==TDlg[3] or Dlg.Id==TDlg[4]) end;
107 | action = function() repdata = pSIN and pSIN==1 and not repdata or false end;
108 | }
109 |
--------------------------------------------------------------------------------
/ansicolors.lua:
--------------------------------------------------------------------------------
1 | -- ansicolors.lua
2 | -- v1.1.2
3 | -- Ansi colors for console
4 | -- 
5 | -- Tags format: **<#xya>**, **x** - foreground color **0..f**, **y** - background color **0..f**, **a** - attributes [rbdiul]
6 | -- **r** - restore default color for foreground/background, **s** - skip, don't change foreground/background color
7 | -- Examples:
8 | -- ``` lua
9 | -- local colors = require'ansicolors'
10 | -- print(colors('%{bright italic red underline}hello'))
11 | -- print(colors('<#ecuib>Hello<#rrr>, World!'))
12 | -- ```
13 |
14 | -- Copyright (c) 2009 Rob Hoelz
15 | -- Copyright (c) 2011 Enrique García Cota
16 | --
17 | -- Permission is hereby granted, free of charge, to any person obtaining a copy
18 | -- of this software and associated documentation files (the "Software"), to deal
19 | -- in the Software without restriction, including without limitation the rights
20 | -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
21 | -- copies of the Software, and to permit persons to whom the Software is
22 | -- furnished to do so, subject to the following conditions:
23 | --
24 | -- The above copyright notice and this permission notice shall be included in
25 | -- all copies or substantial portions of the Software.
26 | --
27 | -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
28 | -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29 | -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
30 | -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
31 | -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
32 | -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
33 | -- THE SOFTWARE.
34 |
35 | local s = string
36 | local char,find,format,rep,sub,gsub,match,gmatch = s.char,s.find,s.format,s.rep,s.sub,s.gsub,s.match,s.gmatch
37 |
38 | local b = bit
39 | local band = b.band
40 |
41 | local t = table
42 | local concat = t.concat
43 |
44 | -- support detection
45 | local function isWindows()
46 | return type(package) == "table" and type(package.config) == "string" and sub(package.config,1,1) == "\\"
47 | end
48 |
49 | local supported = not isWindows()
50 | if isWindows() then supported = win.GetEnv("ANSICON") end
51 |
52 | local keys = {
53 | -- reset
54 | r = 0, -- reset all attributes
55 | reset = 0, -- reset all attributes
56 |
57 | -- attributes
58 | b = 1, -- bold for 8..15 color value
59 | bright = 1, -- bold for 8..15 color value
60 | bold = 60,
61 | d = 2, -- dim
62 | dim = 2,
63 | i = 3, -- italic
64 | italic = 3,
65 | u = 4, -- underline
66 | underline = 4,
67 | l = 5, -- blink
68 | blink = 5,
69 | reverse = 7,
70 | hidden = 8,
71 |
72 | -- foreground colors
73 | black = 30,
74 | red = 31,
75 | green = 32,
76 | yellow = 33,
77 | blue = 34,
78 | magenta = 35,
79 | cyan = 36,
80 | white = 37,
81 | dfg = 39, -- default foreground color
82 |
83 | -- background colors
84 | blackbg = 40,
85 | redbg = 41,
86 | greenbg = 42,
87 | yellowbg = 43,
88 | bluebg = 44,
89 | magentabg = 45,
90 | cyanbg = 46,
91 | whitebg = 47,
92 | dbg = 49 -- default background color
93 | }
94 |
95 | local colors = {
96 | --[[0]] 0, -- black
97 | --[[1]] 4, -- blue
98 | --[[2]] 2, -- green
99 | --[[3]] 6, -- cyan
100 | --[[4]] 1, -- red
101 | --[[5]] 5, -- magenta
102 | --[[6]] 3, -- yellow
103 | --[[7]] 7 -- white
104 | }
105 |
106 | local esc,pbuffer,buffer = char(27) .. "["
107 |
108 | local function escapeNumber(number) pbuffer = pbuffer + 1 buffer[pbuffer] = esc .. tostring(number) .. "m" end
109 |
110 | local function color(symbol, base)
111 | local number
112 | if symbol == "s" then -- skip
113 | elseif symbol == "r" then number = base + 9
114 | else
115 | symbol = tonumber(symbol, 16)
116 | number = colors[band(symbol, 7) + 1] + base
117 | if band(symbol, 8) > 0 then number = number + 60 end
118 | end
119 | escapeNumber(number)
120 | end
121 |
122 | local function attributes(str, mask)
123 | local bold
124 | for word in gmatch(str, mask) do if word == "bold" then bold = true break end end
125 | for word in gmatch(str, mask) do
126 | local number = keys[word]
127 | assert(number, "Unknown key: " .. word)
128 | if number ~= 60 then
129 | if bold and number >= 30 and number <= 37 or number >= 40 and number <= 47 then number = number + 60 end
130 | escapeNumber(number)
131 | end
132 | end
133 | end
134 |
135 | local function escapeKeys(str)
136 | if not supported then return "" end
137 | pbuffer,buffer = 0,{}
138 | if find(str, "^#[%xsr][%xsr][rbdiul]*$") then
139 | local fg,bg,str = match(str, "^#(.)(.)(.*)$")
140 | color(fg, 30) color(bg, 40)
141 | attributes(str, "%w")
142 | else attributes(str, "%w+")
143 | end
144 | return concat(buffer)
145 | end
146 |
147 | local function replaceCodes(str)
148 | str = gsub(str, "(%%{([a-z ]-)})", function(_, str) return escapeKeys(str) end)
149 | str = gsub(str, "(<(#[%xsr][%xsr][rbdiul]*)>)", function(_, str) return escapeKeys(str) end)
150 | return str
151 | end
152 |
153 | local function ansicolors(str) return replaceCodes("%{reset}".. tostring(str or '') .. "%{reset}") end
154 |
155 | return setmetatable({noReset = replaceCodes}, {__call = function (_, str) return ansicolors(str) end})
156 |
--------------------------------------------------------------------------------
/Editor.LatCyrMixHighlighting.moon:
--------------------------------------------------------------------------------
1 | -- Editor.LatCyrMixHighlighting.moon
2 | -- v1.1.3.6
3 | -- Highlighting mixed Latin and Cyrillic letters in the editor
4 | -- 
5 | -- Required: MessageX.lua in modules folder
6 | -- Keys: F3
7 | -- author zg, co-author AleXH
8 | -- Url: https://forum.ru-board.com/topic.cgi?forum=5&topic=49572&start=2460#3
9 | -- prototype: https://forum.farmanager.com/viewtopic.php?f=60&t=8674
10 |
11 | -- default values
12 | ExecDelay=2
13 | ShowTimeofProcessing=true
14 | VisibilityColor=0xFF000000
15 | ForegroundColor=VisibilityColor+9
16 | BackgroundColor=VisibilityColor+1
17 |
18 | f=far
19 | F,AdvControl,Colors,FarClock = f.Flags,f.AdvControl,f.Colors,f.FarClock
20 |
21 | b=bit64
22 | bor,band = b.bor,b.band
23 |
24 | m=math
25 | min,fmod = m.min,m.fmod
26 |
27 | e=editor
28 | AddColor,DelColor,GetInfo,GetStringW,Redraw,TabToReal = e.AddColor,e.DelColor,e.GetInfo,e.GetStringW,e.Redraw,e.TabToReal
29 |
30 | Flags=F.ECF_AUTODELETE
31 | MessageX=require'MessageX'
32 |
33 | editors={}
34 | colors={
35 | {regex.new "/(\\s+)(\\S|$)/"
36 | {Flags:bor F.FCF_FG_4BIT,F.FCF_BG_4BIT
37 | ForegroundColor:ForegroundColor
38 | BackgroundColor:BackgroundColor}}
39 | {regex.new "/([a-zA-Z]+)([а-яёА-ЯЁ]+)|([а-яёА-ЯЁ]+)([a-zA-Z]+)/"
40 | {Flags:bor F.FCF_FG_4BIT,F.FCF_BG_4BIT
41 | ForegroundColor:ForegroundColor+5
42 | BackgroundColor:BackgroundColor+3}}
43 | }
44 | colorguid=win.Uuid "A1811CF8-C7AA-4474-A204-F8306028C7A7"
45 |
46 | GetEditorData=(id)->
47 | data=editors[id]
48 | if not data
49 | editors[id]=
50 | start:0
51 | finish:0
52 | data=editors[id]
53 | data
54 |
55 | RemoveColors=(id,data)->
56 | for ii=data.start,data.finish
57 | DelColor id,ii,0,colorguid
58 |
59 | ProcessColors=(id,update)->
60 | data=GetEditorData id
61 | RemoveColors id,data
62 | update data
63 |
64 | count,ttime0,ttime1=0,0,0
65 | Event
66 | group:"EditorEvent"
67 | condition:(id,event,param)->
68 | return editors[id]
69 | action:(id,event,param)->
70 | if event==F.EE_CLOSE
71 | editors[id]=nil
72 | if event==F.EE_REDRAW
73 | count=count+1
74 | ei=GetInfo id
75 | if ei
76 | ttime=FarClock!
77 | ProcessColors ei.EditorID,(data)->
78 | data.start=ei.TopScreenLine
79 | data.finish=min ei.TopScreenLine+ei.WindowSizeY,ei.TotalLines
80 | for ii=data.start,data.finish
81 | RealLeftPos=TabToReal(ei.EditorID,ii,ei.LeftPos)-1
82 | gsw=GetStringW ei.EditorID,ii
83 | line=gsw.StringText
84 | length=gsw.StringLength
85 | if RealLeftPos<=length
86 | RightBorder=RealLeftPos+ei.WindowSizeX
87 | if length
114 | wincount=AdvControl F.ACTL_GETWINDOWCOUNT,0,0
115 | for ii=1,wincount
116 | info=AdvControl F.ACTL_GETWINDOWINFO,ii,0
117 | if info and F.WTYPE_EDITOR==info.Type
118 | ProcessColors info.Id,(data)->
119 | data.start=0
120 | data.finish=0
121 |
122 | Macro
123 | description:description
124 | area:"Editor"
125 | key:"F3"
126 | action:->
127 | count,ttime0=0,0
128 | id=GetInfo().EditorID
129 | Msg=(s)->
130 | Redraw id
131 | if ShowTimeofProcessing
132 | Answer=MessageX s.."\n\nEvent count: <#1s>"..count.."<#rs>\nTime: <#1s>"..ttime0.."<#rs> mcs","LatCyrMixHighlighting","Close;Hide","c","","",ExecDelay
133 | if Answer==2
134 | ShowTimeofProcessing=false
135 | if not editors[id]
136 | tFarColor=AdvControl F.ACTL_GETCOLOR,Colors.COL_EDITORTEXT,0
137 | if tFarColor
138 | BackgroundColor=bor tFarColor.BackgroundColor,VisibilityColor
139 | if 7 ON <#rr>"
154 | else
155 | editor.SetParam id,F.ESPT_SHOWWHITESPACE,0
156 | ProcessColors id,(data)->
157 | data.start=1
158 | data.finish=1
159 | editors[id]=nil
160 | Msg "\nStatus: <#c4> OFF <#rr>"
161 |
--------------------------------------------------------------------------------
/Editor.CyrSpaceHighlighting.moon:
--------------------------------------------------------------------------------
1 | -- Editor.CyrSpaceHighlighting.moon
2 | -- v1.1.3.6
3 | -- Highlighting Cyrillic and space symbols
4 | -- 
5 | -- 
6 | -- 
7 | -- Required: MessageX.lua in modules folder
8 | -- Keys: F3
9 | -- author zg, co-author AleXH
10 | -- Url: https://forum.ru-board.com/topic.cgi?forum=5&topic=48136&start=960#17
11 | -- prototype: https://forum.farmanager.com/viewtopic.php?f=60&t=8674
12 |
13 | -- default values
14 | ExecDelay=2
15 | ShowTimeofProcessing=true
16 | VisibilityColor=0xFF000000
17 | ForegroundColor=VisibilityColor+9
18 | BackgroundColor=VisibilityColor+1
19 |
20 | f=far
21 | F,AdvControl,Colors,FarClock = f.Flags,f.AdvControl,f.Colors,f.FarClock
22 |
23 | b=bit64
24 | bor,band = b.bor,b.band
25 |
26 | m=math
27 | min,fmod = m.min,m.fmod
28 |
29 | e=editor
30 | AddColor,DelColor,GetInfo,GetStringW,Redraw,TabToReal = e.AddColor,e.DelColor,e.GetInfo,e.GetStringW,e.Redraw,e.TabToReal
31 |
32 | Flags=F.ECF_AUTODELETE
33 | MessageX=require'MessageX'
34 |
35 | editors={}
36 | colors={
37 | {regex.new "/(\\s+)(\\S|$)/"
38 | {Flags:bor F.FCF_FG_4BIT,F.FCF_BG_4BIT
39 | ForegroundColor:ForegroundColor
40 | BackgroundColor:BackgroundColor}}
41 | {regex.new "/([а-яёА-ЯЁ]+)([^а-яёА-ЯЁ]|$)/"
42 | {Flags:bor F.FCF_FG_4BIT,F.FCF_BG_4BIT
43 | ForegroundColor:ForegroundColor+5
44 | BackgroundColor:BackgroundColor+3}}
45 | -- regex.new [[/([-+*:.,;!?~@#$%^&\\\/]+?)([-+*:.,;!?~@#$%^&\\\/]|$)/]]
46 | -- {Flags:bor F.FCF_FG_4BIT,F.FCF_BG_4BIT
47 | -- ForegroundColor:ForegroundColor+6
48 | -- BackgroundColor:BackgroundColor}
49 | }
50 | colorguid=win.Uuid "F4B5E624-16F6-4243-9A3D-763097C72EAA"
51 |
52 | GetEditorData=(id)->
53 | data=editors[id]
54 | if not data
55 | editors[id]=
56 | start:0
57 | finish:0
58 | data=editors[id]
59 | data
60 |
61 | RemoveColors=(id,data)->
62 | for ii=data.start,data.finish
63 | DelColor id,ii,0,colorguid
64 |
65 | ProcessColors=(id,update)->
66 | data=GetEditorData id
67 | RemoveColors id,data
68 | update data
69 |
70 | count,ttime0,ttime1=0,0,0
71 | Event
72 | group:"EditorEvent"
73 | condition:(id,event,param)->
74 | return editors[id]
75 | action:(id,event,param)->
76 | if event==F.EE_CLOSE
77 | editors[id]=nil
78 | if event==F.EE_REDRAW
79 | count=count+1
80 | ei=GetInfo id
81 | if ei
82 | ttime=FarClock!
83 | ProcessColors ei.EditorID,(data)->
84 | data.start=ei.TopScreenLine
85 | data.finish=min ei.TopScreenLine+ei.WindowSizeY,ei.TotalLines
86 | for ii=data.start,data.finish
87 | RealLeftPos=TabToReal(ei.EditorID,ii,ei.LeftPos)-1
88 | gsw=GetStringW ei.EditorID,ii
89 | line=gsw.StringText
90 | length=gsw.StringLength
91 | if RealLeftPos<=length
92 | RightBorder=RealLeftPos+ei.WindowSizeX
93 | if length
114 | wincount=AdvControl F.ACTL_GETWINDOWCOUNT,0,0
115 | for ii=1,wincount
116 | info=AdvControl F.ACTL_GETWINDOWINFO,ii,0
117 | if info and F.WTYPE_EDITOR==info.Type
118 | ProcessColors info.Id,(data)->
119 | data.start=0
120 | data.finish=0
121 |
122 | Macro
123 | description:description
124 | area:"Editor"
125 | key:"F3"
126 | action:->
127 | count,ttime0=0,0
128 | id=GetInfo!.EditorID
129 | Msg=(s)->
130 | Redraw id
131 | if ShowTimeofProcessing
132 | Answer=MessageX s.."\n\nEvent count: <#1s>"..count.."<#rs>\nTime: <#1s>"..ttime0.."<#rs> mcs","CyrSpaceHighlighting","Close;Hide","c","","",ExecDelay
133 | if Answer==2
134 | ShowTimeofProcessing=false
135 | if not editors[id]
136 | tFarColor=AdvControl F.ACTL_GETCOLOR,Colors.COL_EDITORTEXT,0
137 | if tFarColor
138 | BackgroundColor=bor tFarColor.BackgroundColor,VisibilityColor
139 | if 7 ON <#rr>"
154 | else
155 | editor.SetParam id,F.ESPT_SHOWWHITESPACE,0
156 | ProcessColors id,(data)->
157 | data.start=1
158 | data.finish=1
159 | editors[id]=nil
160 | Msg "\nStatus: <#c4> OFF <#rr>"
161 |
--------------------------------------------------------------------------------
/FarExit.lua:
--------------------------------------------------------------------------------
1 | -- FarExit.lua
2 | -- v1.1.0.4
3 | -- Extend Quit Far Dialog
4 | -- 
5 | -- Required: MessageX.lua in the modules folder
6 | -- Keys: F10
7 |
8 | local F = far.Flags
9 | local GuidEditAskSaveId = far.Guids.EditAskSaveId
10 | local uGuidEditAskSaveId = win.Uuid(GuidEditAskSaveId)
11 | local uGuidFarAskQuitId = win.Uuid(far.Guids.FarAskQuitId)
12 | local GuidScreensSwitchId = far.Guids.ScreensSwitchId
13 | local uGuidScreensSwitchId = win.Uuid(GuidScreensSwitchId)
14 | local GuidFarExitId = "FA70F0B0-AE94-4CB2-BB17-D9F8F6DEC66B"
15 | local uGuidFarExitId = win.Uuid(GuidFarExitId)
16 | local bYES,bNO,bCANCEL,bSAVE,bEXIT = 4,5,6,1,2
17 | local FarExitFlag,FarExitCode,hDlg = true
18 | local key,desc = "0","Extend Quit Dialog"
19 | local dialogs,viewers,editors,edmod = 0,0,0,0
20 |
21 | local MessageX=require'MessageX'
22 |
23 | local function Title() return viewers==0 and editors==0 and "Quit" or "Quit ["..(FarExitFlag and "x" or " ").."]" end
24 |
25 | local function Message()
26 | local ss,s = ""
27 | if dialogs>0 then ss=ss.." Opened Dialog(s): "..dialogs.."\n" end
28 | if viewers>0 then ss=ss.." Opened Viewer(s): "..viewers.."\n" end
29 | if editors>0 then ss=ss.." Opened Editor(s): "..editors.."\n"
30 | if edmod>0 then ss=ss.."<#ec>Unsaved Editor(s): "..edmod.."<#rr>\n" end
31 | end
32 | if #ss>0 then ss=ss.."\n" end
33 | if FarExitFlag then s,ss = "Exit",ss.."Do you want to quit FAR?" else s,ss = "Close",ss.."Do you want to close all viewers and editors?" end
34 | if viewers==0 and editors==0 then ss=ss.."\n" else ss=ss.."\n\n<#es>0<#rs> Quit or not" if edmod>0 then ss=ss.." " end end
35 | if edmod>0 then ss=ss.."\n<#es>1<#rs> <#sa>Save modified Editors and "..s.."<#sr>\n<#es>2<#rs> <#sc>"..(FarExitFlag and "Exit without saving Editors" or "Close Editors without saving").." <#sr>\n<#es>3<#rs> Cancel " end
36 | return ss
37 | end
38 |
39 | local function Buttons()
40 | local b1,b2,b3
41 | if edmod==0 then b1,b2 = "&Yes","&No"
42 | else
43 | local s=FarExitFlag and "Exit" or "Close"
44 | b1,b2,b3 = "&1 Save and "..s,"&2 "..s,"&3 Cancel"
45 | end
46 | return "!"..b1..";"..b2..(b3 and ";"..b3 or "")
47 | end
48 |
49 | return Event({
50 | group = "DialogEvent",
51 | description = desc.." Event",
52 | action = function(event, param)
53 | if event==F.DE_DLGPROCINIT and param.Msg==F.DN_INITDIALOG then
54 | local id=far.SendDlgMessage(param.hDlg,F.DM_GETDIALOGINFO)
55 | id = id and id.Id or ""
56 | if id==uGuidFarAskQuitId then
57 | local windows=far.AdvControl(F.ACTL_GETWINDOWCOUNT,0,0)
58 | dialogs,viewers,editors,edmod,FarExitCode = 0,0,0,0,nil
59 | for ii=1,windows do
60 | local info=far.AdvControl(F.ACTL_GETWINDOWINFO,ii,0)
61 | if info then
62 | if F.WTYPE_DIALOG==info.Type then dialogs=dialogs+1
63 | elseif F.WTYPE_VIEWER==info.Type then viewers=viewers+1
64 | elseif F.WTYPE_EDITOR==info.Type then editors=editors+1
65 | if bit64.band(info.Flags,F.WIF_MODIFIED)==F.WIF_MODIFIED then edmod=edmod+1 end
66 | end
67 | end
68 | end
69 | if viewers==0 and editors==0 then FarExitFlag=true end
70 | FarExitCode=MessageX(Message(),Title(),Buttons(),"c","",uGuidFarExitId)
71 | if edmod==0 and (FarExitCode==bSAVE or FarExitCode==bEXIT) then FarExitCode=FarExitCode+1 end
72 | if FarExitCode==bSAVE or FarExitCode==bEXIT then
73 | for ii=windows,1,-1 do
74 | local info=far.AdvControl(F.ACTL_GETWINDOWINFO,ii)
75 | if info then
76 | if info.Type==F.WTYPE_EDITOR then
77 | far.AdvControl(F.ACTL_SETCURRENTWINDOW,ii)
78 | far.AdvControl(F.ACTL_COMMIT)
79 | local EGI=editor.GetInfo()
80 | if FarExitCode==bSAVE and bit64.band(info.Flags,F.WIF_MODIFIED)==F.WIF_MODIFIED then editor.SaveFile(EGI.EditorID) end
81 | editor.Quit(EGI.EditorID)
82 | elseif info.Type==F.WTYPE_VIEWER then
83 | far.AdvControl(F.ACTL_SETCURRENTWINDOW,ii)
84 | far.AdvControl(F.ACTL_COMMIT)
85 | local VGI=viewer.GetInfo()
86 | viewer.Quit(VGI.ViewerID)
87 | end
88 | end
89 | end
90 | end
91 | far.SendDlgMessage(param.hDlg,F.DM_CLOSE,FarExitFlag and (FarExitCode==bSAVE or FarExitCode==bEXIT) and bYES or bNO)
92 | elseif id==uGuidEditAskSaveId and (FarExitCode==bSAVE or FarExitCode==bEXIT) then
93 | hDlg=param.hDlg
94 | far.SendDlgMessage(hDlg,F.DM_CLOSE,FarExitCode==bSAVE and bYES or (FarExitCode==bEXIT and bNO or bCANCEL),0)
95 | elseif id==uGuidFarExitId or id==uGuidScreensSwitchId then hDlg=param.hDlg
96 | end
97 | elseif hDlg and (viewers>0 or editors>0) and Area.Dialog and Dlg.Id==GuidFarExitId and event==F.DE_DEFDLGPROCINIT and param.Msg==F.DN_CONTROLINPUT then
98 | if param.Param2.EventType==F.KEY_EVENT then
99 | local name=far.InputRecordToName(param.Param2)
100 | if name==key or name=="Alt"..key then
101 | FarExitFlag=not FarExitFlag
102 | mf.postmacro(Keys,"F10 F10")
103 | end
104 | end
105 | elseif hDlg and Area.Dialog and Dlg.Id==GuidEditAskSaveId and FarExitCode==nil then
106 | local EdExitCode=MessageX("File has been modified. Save?","Editor","!&Yes;&No;&Cancel","","",uGuidEditAskSaveId)
107 | far.SendDlgMessage(param.hDlg,F.DM_CLOSE,EdExitCode==bSAVE and bYES or (EdExitCode==bEXIT and bNO or bCANCEL),0)
108 | elseif hDlg and Area.Menu and Menu.Id==GuidScreensSwitchId and event==F.DE_DEFDLGPROCINIT and param.Msg==F.DN_CONTROLINPUT then
109 | if param.Param2.EventType==F.KEY_EVENT then
110 | local name=far.InputRecordToName(param.Param2)
111 | if name=="Del" then mf.postmacro(Keys,"Enter F10 F12 End") end
112 | end
113 | end
114 | return false
115 | end
116 | })
117 |
--------------------------------------------------------------------------------
/Panel.SelectBOM.lua:
--------------------------------------------------------------------------------
1 | -- Panel.SelectBOM.lua
2 | -- v1.3
3 | -- Selection files with BOM
4 | -- Keys: launch from Macro Browser alt.
5 | -- Url: https://forum.ru-board.com/topic.cgi?forum=5&topic=49572&start=2280#12
6 |
7 | local F = far.Flags
8 | --local ffi = require'ffi'
9 | --local NULL = ffi.cast("void*",0)
10 | --local PANEL_ACTIVE = ffi.cast("HANDLE",-1)
11 | --local pBL0,pBL1 = ffi.cast("BOOL*",0),ffi.cast("BOOL*",1)
12 | local ReportPath=win.GetEnv('TEMP')..'\\boom.txt'
13 | local boom,Report = {},false
14 | local function process(f,t)
15 | -- utf32le,utf32be,utf16le,utf16be,utf8
16 | local res,bom = 0,{'\255\254\0\0','\0\0\254\255','\255\254','\254\255','\239\187\191'}
17 | local h=io.open(f,"rb")
18 | if h then
19 | local s=h:read(4) or '' h:close()
20 | for i=#bom,2,-1 do
21 | if string.sub(s,1,#bom[i])==bom[i] then
22 | if i==3 and s==bom[1] then i=1 end
23 | if t[i] then res=i end
24 | if Report then table.insert(boom[i],f) end
25 | break
26 | end
27 | end
28 | end
29 | return res
30 | end
31 |
32 | local guid = win.Uuid("2180A62D-04B5-44D9-999E-3A3328D51B84")
33 | local edtFlags = F.DIF_HISTORY+F.DIF_USELASTHISTORY
34 | local Items = {
35 | --[[01]] {F.DI_DOUBLEBOX, 3,1, 27,11,0, 0,0, 0, "Select BOOM!"},
36 | --[[02]] {F.DI_CHECKBOX, 5,2, 25,0, 0, 0,0, 0, "UTF-32 LE"},
37 | --[[03]] {F.DI_CHECKBOX, 5,3, 25,0, 0, 0,0, 0, "UTF-32 BE"},
38 | --[[04]] {F.DI_CHECKBOX, 5,4, 25,0, 0, 0,0, 0, "UTF-16 &LE"},
39 | --[[05]] {F.DI_CHECKBOX, 5,5, 25,0, 0, 0,0, 0, "UTF-16 &BE"},
40 | --[[06]] {F.DI_CHECKBOX, 5,6, 25,0, 0, 0,0, 0, "&UTF-8"},
41 | --[[07]] {F.DI_CHECKBOX, 5,7, 12,0, 0, 0,0, 0, "&All"},
42 | --[[08]] {F.DI_CHECKBOX, 15,7, 25,0, 0, 0,0, 0, "&Report"},
43 | --[[09]] {F.DI_EDIT, 5,8, 24,2, 0, "BOOM!ReportPath",0, edtFlags,""},
44 | --[[10]] {F.DI_TEXT, -1,9, 0,0, 0, 0,0, F.DIF_SEPARATOR,""},
45 | --[[11]] {F.DI_BUTTON, 0,10, 0,0, 0, 0,0, F.DIF_DEFAULTBUTTON+F.DIF_CENTERGROUP,"&Ok"},
46 | --[[12]] {F.DI_BUTTON, 0,10, 0,0, 0, 0,0, F.DIF_CENTERGROUP,"Ca&ncel"}
47 | }
48 |
49 | local GFocus,ChkBOX,tReportPath = 6,{false,false,false,false,true,false},ReportPath
50 | local function DlgProc(hDlg,Msg,Param1,Param2)
51 | if Msg==F.DN_INITDIALOG then
52 | for i=1,#ChkBOX do hDlg:send(F.DM_SETCHECK,i+1,ChkBOX[i] and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED) end
53 | hDlg:send(F.DM_SETTEXT,9,ReportPath)
54 | hDlg:send(F.DM_SETFOCUS,GFocus)
55 | elseif Msg==F.DN_BTNCLICK and Param1>1 and Param1<7 then
56 | ChkBOX[Param1-1]=Param2~=0
57 | elseif Msg==F.DN_BTNCLICK and Param1==7 then
58 | for i=1,#ChkBOX do
59 | ChkBOX[i]=Param2~=0
60 | hDlg:send(F.DM_SETCHECK,i+1,ChkBOX[i] and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED)
61 | end
62 | elseif Msg==F.DN_BTNCLICK and Param1==8 then
63 | Report=Param2~=0
64 | elseif (Msg==F.DN_EDITCHANGE or Msg==F.DN_LISTCHANGE) and Param1==9 then -- ReportPath changed
65 | local s=tostring(hDlg:send(F.DM_GETTEXT,9))
66 | tReportPath = s and s~='' and s or tReportPath
67 | elseif Msg==F.DN_GOTFOCUS then
68 | if Param1>1 and Param1<#Items-2 then GFocus=Param1 end
69 | else
70 | return
71 | end
72 | return true
73 | end
74 |
75 | Macro {
76 | description="BOM Files select"; name="BOOM"; area="Shell"; key="";
77 | action=function()
78 | if far.Dialog(guid,-1,-1,31,#Items+1,nil,Items,nil,DlgProc)==#Items-1 then
79 | --local s='' for i=1,#ChkBOX do s=s..(ChkBOX[i] and 1 or 0) end far.Message(s,'BOX')
80 | local ttime=far.FarClock()
81 | ReportPath = tReportPath=='' and ReportPath or tReportPath
82 | local head,itm0,itm1 = {},{},{}
83 | for i=2,6 do local s=Items[i][10]:gsub("&","") table.insert(head,s) end
84 | boom={} for i=1,#head do boom[i]={} end
85 | local ItemsNumber=panel.GetPanelInfo(nil,1).ItemsNumber
86 | --local pc=ffi.cast("struct PluginStartupInfo*",far.CPluginStartupInfo()).PanelControl
87 | --pc(PANEL_ACTIVE,"FCTL_BEGINSELECTION",0,NULL)
88 | for Item=1,ItemsNumber do
89 | local GPItem=panel.GetPanelItem(nil,1,Item)
90 | table.insert((GPItem.FileAttributes:find("d") or process(GPItem.FileName,ChkBOX)==0) and itm0 or itm1,Item)
91 | --pc(PANEL_ACTIVE,"FCTL_SETSELECTION",Item-1,(GPItem.FileAttributes:find("d") or process(GPItem.FileName,ChkBOX)==0) and pBL0 or pBL1)
92 | end
93 | panel.BeginSelection(nil,1)
94 | panel.SetSelection(nil,1,itm0,false)
95 | panel.SetSelection(nil,1,itm1,true)
96 | panel.EndSelection(nil,1)
97 | panel.RedrawPanel(nil,1)
98 | --pc(PANEL_ACTIVE,"FCTL_ENDSELECTION",0,NULL)
99 | --pc(PANEL_ACTIVE,"FCTL_REDRAWPANEL",0,NULL)
100 | if Report then
101 | ttime = far.FarClock()-ttime
102 | local ans=1
103 | if win.GetFileInfo(ReportPath) then ans=far.Message(ReportPath.."\nexist - overwrite?","BOOM! WARNING",";YesNo","w") end
104 | if ans==1 then
105 | local h=io.open(ReportPath,'wb')
106 | if h then
107 | local function _RootDir()
108 | local ItemInfo=panel.GetPanelInfo(0)
109 | local iItem,iTop = ItemInfo.CurrentItem,ItemInfo.TopPanelItem
110 | Panel.SetPosIdx(0,1)
111 | local APP0=APanel.Path0
112 | panel.RedrawPanel(nil,1,{CurrentItem=iItem; TopPanelItem=iTop})
113 | return APP0
114 | end
115 | h:write('Scan:\t'..ItemsNumber..' objects\n')
116 | h:write('Time:\t'..ttime..' mcs\n')
117 | h:write('Path:\t'.._RootDir()..'\nFind:')
118 | local s=''
119 | for i=#head,1,-1 do s=s..(#boom[i]>0 and '\t'..head[i]..' '..#boom[i] or '') end
120 | s=s=='' and '\t0 files' or s
121 | h:write(s)
122 | for i=#head,1,-1 do
123 | if #boom[i]>0 then
124 | table.sort(boom[i],function(a,b) return win.CompareString(a,b,"u","c")==-1 end)
125 | h:write('\n')
126 | for j=1,#boom[i] do h:write('\n'..head[i]..'\t'..boom[i][j]) end
127 | end
128 | end
129 | end
130 | h:close()
131 | end
132 | end
133 | end
134 | end
135 | }
136 |
--------------------------------------------------------------------------------
/Editor.TagGoto.lua:
--------------------------------------------------------------------------------
1 | -- Editor.TagGoto.lua
2 | -- v1.1.2
3 | -- Tag navigation in files opened in the editor: [dgmsx]?html?, xslt?, [xy]ml
4 | -- Required: plugin LFSearch (LuaFAR Search) by Shmuel
5 | -- Keys: Alt[JKLP]
6 |
7 | local SelectFound=true -- Select Found true=yes, false=no
8 |
9 | local Code=[[
10 | local nFound,direction
11 |
12 | local XCursor=function(x)
13 | local EGI=editor.GetInfo()
14 | editor.SetPosition(EGI.EditorID,{CurPos=EGI.CurPos+x})
15 | end
16 |
17 | local patt="(<\\/?(?:\\w+?|xsl:\\w+?-?\\w+?))[ >]|(\\/>)"
18 | local SearchTag=function(direction,pattern)
19 | local Data={
20 | sSearchPat=pattern or patt,
21 | sRegexLib="oniguruma", --"far" (default), "oniguruma", "pcre" or "pcre2"
22 | bRegExpr=true,
23 | bSearchBack=direction=="left"
24 | }
25 | local nFound=lfsearch.EditorAction("test:search",Data)
26 | if not Data.bSearchBack then XCursor(-1) end
27 | return nFound
28 | end
29 |
30 | local CaptureTag=function()
31 | _G.LFST=nil
32 | local patt=regex.new(patt,"ix")
33 | local s=editor.GetStringW()
34 | if not s then return end
35 | local EGI=editor.GetInfo()
36 | local pos,pEnd = EGI.CurPos,s.StringLength+1
37 | _G.Y1 = EGI.CurLine
38 | if pos>=pEnd then return end
39 | local text,start = s.StringText.."\0",1
40 | while true do
41 | local b,e = patt:findW(text,start)
42 | if b==nil or b>pos then break
43 | elseif e>=pos then
44 | _G.LFST={}
45 | if e-b==1
46 | then
47 | _G.LFST.Rev=true
48 | _G.LFST.Num=1
49 | _G.LFST.Cnt=1
50 | else
51 | _G.LFST.Txt=win.Utf16ToUtf8(win.subW(text,b,e-1))
52 | _G.LFST.Rev=_G.LFST.Txt:sub(2,2)=='/'
53 | _G.LFST.Num=b==pos and not _G.LFST.Rev and 0 or 1
54 | _G.LFST.Cnt=b==pos and 2 or 1
55 | _G.LFST.Tag=_G.LFST.Rev and '<'.._G.LFST.Txt:sub(3,-1) or _G.LFST.Txt
56 | end
57 | _G.X1=_G.LFST.Rev and e or b
58 | break
59 | end
60 | start=e+1
61 | end
62 | end
63 |
64 | local ProcessingTag=function()
65 | local Data={
66 | sSearchPat=patt,
67 | sReplacePat=[=[
68 | if T[1] and T[1]==_G.LFST.Txt then _G.LFST.Num=_G.LFST.Num+1
69 | elseif T[1] and (T[1]:sub(2,2)=='/' and '<'..T[1]:sub(3,-1) or T[1])==_G.LFST.Tag then _G.LFST.Num=LFST.Num-1
70 | elseif _G.LFST.Rev and T[1] and T[1]:sub(2,2)~='/' and M==_G.LFST.Cnt and not _G.LFST.Tag then _G.LFST.Num=0
71 | elseif not _G.LFST.Rev and T[2] and T[2]=='/>' and M==_G.LFST.Cnt and _G.LFST.Num==1 then _G.LFST.Num=0
72 | end
73 | if _G.LFST.Num==0 then return true,true end
74 | ]=],
75 | sRegexLib="oniguruma", --"far" (default), "oniguruma", "pcre" or "pcre2"
76 | bRegExpr=true,
77 | bSearchBack=_G.LFST.Rev,
78 | bRepIsFunc=true,
79 | bConfirmReplace=true,
80 | fUserChoiceFunc=function() return "cancel" end
81 | }
82 | local nFound,nReps = lfsearch.EditorAction("test:replace",Data)
83 | if not _G.LFST.Rev then XCursor(-1) end
84 | return nFound,nReps
85 | end
86 | ]]
87 |
88 | local Algo=[[
89 | CaptureTag()
90 | if not _G.LFST then
91 | local ans=far.Message("<= 1st =>\n=> 2nd <=","Seek priority","Left;Right")
92 | if ans==1 then nFound=SearchTag("left") if nFound==0 then nFound=SearchTag("right") end
93 | elseif ans==2 then nFound=SearchTag("right") if nFound==0 then nFound=SearchTag("left") end
94 | end
95 | if nFound==1 then CaptureTag() else return end
96 | end
97 | repeat
98 | if _G.LFST then
99 | nFound=ProcessingTag()
100 | if _G.LFST.Num==0 then
101 | local EGI=editor.GetInfo()
102 | local eid,X2,Y2 = EGI.EditorID,EGI.CurPos,EGI.CurLine
103 | if direction then editor.SetPosition(EGI.EditorID,{CurPos=_G.X1,CurLine=_G.Y1}) end
104 | return eid,_G.X1,_G.Y1,X2,Y2
105 | elseif _G.LFST.Num>0 then
106 | if not direction and _G.LFST.Rev or direction and direction=="left"
107 | then nFound=SearchTag("left") if nFound==0 then nFound=SearchTag("right") end
108 | else nFound=SearchTag("right") if nFound==0 then nFound=SearchTag("left") end
109 | end
110 | end
111 | end
112 | if nFound==1 then CaptureTag() else return end
113 | until nFound==0
114 | ]]
115 |
116 | local TagLeft=[[
117 | direction="left"
118 | nFound=SearchTag(direction)
119 | if nFound==0 then return end
120 | ]]
121 |
122 | local TagRight=[[
123 | direction="right"
124 | XCursor(1)
125 | nFound=SearchTag(direction)
126 | if nFound==0 then return end
127 | ]]
128 |
129 | local TagParent=[[
130 | direction,pattern,pos = "left",...
131 | nFound=SearchTag(direction,pattern)
132 | if nFound==0 then return end
133 | XCursor(pos)
134 | ]]
135 |
136 | local Proc=function(eid,X1,Y1,X2,Y2)
137 | if SelectFound and X1 and Y1 and X2 and Y2 then
138 | local F=far.Flags
139 | local SelectData={
140 | BlockType=F.BTYPE_STREAM,
141 | BlockStartLine=math.min(Y2,Y1),
142 | BlockStartPos=Y12 then
85 | local t1,t0 = {},{}
86 | for i=1,tPanelInfo1.SelectedItemsNumber do table.insert(t1,panel.GetSelectedPanelItem(nil,1,i).FileName) end -- selected => t1
87 | Panel.Select(1,0) -- clear selection on the passive panel
88 | for i=1,tPanelInfo0.ItemsNumber do -- select files on the passive panel with the same names
89 | for k,v in ipairs(t1) do
90 | if panel.GetPanelItem(nil,0,i).FileName==v then table.insert(t0,i) table.remove(t1,k) break end
91 | end
92 | if #t1==0 then break end
93 | end
94 | if #t0>0 then panel.SetSelection(nil,0,t0,true) end
95 | Plugin.SyncCall("ED0C4BD8-D2F0-4B6E-A19F-B0B0137C9B0C") -- call AdvCmpEx
96 | panel.RedrawPanel(nil,1)
97 | panel.RedrawPanel(nil,0)
98 | elseif tPanelInfo1.SelectedItemsNumber==2
99 | or tPanelInfo1.SelectedItemsNumber==1 and tPanelInfo0.SelectedItemsNumber<=1
100 | or tPanelInfo1.SelectedItemsNumber==0 and (not PPanel.Plugin or PPanel.Plugin and
101 | (PPanel.Format=="Branch" or PPanel.Prefix=="tmp" or tPanelInfo0.SelectedItemsNumber<=1))
102 | then return true
103 | else far.Message(msg,VC)
104 | end
105 | end
106 | end;
107 | action = function()
108 | local APR,PPR,AP,PP,AC,PC,AF,PF,ePF,APD,PPD,TMP,S2,CI = APanel.Prefix,PPanel.Prefix,APanel.Path0,PPanel.Path0,APanel.Current,PPanel.Current,APanel.Format,PPanel.Format,regex.new"netbox|observe|torrent","\\AP","\\PP",win.GetEnv("Temp").."\\~arc"
109 | remove(TMP)
110 | if APanel.SelCount==2 then
111 | S2,PC,AC = true,panel.GetSelectedPanelItem(nil,1,1).FileName,panel.GetSelectedPanelItem(nil,1,2).FileName
112 | --if not APanel.Left then AC,PC = PC,AC end
113 | elseif APanel.SelCount==1 and PPanel.SelCount==1 then PC,AC = panel.GetSelectedPanelItem(nil,0,1).FileName,panel.GetSelectedPanelItem(nil,1,1).FileName
114 | elseif APanel.SelCount==1 then S2,PC,AC = true,panel.GetSelectedPanelItem(nil,1,1).FileName,panel.GetCurrentPanelItem(nil,1).FileName
115 | CI=panel.GetPanelInfo(nil,1).CurrentItem
116 | panel.BeginSelection(nil,1) panel.SetSelection(nil,1,CI,true)
117 | elseif APanel.SelCount==0 and PPanel.SelCount==1 then PC=panel.GetSelectedPanelItem(nil,0,1).FileName
118 | end
119 | local eAP,ePP = AF=="arc" or APR=="ma" or ePF:match(APR or ""),PF=="arc" or PPR=="ma" or ePF:match(PPR or "")
120 | if S2 and eAP then
121 | AP=TMP..APD PP=AP e(AP,AC)
122 | elseif S2 then
123 | PP=AP
124 | else
125 | if eAP then AP=TMP..APD e(AP,AC) end
126 | if ePP then PP=TMP..PPD panel.SetActivePanel(nil,0) e(PP,PC) panel.SetActivePanel(nil,0) end
127 | end
128 | if CI then panel.SetSelection(nil,1,CI,false) panel.EndSelection(nil,1) end
129 | AP,PP = f(AP,AC),f(PP,PC)
130 | if AP==PP then far.Message("it's the same object\n\n1st: "..PP.."\n2nd: "..AP,VC)
131 | else
132 | local NotRead,NotReadFile = false,""
133 | local function crash_protect(f)
134 | local fffezzzz,zzzzfeff,feff,fffe,efbbbf,zero = "\255\254\000\000","\000\000\254\255","\254\255","\255\254","\239\187\191"
135 | if not win.GetFileInfo(f).FileAttributes:find("d") then
136 | local h=io.open(f,"rb")
137 | if h then
138 | local s=h:read(4) or ""
139 | local l=string.len(s)
140 | zero=(l==0 or l==3 and s==efbbbf or l==2 and (s==fffe or s==feff) or l==4 and (s==fffezzzz or s==zzzzfeff)) h:close()
141 | else
142 | NotRead,NotReadFile = true,f
143 | end
144 | end
145 | return zero
146 | end
147 | local cp_AP,cp_PP = crash_protect(AP),crash_protect(PP)
148 | if NotRead then far.Message("\nCrash protect!\n\nFile: "..NotReadFile.."\n- blocked?",VC)
149 | elseif cp_AP and cp_PP
150 | then
151 | local APlen = AP:len()-PP:len()
152 | far.Message("\nCrash protect!\n\nFiles have zero sizes or BOM only\n\n1st: "..PP..(APlen>0 and string.rep(" ",APlen) or "").."\n2nd: "..AP..(APlen<0 and string.rep(" ",-APlen) or ""),VC)
153 | else
154 | if APanel.Left
155 | then Plugin.Command(VisComp,'"'..AP..'" "'..PP..'"')
156 | else Plugin.Command(VisComp,'"'..PP..'" "'..AP..'"') Keys("Tab")
157 | end
158 | end
159 | end
160 | end
161 | }
162 |
163 |
164 | --local BackUP={}
165 | --
166 | --Macro {
167 | --description="VC: Exchange of lines between files"; area="Dialog"; key="Del Ins F5 F6 AltLeft AltRight";
168 | --condition = function() return Area.Dialog and Dlg.Id=="78DBDD6F-74A0-41E4-91FC-DE5707CF63F5" end;
169 | --action = function()
170 | -- local key=akey(1,1)
171 | -- local LFile=Dlg.CurPos==4
172 | -- local Info,ret = {}
173 | -- local DelLine=function() Keys("F4 Home") Info=editor.GetInfo() editor.DeleteString(Info.EditorID) end
174 | -- local InsLine=function() Keys("F4 Home") Info=editor.GetInfo() editor.InsertString(Info.EditorID) end
175 | -- local CopyLine=function()
176 | -- if ret then Keys("Tab F4 Home") else Keys("F4 Home") end
177 | -- Info=editor.GetInfo()
178 | -- local StringText=editor.GetStringW(Info.EditorID,Info.CurLine,0).StringText
179 | -- editor.Quit(Info.EditorID)
180 | -- ret=not ret
181 | -- Keys("Tab F4 Home")
182 | -- Info=editor.GetInfo()
183 | -- if key=="F5" then
184 | -- if Info.CurLine==Info.TotalLines-1 then Keys("End") Info.CurLine=Info.TotalLines end
185 | -- editor.InsertString(Info.EditorID)
186 | -- end
187 | -- editor.SetStringW(Info.EditorID,Info.CurLine,StringText)
188 | -- end
189 | --
190 | -- if key=="Del" then DelLine()
191 | -- elseif key=="Ins" then InsLine()
192 | -- elseif key=="F5" or key=="F6" then CopyLine()
193 | -- else
194 | -- if LFile and (key=="AltLeft") or not LFile and (key=="AltRight") then ret=not ret end
195 | -- key="F6"
196 | -- CopyLine()
197 | -- end
198 | -- local bkp=true
199 | -- for _,v in ipairs(BackUP) do if v==Info.FileName then bkp=false break end end
200 | -- if bkp then win.CopyFile(Info.FileName,Info.FileName.."_") table.insert(BackUP,Info.FileName) end
201 | -- editor.SaveFile(Info.EditorID)
202 | -- editor.Quit(Info.EditorID)
203 | -- if ret then Keys("Tab") end
204 | --end
205 | --}
206 |
--------------------------------------------------------------------------------
/MessageX.lua:
--------------------------------------------------------------------------------
1 | -- MessageX.lua
2 | -- v0.6.7.9
3 | -- Color **MessageX(Msg,Title,Buttons,Flags,HelpTopic,Guid,ExecDelay)** module with support default button assignments
4 | -- 
5 | -- Support delay execution in seconds (**ExecDelay**:integer)
6 | -- Support flags: **"wlcm"**
7 | -- **w** - warning dialog, **l** - left align (default center align), **c** - color mode, **m** - monochrome mode
8 | -- without **cm** will be used raw mode
9 | -- Tags format: **<#xy>**, **x** - foreground color **0..f**, **y** - background color **0..f**
10 | -- **r** - restore default color for foreground/background, **s** - skip, don't change foreground/background color
11 | -- Example message string: "aaa<#e1>bbb<#s2>\nccc<#bs>ddd\neee<#rs>fff<#sr>ggg"
12 | --
13 | -- Usage: put **MessageX.lua** to modules folder
14 | -- Call in scripts (example):
15 | -- ``` lua
16 | -- local MessageX = require'MessageX'
17 | -- MessageX("aaa <#e2>bbb<#s1>\nccc<#bs> ddd\neee<#9s> fff <#sr> ggg <#ec>hhh","MessageX","&Ok;!Ca&ncel","wc","","",11)
18 | -- ```
19 |
20 | local F=far.Flags
21 | local K=far.Colors
22 |
23 | local band64,bor64 = bit64.band,bit64.bor
24 | local string_find,string_gsub,string_lower,string_rep = string.find,string.gsub,string.lower,string.rep
25 | local math_floor,math_log,math_max = math.floor,math.log,math.max
26 | local far_AdvControl,far_CreateUserControl,far_Dialog,far_SendDlgMessage,far_Show,far_Timer = far.AdvControl,far.CreateUserControl,far.Dialog,far.SendDlgMessage,far.Show,far.Timer
27 | local table_insert = table.insert
28 | local regex_new = regex.new
29 |
30 | local pat=regex_new"<#([0-9A-FRSa-frs])([0-9A-FRSa-frs])>"
31 | local patlen=5
32 | -- if available flag "c"
33 | local function CreateColorTbl(tbl,width)
34 | local ct,line,smax,fg,bg = {},1,0
35 | while line<=#tbl do
36 | table_insert(ct,{})
37 | local len,to,from,_fg,_bg = 0,0
38 | repeat
39 | from,to,_fg,_bg = pat:find(tbl[line],to+1)
40 | if from then
41 | _fg=_fg:lower() _bg=_bg:lower()
42 | if _fg=="r" then fg=nil
43 | elseif _fg~="s" then fg=tonumber(_fg,16)
44 | end
45 | if _bg=="r" then bg=nil
46 | elseif _bg~="s" then bg=tonumber(_bg,16)
47 | end
48 | ct[line][from-len]={fg=fg,bg=bg}
49 | len=len+patlen
50 | end
51 | until not from
52 | tbl[line]=pat:gsub(tbl[line],"")
53 | local sz=tbl[line]:len()
54 | local w=width-4
55 | if sz>=w then smax=w elseif smaxw do
57 | table_insert(ct,{})
58 | for k in pairs(ct[line]) do if k>w then ct[line+1][k-w]=ct[line][k] ct[line][k]=nil end end
59 | local s
60 | tbl[line],s = tbl[line]:sub(1,w),tbl[line]:sub(w+1,sz)
61 | line=line+1 table_insert(tbl,line,s) sz=sz-w
62 | end
63 | line=line+1
64 | end
65 | return tbl,ct,smax
66 | end
67 |
68 | -- if available flag "m" or w/o him
69 | local function CreateMonoTbl(tbl,width,Flags)
70 | local line,ct,smax,mono = 1,{},0
71 | if string_find(Flags,"m") then mono=true end
72 | while line<=#tbl do
73 | table_insert(ct,{})
74 | if mono then tbl[line]=pat:gsub(tbl[line],"") end
75 | local sz=tbl[line]:len()
76 | local w=width-4
77 | if sz>=w then smax=w elseif smaxw do
79 | table_insert(ct,{})
80 | local s
81 | tbl[line],s = tbl[line]:sub(1,w),tbl[line]:sub(w+1,sz)
82 | line=line+1 table_insert(tbl,line,s) sz=sz-w
83 | end
84 | line=line+1
85 | end
86 | return tbl,ct,smax
87 | end
88 |
89 | -- if available Buttons
90 | local pat1 = "(!?)([^;]+)"
91 | local function CreateButtons(line,Buttons)
92 | local butnum,butdef,butlen,tButtons = 0,0,0,{}
93 | if Buttons=="" then return butdef,butlen end
94 | local bFlags=F.DIF_CENTERGROUP
95 | for def,button in Buttons:gmatch(pat1) do
96 | butnum=butnum+1
97 | if def=="!" then butdef=butnum end
98 | table_insert(tButtons,{F.DI_BUTTON,0,line,0,0,0,0,0,bFlags,button})
99 | butlen=butlen+button:gsub("&&"," "):gsub("&",""):len()+4
100 | end
101 | if butdef==0 then butdef=1 end
102 | tButtons[butdef][9]=bFlags+F.DIF_DEFAULTBUTTON
103 | return butdef,butlen+butnum-1,tButtons
104 | end
105 |
106 | local function CreateItem(tbl,width,height,Flags,Buttons,Title,ExecDelay)
107 | local tbllen,smax,ct = #tbl,0
108 | if tbllen>0 then
109 | if string_find(Flags,"c")
110 | then tbl,ct,smax = CreateColorTbl(tbl,width)
111 | else tbl,ct,smax = CreateMonoTbl(tbl,width,Flags)
112 | end
113 | tbllen=#tbl
114 | end
115 |
116 | -- Buttons processing
117 | local line=tbllen+4>height and height-2 or (tbllen + (tbllen>0 and 2 or 1))
118 | local butdef,butlen,tButtons = CreateButtons(line,Buttons)
119 |
120 | local X2=math_max(smax+4,butlen+4,Title:len()+4+(ExecDelay and math_floor(math_log(ExecDelay,10)+3) or 0))
121 | local Y2=2+tbllen -- add box and Msg
122 | if tButtons then Y2=Y2+1 -- add Buttons
123 | if tbllen>0 then Y2=Y2+1 end -- add separator
124 | end
125 | if Y2>height then Y2,tbllen = height,(tButtons and height-4 or height-2) end
126 | if tbllen==0 then return tButtons,butdef,X2,Y2 end -- No Msg
127 | local X3,X4 = X2-3,X2-4
128 | local buffer=far_CreateUserControl(X4,tbllen)
129 | local cFlags=bor64(F.FCF_FG_4BIT,F.FCF_BG_4BIT)
130 | local elem=string_find(Flags,"w") and K.COL_WARNDIALOGTEXT or K.COL_DIALOGTEXT
131 | local leftAlign=string_find(Flags,"l")
132 | local tFarColor=far_AdvControl(F.ACTL_GETCOLOR,elem)
133 | local fg_dlg=band64(tFarColor.ForegroundColor,0xF)
134 | local bg_dlg=band64(tFarColor.BackgroundColor,0xF)
135 | local fg,bg,ptr = fg_dlg,bg_dlg,1
136 | for y=1,tbllen do
137 | if not leftAlign then
138 | local half=math_floor((X4-tbl[y]:len())/2)
139 | if half>0 then
140 | tbl[y]=string_rep(" ",half)..tbl[y]
141 | for x=X4,1,-1 do if ct[y][x] then ct[y][x+half]=ct[y][x] ct[y][x]=nil end end
142 | end
143 | end
144 | for x=1,X4 do
145 | local char=tbl[y]:sub(x,x) or " "
146 | fg = ct[y][x] and (ct[y][x].fg and ct[y][x].fg or fg_dlg) or x==1 and y>1 and ct[y-1][X3] and (ct[y-1][X3].fg and ct[y-1][X3].fg or fg_dlg) or fg
147 | bg = ct[y][x] and (ct[y][x].bg and ct[y][x].bg or bg_dlg) or x==1 and y>1 and ct[y-1][X3] and (ct[y-1][X3].bg and ct[y-1][X3].bg or bg_dlg) or bg
148 | buffer[ptr]={Char=char,Attributes={Flags=cFlags,ForegroundColor=fg,BackgroundColor=bg}}
149 | ptr=ptr+1
150 | end
151 | end
152 | return tButtons,butdef,X2,Y2,{F.DI_USERCONTROL,2,1,X3,tbllen,buffer,0,0,F.DIF_NOFOCUS,""}
153 | end
154 |
155 | local pat2,pat3,pat4 = "([^\r\n]*)\r?\n",regex_new"[^\r\n]+$"," :%d+$"
156 | local function MessageX(Msg,Title,Buttons,Flags,HelpTopic,Guid,ExecDelay)
157 | -- Protection against incorrect arguments
158 | if ExecDelay and type(ExecDelay)=="number" then
159 | if ExecDelay>=1 then ExecDelay=math_floor(ExecDelay) else return end
160 | else ExecDelay=nil
161 | end
162 | Title,Buttons,Flags,HelpTopic,Guid = Title or "MessageX",Buttons or "",Flags or "",HelpTopic or "",Guid or ""
163 | Flags=string_lower(Flags)
164 |
165 | -- Check window size
166 | local width,height
167 | local w=far_AdvControl(F.ACTL_GETFARRECT)
168 | if w then width,height = w.Right-w.Left+1,w.Bottom-w.Top+1 end
169 |
170 | local MsgType=type(Msg)
171 | if MsgType~="string" then
172 | if MsgType=="table" then far_Show(unpack(Msg)) else far_Show(Msg) end
173 | exit()
174 | end
175 | if Msg:find"^[%s%c]+$" then
176 | local spc="\194\183"
177 | local tab="\26"
178 | Msg=Msg:gsub(" ",spc)
179 | Msg=Msg:gsub("\t",tab)
180 | Msg="<#1s>"..Msg.."<#rs>"
181 | Flags=string_find(Flags,"c") and Flags or Flags..'c'
182 | end
183 |
184 | -- Line processing
185 | local tbl={}
186 | if Msg and Msg~="" then
187 | for line in Msg:gmatch(pat2) do table_insert(tbl,line) end
188 | table_insert(tbl,pat3:match(Msg))
189 | end
190 |
191 | -- Message Creation
192 | local tButtons,butdef,X2,Y2,item = CreateItem(tbl,width,height,Flags,Buttons,Title,ExecDelay)
193 |
194 | -- Frame Creation
195 | local Items={{F.DI_DOUBLEBOX,0,0,X2,Y2,0,0,0,0,Title or ""}}
196 | -- Message Insertion
197 | if item then table_insert(Items,item) end
198 |
199 | -- Seperator Insertion
200 | if item and tButtons then table_insert(Items,{F.DI_TEXT,0,Y2-3,0,0,0,0,0,F.DIF_SEPARATOR,""}) end
201 |
202 | -- Button Creation
203 | if tButtons then for i=1,#tButtons do table_insert(Items,tButtons[i]) end end
204 |
205 | -- Dialogue processing
206 | local timer
207 | local shft=item and 3 or 1
208 | local butdefid=butdef+shft
209 | local DlgProc=function(hDlg,Msg,Param1,Param2)
210 | local function OnTimer()
211 | ExecDelay=ExecDelay-1
212 | if ExecDelay>0
213 | then far_SendDlgMessage(hDlg,F.DM_SETTEXT,1,string_gsub(far_SendDlgMessage(hDlg,F.DM_GETTEXT,1),pat4," :"..ExecDelay))
214 | else far_SendDlgMessage(hDlg,F.DM_CLOSE,far_SendDlgMessage(hDlg,F.DM_GETFOCUS))
215 | end
216 | end
217 | if Msg==F.DN_INITDIALOG then
218 | if butdef~=0 then far_SendDlgMessage(hDlg,F.DM_SETFOCUS,butdefid) end
219 | if ExecDelay then
220 | far_SendDlgMessage(hDlg,F.DM_SETTEXT,1,far_SendDlgMessage(hDlg,F.DM_GETTEXT,1).." :"..ExecDelay)
221 | timer=far_Timer(1000,OnTimer)
222 | end
223 | elseif timer and Msg==F.DN_GOTFOCUS and far_SendDlgMessage(hDlg,F.DM_GETFOCUS)~=butdefid then -- Param1 1st time return wrong id
224 | timer:Close() timer=nil
225 | far_SendDlgMessage(hDlg,F.DM_SETTEXT,1,string_gsub(far_SendDlgMessage(hDlg,F.DM_GETTEXT,1),pat4,""))
226 | end
227 | end
228 |
229 | -- Flags processing
230 | local DlgFlags=F.FDLG_SMALLDIALOG
231 | if string_find(Flags,"w") then DlgFlags=DlgFlags+F.FMSG_WARNING end
232 |
233 | -- Show dialogue
234 | local result=far_Dialog(Guid,-1,-1,X2,Y2,HelpTopic,Items,DlgFlags,DlgProc)
235 | if timer then timer:Close() timer=nil end
236 | return result<0 and result or result-shft
237 | end
238 |
239 | return MessageX
--------------------------------------------------------------------------------
/Panel.CustomSortByAttributes.lua:
--------------------------------------------------------------------------------
1 | -- Panel.CustomSortByAttributes.lua
2 | -- v2.0.1.1
3 | -- Panel files sorting by attributes
4 | -- 
5 | -- Keys: CtrlShiftF3 or from Menu "Sort by"
6 | -- Tip: In the dialog all elements have prompts, press F1 for help
7 | -- Url: https://forum.ru-board.com/topic.cgi?forum=5&topic=49572&start=2240#16
8 |
9 | if not (bit and jit) then return end
10 |
11 | local F = far.Flags
12 | local guid = "A79390CE-5450-403A-8FAE-17EE3315CB38"
13 | local uGuid = win.Uuid(guid)
14 | local MenuGuid = "B8B6E1DA-4221-47D2-AB2E-9EC67D0DC1E3"
15 | -- Settings --------------------------------------------------------------------
16 | local ModeNumber = 100109
17 | local Description = "Custom: by Attributes"
18 | local Indi1 = "aA"
19 | local Indicator = Indi1
20 | local Key = "CtrlShiftF3"
21 | --------------------------------------------------------------------------------
22 |
23 | local ffi = require("ffi")
24 |
25 | ffi.cdef[[BOOL SetFileAttributesW(LPCWSTR lpFileName, DWORD dwFileAttributes);]]
26 |
27 | local b=bit
28 | local band,bnot,bor,bxor = b.band,b.bnot,b.bor,b.bxor
29 |
30 | local function ToWChar(str) str=win.Utf8ToUtf16(str) local res=ffi.new("wchar_t[?]",#str/2+1) ffi.copy(res,str) return res end
31 |
32 | local edtFlags = F.DIF_HISTORY+F.DIF_USELASTHISTORY
33 | local Items = {
34 | --[[01]] {F.DI_DOUBLEBOX, 3,1, 66,18, 0, 0,0, 0, "Custom sort by Attributes"},
35 | --[[02]] {F.DI_TEXT, 5,2, 64,0, 0, 0,0, 0, "File:"},
36 | --[[03]] {F.DI_TEXT, 5,3, 18,0, 0, 0,0, 0, "Attributes:"},
37 | --[[04]] {F.DI_EDIT, 17,3, 35,0, 0, "CustomSortByAttributes_Attributes",0, edtFlags, ""},
38 | --[[05]] {F.DI_BUTTON, 38,3, 54,0, 0, 0,0, 0, "[ Get from &File ]"},
39 | --[[06]] {F.DI_BUTTON, 56,3, 62,0, 0, 0,0, 0, "[ Set &M ]"},
40 | --[[07]] {F.DI_TEXT, -1,4, 0,0, 0, 0,0, F.DIF_SEPARATOR,""},
41 | --[[08]] {F.DI_CHECKBOX, 5,5, 30,0, 0, 0,0, 0, "&Read only"},
42 | --[[09]] {F.DI_CHECKBOX, 5,6, 30,0, 0, 0,0, 0, "&Archive"},
43 | --[[10]] {F.DI_CHECKBOX, 5,7, 30,0, 0, 0,0, 0, "&Hidden"},
44 | --[[11]] {F.DI_CHECKBOX, 5,8, 30,0, 0, 0,0, 0, "&System"},
45 | --[[12]] {F.DI_CHECKBOX, 5,9, 30,0, 0, 0,0, 0, "&Directory"},
46 | --[[13]] {F.DI_CHECKBOX, 5,10, 30,0, 0, 0,0, 0, "&Compressed"},
47 | --[[14]] {F.DI_CHECKBOX, 5,11, 30,0, 0, 0,0, 0, "&Encrypted"},
48 | --[[15]] {F.DI_CHECKBOX, 5,12, 30,0, 0, 0,0, 0, "Not &indexed"},
49 | --[[16]] {F.DI_CHECKBOX, 5,13, 30,0, 0, 0,0, 0, "S&parse"},
50 | --[[17]] {F.DI_CHECKBOX, 5,14, 30,0, 0, 0,0, 0, "&Temporary"},
51 | --[[18]] {F.DI_CHECKBOX, 38,5, 62,0, 0, 0,0, 0, "Off&line"},
52 | --[[19]] {F.DI_CHECKBOX, 38,6, 62,0, 0, 0,0, 0, "Reparse point &X"},
53 | --[[20]] {F.DI_CHECKBOX, 38,7, 62,0, 0, 0,0, 0, "&Virtual"},
54 | --[[21]] {F.DI_CHECKBOX, 38,8, 62,0, 0, 0,0, 0, "Inte&grity stream"},
55 | --[[22]] {F.DI_CHECKBOX, 38,9, 62,0, 0, 0,0, 0, "No scru&b data"},
56 | --[[23]] {F.DI_CHECKBOX, 38,10,62,0, 0, 0,0, 0, "Pinned &Y"},
57 | --[[24]] {F.DI_CHECKBOX, 38,11,62,0, 0, 0,0, 0, "&Unpinned"},
58 | --[[25]] {F.DI_CHECKBOX, 38,12,62,0, 0, 0,0, 0, "Recall on open &J"},
59 | --[[26]] {F.DI_CHECKBOX, 38,13,62,0, 0, 0,0, 0, "Recall on data access &K"},
60 | --[[27]] {F.DI_CHECKBOX, 38,14,62,0, 0, 0,0, 0, "Strictly se&quential"},
61 | --[[28]] {F.DI_CHECKBOX, 20,15,36,0, 0, 0,0, 0, "by selected &Z"},
62 | --[[29]] {F.DI_CHECKBOX, 5,17, 17,0, 0, 0,0, 0, "Report &W"},
63 | --[[30]] {F.DI_TEXT, -1,16, 0,0, 0, 0,0, F.DIF_SEPARATOR,""},
64 | --[[31]] {F.DI_BUTTON, 0,17, 0,0, 0, 0,0, F.DIF_DEFAULTBUTTON+F.DIF_CENTERGROUP,"&Ok"},
65 | --[[32]] {F.DI_BUTTON, 0,17, 0,0, 0, 0,0, F.DIF_CENTERGROUP,"Ca&ncel"}
66 | }
67 |
68 | local AttributesSymbols="rahsdceiptlxvgbyujkq"
69 |
70 | local AttributeValue = {
71 | --[[FILE_ATTRIBUTE_READONLY ]] 0x00000001,
72 | --[[FILE_ATTRIBUTE_ARCHIVE ]] 0x00000020,
73 | --[[FILE_ATTRIBUTE_HIDDEN ]] 0x00000002,
74 | --[[FILE_ATTRIBUTE_SYSTEM ]] 0x00000004,
75 | --[[FILE_ATTRIBUTE_DIRECTORY ]] 0x00000010,
76 | --[[FILE_ATTRIBUTE_COMPRESSED ]] 0x00000800,
77 | --[[FILE_ATTRIBUTE_ENCRYPTED ]] 0x00004000,
78 | --[[FILE_ATTRIBUTE_NOT_CONTENT_INDEXED]] 0x00002000,
79 | --[[FILE_ATTRIBUTE_SPARSE_FILE ]] 0x00000200,
80 | --[[FILE_ATTRIBUTE_TEMPORARY ]] 0x00000100,
81 | --[[FILE_ATTRIBUTE_OFFLINE ]] 0x00001000,
82 | --[[FILE_ATTRIBUTE_REPARSE_POINT ]] 0x00000400,
83 | --[[FILE_ATTRIBUTE_VIRTUAL ]] 0x00010000,
84 | --[[FILE_ATTRIBUTE_INTEGRITY_STREAM ]] 0x00008000,
85 | --[[FILE_ATTRIBUTE_NO_SCRUB_DATA ]] 0x00020000,
86 | --[[FILE_ATTRIBUTE_PINNED ]] 0x00080000,
87 | --[[FILE_ATTRIBUTE_UNPINNED ]] 0x00100000,
88 | --[[FILE_ATTRIBUTE_RECALL_ON_OPEN ]] 0x00040000,
89 | --[[FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS]] 0x00400000,
90 | --[[FILE_ATTRIBUTE_STRICTLY_SEQUENTIAL]] 0x20000000
91 | }
92 |
93 | -- FILE_ATTRIBUTE_DIRECTORY 0x00000010
94 | -- FILE_ATTRIBUTE_DEVICE 0x00000040
95 | -- FILE_ATTRIBUTE_NORMAL 0x00000080
96 |
97 | local SAttributes,FAttributes,FAMasque,AttributesWeight,CompareMode,xReport,count,FName,FPath,GFocus,ttime0,count0 = nil,{},0x205FFF37,0,true,false,0,"","",4
98 | for i=1,#AttributeValue do FAttributes[i]=false end
99 |
100 | local function BySelected(l)
101 | if l==AttributesWeight then l=(#AttributeValue+1)*#AttributeValue+1
102 | else
103 | local equal=band(l,AttributesWeight)
104 | local diff =bxor(l,AttributesWeight)
105 | local e,d = 0,0
106 | for i=1,#AttributeValue do
107 | if band(equal,AttributeValue[i])>0 then e=e+1 end
108 | if band(diff ,AttributeValue[i])>0 then d=d+1 end
109 | end
110 | l=(#AttributeValue+1)*e-d
111 | end
112 | return -l
113 | end
114 |
115 | local Compare = function(p1,p2)
116 | count = count+1
117 | local l1 = band(tonumber(p1.FileAttributes),FAMasque)
118 | local l2 = band(tonumber(p2.FileAttributes),FAMasque)
119 | if CompareMode then l1,l2 = BySelected(l1),BySelected(l2) end
120 | return l1l2 and 1 or 0)
121 | end
122 |
123 | local tFAttributes,tSAttributes,tCompareMode = {}
124 |
125 | local function DlgProc(hDlg,Msg,Param1,Param2)
126 | if Msg==F.DN_INITDIALOG then
127 | tSAttributes,tCompareMode = SAttributes,CompareMode
128 | hDlg:send(F.DM_SETTEXT,2,"File: "..(FName:len()<55 and FName or (FName:sub(1,27).."…"..FName:sub(-26,-1))))
129 | hDlg:send(F.DM_SETTEXT,4,tostring(tSAttributes):gsub("^0",""))
130 | for i=1,#AttributeValue do
131 | tFAttributes[i]=FAttributes[i]
132 | hDlg:send(F.DM_SETCHECK,i+7,tFAttributes[i] and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED)
133 | end
134 | hDlg:send(F.DM_SETCHECK,28,tCompareMode and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED)
135 | hDlg:send(F.DM_SETCHECK,29,xReport and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED)
136 | hDlg:send(F.DM_SETFOCUS,GFocus)
137 | elseif Msg==F.DN_EDITCHANGE and Param1==4 then
138 | local text = hDlg:send(F.DM_GETTEXT,4):lower()
139 | if text:match("^%d") then text=text:gsub("%D","")
140 | elseif text:match("^["..AttributesSymbols.."]") then text=text:gsub("[^"..AttributesSymbols.."]","")
141 | else text=text:gsub("[^%d"..AttributesSymbols.."]","")
142 | end
143 | if tonumber(text) then
144 | text = text:gsub("^0","")
145 | tSAttributes = band(tonumber(text) or 0,FAMasque)
146 | for i=1,#AttributeValue do
147 | tFAttributes[i] = band(tSAttributes,AttributeValue[i])==AttributeValue[i] and true or false
148 | hDlg:send(F.DM_SETCHECK,i+7,tFAttributes[i] and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED)
149 | end
150 | else
151 | tSAttributes,text = tostring(text),""
152 | for i=1,#AttributesSymbols do
153 | local symbol=AttributesSymbols:sub(i,i)
154 | local _,n = tSAttributes:gsub(symbol,symbol)
155 | if n==1 then tFAttributes[i]=true text=text..symbol else tFAttributes[i]=false end
156 | hDlg:send(F.DM_SETCHECK,i+7,tFAttributes[i] and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED)
157 | end
158 | tSAttributes = text
159 | end
160 | hDlg:send(F.DM_SETTEXT,4,text)
161 | elseif Msg==F.DN_BTNCLICK and Param1==5 then -- Get Attributes
162 | tSAttributes = mf.fattr(FPath) or tSAttributes
163 | hDlg:send(F.DM_SETTEXT,4,tSAttributes)
164 | for i=1,#AttributeValue do
165 | tFAttributes[i] = band(tSAttributes,AttributeValue[i])==AttributeValue[i] and true or false
166 | hDlg:send(F.DM_SETCHECK,i+7,tFAttributes[i] and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED)
167 | end
168 | elseif Msg==F.DN_BTNCLICK and Param1==6 then -- Set Attributes
169 | local ret=ffi.C.SetFileAttributesW(ToWChar(FPath.."\0\0"),tSAttributes)
170 | if ret==0 then far.Message("Fail :(","Result",";Ok","w") end
171 | elseif Msg==F.DN_BTNCLICK and Param1>7 and Param1<28 then -- Attributes
172 | local i=Param1-7
173 | tFAttributes[i] = Param2~=0
174 | if tonumber(tSAttributes) then
175 | tSAttributes = tFAttributes[i] and bor(tSAttributes,AttributeValue[i]) or band(tSAttributes,bnot(AttributeValue[i]))
176 | else
177 | tSAttributes = tFAttributes[i] and tSAttributes..AttributesSymbols:sub(i,i) or tSAttributes:gsub(AttributesSymbols:sub(i,i),"")
178 | end
179 | hDlg:send(F.DM_SETTEXT,4,tSAttributes)
180 | elseif Msg==F.DN_BTNCLICK and Param1==28 then tCompareMode = Param2~=0 -- [x] By Selected
181 | elseif Msg==F.DN_BTNCLICK and Param1==29 then xReport = Param2~=0 -- [x] Report
182 | else return
183 | end
184 | return true
185 | end
186 |
187 | Panel.LoadCustomSortMode(ModeNumber,{Description=Description;Indicator=Indicator;Compare=Compare})
188 |
189 | Macro {
190 | description = Description; area = "Shell Menu"; key = Key.." Enter MsLClick";
191 | condition = function(key) return Area.Shell and key==Key or Area.Menu and Menu.Id==MenuGuid and Menu.Value:match(Description) and (key=="Enter" or key=="MsLClick") end;
192 | action = function()
193 | local kbd=band(Far.KbdLayout(),0xFFFF)
194 | if kbd==0 and _G.KbdLayout then kbd=_G.KbdLayout() end
195 | if not kbd or kbd and kbd~=0x0409 then Far.KbdLayout(0x0409) end
196 | FName=APanel.Current
197 | FPath=APanel.Path0.."\\"..FName
198 | if not SAttributes then
199 | SAttributes=mf.fattr(FPath)
200 | for i=1,#AttributeValue do FAttributes[i] = band(SAttributes,AttributeValue[i])==AttributeValue[i] and true or false end
201 | end
202 | if Area.Menu then Keys("Esc") end
203 | if far.Dialog(uGuid,-1,-1,70,20,nil,Items,nil,DlgProc)==#Items-1 then
204 | SAttributes = tSAttributes
205 | local OldAttributesWeight = AttributesWeight
206 | AttributesWeight=0 for i=1,#AttributeValue do FAttributes[i]=tFAttributes[i] if FAttributes[i] then AttributesWeight=AttributesWeight+AttributeValue[i] end end
207 | if AttributesWeight~=OldAttributesWeight or tCompareMode~=CompareMode then panel.SetSortOrder(nil,1,band(panel.GetPanelInfo(nil,1).Flags,F.PFLAGS_REVERSESORTORDER)==0) end
208 | CompareMode = tCompareMode
209 | count = 0
210 | local ttime=far.FarClock()
211 | Panel.LoadCustomSortMode(ModeNumber,{Description=Description;Indicator=Indicator;Compare=Compare})
212 | Panel.SetCustomSortMode(ModeNumber,0)
213 | ttime = far.FarClock()-ttime
214 | local report = "Curr count: "..count.." mcs: "..ttime
215 | if count0 then
216 | report = report.."\nPrev count: "..count0.." mcs: "..ttime0.."\nDifference:"..string.format("%+"..(string.len(tostring(count0))+1).."d",count-count0).." mcs:"..string.format("%+"..(string.len(tostring(ttime0))+1).."d",ttime-ttime0)
217 | end
218 | count0,ttime0 = count,ttime
219 | panel.RedrawPanel(nil,1)
220 | if xReport then far.Message(report,"Report",nil,"l") end
221 | end
222 | if kbd and type(kbd)=="number" and kbd~=0x0409 then Far.KbdLayout(kbd) end
223 | end;
224 | }
225 |
226 | Macro {
227 | description = Description.." - Help"; area = "Dialog"; key = "F1";
228 | condition=function() return Area.Dialog and Dlg.Id==guid end;
229 | action=function()
230 | if Dlg.CurPos==4 then far.Message("Number or string","Help: Attributes")
231 | elseif Dlg.CurPos==5 then far.Message("Get attributes from file under cursor","Help: Get")
232 | elseif Dlg.CurPos==6 then far.Message("Set attributes","Help: Set")
233 | elseif Dlg.CurPos>7 and Dlg.CurPos<28 then far.Message("Change attribute","Help: Change")
234 | elseif Dlg.CurPos==28 then far.Message("Group files by selected attributes","Help: Mode")
235 | elseif Dlg.CurPos==29 then far.Message("Show report","Help: Report")
236 | end
237 | end;
238 | }
239 |
--------------------------------------------------------------------------------
/Editor.FilterDuplicatesFileNames.lua:
--------------------------------------------------------------------------------
1 | -- Editor.FilterDuplicatesFileNames.lua
2 | -- v1.2.3.1
3 | -- Filter Duplicates File Names with complex logic
4 | -- 
5 | -- Keys: launch from Macro Browser alt.
6 | -- Tip: In the dialog all elements have prompts, press F1 for help
7 |
8 | local guid = "FE9B8874-9651-434C-8182-72329F2371A5"
9 | local uGuid = win.Uuid(guid)
10 | local Temp = win.GetEnv("Temp")
11 | local lstfile = "EFDFN-FList.txt"
12 | lstfile = Temp.."\\"..lstfile
13 | local FList = lstfile
14 | local repfile = "EFDFN-Report.txt"
15 | repfile = Temp.."\\"..repfile
16 | local FReport = repfile
17 |
18 |
19 | local F = far.Flags
20 | local ffi = require'ffi'
21 | local C = ffi.C
22 |
23 | local bit_band,bit_bnot,bit_bor = bit.band,bit.bnot,bit.bor
24 | local bit64_bor = bit64.bor
25 | local editor_Editor,editor_GetStringW = editor.Editor,editor.GetStringW
26 | local far_CPluginStartupInfo,far_Dialog,far_FarClock,far_Message,far_SendDlgMessage = far.CPluginStartupInfo,far.Dialog,far.FarClock,far.Message,far.SendDlgMessage
27 | local regex_matchW = regex.matchW
28 | local string_byte,string_rep = string.byte,string.rep
29 | local table_insert,table_remove,table_sort = table.insert,table.remove,table.sort
30 | local win_GetFileAttr,win_Utf16ToUtf8,win_Utf8ToUtf16 = win.GetFileAttr,win.Utf16ToUtf8,win.Utf8ToUtf16
31 |
32 | local NULL = ffi.cast("void*",0)
33 | local pHTAB = ffi.cast("void*",win_Utf8ToUtf16("\t"))
34 | local PANEL_ACTIVE = ffi.cast("HANDLE",-1)
35 | local pBL0,pBL1 = ffi.cast("BOOL*",0),ffi.cast("BOOL*",1)
36 | local FSF = ffi.cast("struct PluginStartupInfo*",far_CPluginStartupInfo()).FSF
37 | local ZERO,HTAB,BS = ffi.cast("unsigned int",0),ffi.cast("unsigned int",9),string_byte("\\")
38 | local ts = {nil,true,9999,true,false,2,2,true,true}
39 | local Flags = C.SORT_STRINGSORT
40 | local tts,FullPathEF,FileSizeEF,FileAttrEF = {}
41 |
42 | ffi.cdef[[
43 | unsigned long int wcstoul(const wchar_t*, wchar_t**, int);
44 | unsigned long long int wcstoull(const wchar_t*, wchar_t**, int);
45 | ]]
46 |
47 | local function ToWChar(str)
48 | str=win_Utf8ToUtf16(str)
49 | local res=ffi.new("wchar_t[?]",#str/2+1)
50 | ffi.copy(res,str)
51 | return res
52 | end
53 |
54 | local function GetStartAndLenW(name)
55 | local ptr = C.wcsrchr(name,BS)
56 | name = ptr==NULL and name or ptr+1
57 | local len = tonumber(C.wcslen(name))
58 | if ts[2] and ts[3]<0 and -ts[3]0 and ts[3]0
100 | end
101 |
102 | local Items = {
103 | --[[01]] {F.DI_DOUBLEBOX, 3,1, 65,9, 0, 0,0, 0, "Filter duplicates of FileName. Help: F1"},
104 | --[[02]] {F.DI_CHECKBOX, 5,2, 26,2, 0, 0,0, 0, "Num&ber of symbols"},
105 | --[[03]] {F.DI_EDIT, 27,2, 32,2, 0, 0,0, 0, ""},
106 | --[[04]] {F.DI_CHECKBOX, 5,3, 20,3, 0, 0,0, 0, "Ignore &case"},
107 | --[[05]] {F.DI_CHECKBOX, 38,3, 62,3, 0, 0,0, 0, "Ignore Full &Duplicates"},
108 | --[[06]] {F.DI_CHECKBOX, 5,4, 21,4, 0, 0,0, F.DIF_3STATE, "&Sizes of FD:"},
109 | --[[07]] {F.DI_CHECKBOX, 5,5, 26,5, 0, 0,0, F.DIF_3STATE, "&Attributes of FD:"},
110 | --[[08]] {F.DI_CHECKBOX, 5,6, 35,6, 0, 0,0, 0, "Accuracy (&two-pass method)"},
111 | --[[09]] {F.DI_CHECKBOX, 5,8, 15,8, 0, 0,0, 0, "Re&port"},
112 | --[[10]] {F.DI_TEXT, -1,7, 0,0, 0, 0,0, F.DIF_SEPARATOR,""},
113 | --[[11]] {F.DI_BUTTON, 0,8, 0,0, 0, 0,0, F.DIF_DEFAULTBUTTON+F.DIF_CENTERGROUP,"&Ok"},
114 | --[[12]] {F.DI_BUTTON, 0,8, 0,0, 0, 0,0, F.DIF_CENTERGROUP,"Ca&ncel"}
115 | }
116 |
117 | local function DlgProc(hDlg,Msg,Param1,Param2)
118 | if Msg==F.DN_INITDIALOG then
119 | for i=2,#Items-3 do tts[i]=ts[i] end
120 | far_SendDlgMessage(hDlg,F.DM_SETTEXT,3,tts[3])
121 | far_SendDlgMessage(hDlg,F.DM_SETCHECK,2,tts[2] and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED)
122 | far_SendDlgMessage(hDlg,F.DM_SETCHECK,4,tts[4] and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED)
123 | far_SendDlgMessage(hDlg,F.DM_SETCHECK,5,tts[5] and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED)
124 | far_SendDlgMessage(hDlg,F.DM_SETCHECK,6,tts[6]==0 and F.BSTATE_UNCHECKED or tts[6]==1 and F.BSTATE_CHECKED or tts[6]==2 and F.BSTATE_3STATE)
125 | far_SendDlgMessage(hDlg,F.DM_SETTEXT,6,"&Sizes of FD: "..(tts[6]==0 and "<>" or tts[6]==1 and "==" or "--"))
126 | far_SendDlgMessage(hDlg,F.DM_ENABLE,6,FileSizeEF and 1 or 0)
127 | far_SendDlgMessage(hDlg,F.DM_SETCHECK,7,tts[7]==0 and F.BSTATE_UNCHECKED or tts[7]==1 and F.BSTATE_CHECKED or tts[7]==2 and F.BSTATE_3STATE)
128 | far_SendDlgMessage(hDlg,F.DM_SETTEXT,7,"&Attributes of FD: "..(tts[7]==0 and "<>" or tts[7]==1 and "==" or "--"))
129 | far_SendDlgMessage(hDlg,F.DM_ENABLE,7,FileAttrEF and 1 or 0)
130 | far_SendDlgMessage(hDlg,F.DM_SETCHECK,8,tts[8] and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED)
131 | far_SendDlgMessage(hDlg,F.DM_ENABLE,8,FileSizeEF and 1 or 0)
132 | far_SendDlgMessage(hDlg,F.DM_SETCHECK,9,tts[9] and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED)
133 | elseif Msg==F.DN_BTNCLICK and (Param1==2 or Param1==4 or Param1==5 or Param1==8 or Param1==9) then
134 | tts[Param1] = Param2~=0
135 | elseif Msg==F.DN_BTNCLICK and (Param1==6 or Param1==7) then
136 | tts[Param1] = Param2
137 | far_SendDlgMessage(hDlg,F.DM_SETTEXT,Param1,(Param1==6 and "&Sizes of FD: " or "&Attributes of FD: ")..(Param2==0 and "<>" or Param2==1 and "==" or "--"))
138 | elseif Msg==F.DN_EDITCHANGE and Param1==3 then -- Number symbols
139 | tts[3] = tonumber(far_SendDlgMessage(hDlg,F.DM_GETTEXT,3)) or tts[3]
140 | else
141 | return
142 | end
143 | return true
144 | end
145 |
146 |
147 | Macro {
148 | description="EFDFN: Filter Duplicates FileName in Editor"; name="EFDFN"; area="Shell Editor";
149 |
150 | action=function()
151 | if Area.Shell then
152 | local t0 = far_FarClock()
153 | local count=0
154 | while true do
155 | if win_GetFileAttr(FList)
156 | then count=count+1 FList=lstfile:gsub("%.txt$","_"..count..".txt")
157 | else break
158 | end
159 | end
160 | local h=io.open(FList,"w+b")
161 | FSF.FarRecursiveSearch(ToWChar(APanel.Path),ToWChar("*"),
162 | function (ppi,FullPath,NULL)
163 | local attr=tonumber(ppi.FileAttributes)
164 | local size=tonumber(ppi.FileSize)
165 | if bit_band(attr,C.FILE_ATTRIBUTE_DIRECTORY)==0 then
166 | h:write(tostring(attr).."\t"..tostring(size).."\t"..win_Utf16ToUtf8(ffi.string(FullPath,C.wcslen(FullPath)*2)).."\n")
167 | end
168 | return true
169 | end
170 | ,F.FRS_RETUPDIR+F.FRS_RECUR+F.FRS_SCANSYMLINK,NULL)
171 | io.close(h)
172 | far_Message("mcs: "..far_FarClock()-t0,"CLFN")
173 | editor_Editor(FList,nil,0,0,-1,-1,bit64_bor(F.EF_NONMODAL,F.EF_IMMEDIATERETURN,F.EF_OPENMODE_RELOADIFOPEN),1,1,65001)
174 | end
175 | local line=editor_GetStringW(-1,1,0).StringText
176 | if line then
177 | FileSizeEF,FileAttrEF,FullPathEF = regex_matchW(line,[[^(\d+\t)?(\d+\t)?([^\t]+)$]])
178 | ts[6],ts[7] = FileSizeEF and ts[6] or 2,FileAttrEF and ts[7] or 2
179 | end
180 | if far_Dialog(uGuid,-1,-1,69,11,nil,Items,nil,DlgProc)==#Items-1 then
181 | local t0 = far_FarClock()
182 | for i=2,#Items-3 do ts[i]=tts[i] end
183 | Flags = ts[4] and bit_bor(Flags,C.NORM_IGNORECASE) or bit_band(Flags,bit_bnot(C.NORM_IGNORECASE))
184 | local tsel = {}
185 | local ec=ffi.cast("struct PluginStartupInfo*",far_CPluginStartupInfo()).EditorControl
186 | local ei=ffi.new("struct EditorInfo")
187 | ei.StructSize=ffi.sizeof(ei)
188 | if ec(-1,"ECTL_GETINFO",0,ei) then
189 | local LastLine=tonumber(ei.TotalLines)
190 | local egs=ffi.new("struct EditorGetString")
191 | egs.StructSize=ffi.sizeof(egs)
192 | local function PGPL(i)
193 | egs.StringNumber=i
194 | if ec(-1,"ECTL_GETSTRING",0,egs) then
195 | local st1,ln1,st3,ln3,sz1,fa1=StartAndLenW(egs.StringText)
196 | table_insert(tsel,{false,st1,ln1,st3,ln3,sz1,fa1,i,egs.StringText})
197 | end
198 | end
199 | for i=0,LastLine-1 do PGPL(i) end
200 | table_sort(tsel,compare)
201 | for i=2,LastLine do
202 | if C.CompareStringW(C.LOCALE_USER_DEFAULT,Flags,tsel[i-1][2],tsel[i-1][3],tsel[i][2],tsel[i][3])==2 then
203 | local x = C.CompareStringW(C.LOCALE_USER_DEFAULT,Flags,tsel[i-1][4],tsel[i-1][5],tsel[i][4],tsel[i][5])==2
204 | local y = (ts[6]==0 and tsel[i-1][6]~=tsel[i][6] or ts[6]==1 and tsel[i-1][6]==tsel[i][6] or ts[6]==2)
205 | and (ts[7]==0 and tsel[i-1][7]~=tsel[i][7] or ts[7]==1 and tsel[i-1][7]==tsel[i][7] or ts[7]==2)
206 | if not ts[5] and (not ts[2] and x and y or ts[2] and y)
207 | or ts[5] and (ts[6]==0 and tsel[i-1][6]==tsel[i][6] or ts[6]==1 and tsel[i-1][6]~=tsel[i][6])
208 | and (ts[7]==0 and tsel[i-1][7]==tsel[i][7] or ts[7]==1 and tsel[i-1][7]~=tsel[i][7])
209 | then
210 | tsel[i-1][1]=true
211 | tsel[i][1]=true
212 | end
213 | end
214 | end
215 | -- -ts[5] and ts[6]==0
216 | -- +ts[5] and ts[6]==1
217 | -- +not ts[5] and ts[6]==0
218 | -- -not ts[5] and ts[6]==1
219 | if ts[8] then
220 | for i=2,LastLine do
221 | if (((ts[5] and ts[6]==1 or not ts[5] and ts[6]==0) and tsel[i-1][6]==tsel[i][6])
222 | or ((ts[5] and ts[7]==1 or not ts[5] and ts[7]==0) and tsel[i-1][7]==tsel[i][7]))
223 | and C.CompareStringW(C.LOCALE_USER_DEFAULT,Flags,tsel[i-1][4],tsel[i-1][5],tsel[i][4],tsel[i][5])==2
224 | then
225 | tsel[i-1][1]=false
226 | tsel[i][1]=false
227 | end
228 | end
229 | end
230 | end
231 | if ts[9] then
232 | local icount=0
233 | for i=1,#tsel do if tsel[i][1] then icount=icount+1 end end
234 | local count=0
235 | while true do
236 | if win_GetFileAttr(FReport)
237 | then count=count+1 FReport=repfile:gsub("%.txt$","_"..count..".txt")
238 | else break
239 | end
240 | end
241 | local h=io.open(FReport,"w+b")
242 | h:write("Items: "..icount.."/"..#tsel..
243 | "\nExecution time: "..(far_FarClock()-t0)..
244 | " mcs\nNumber of symbols: "..(ts[2] and ts[3] or "all")..
245 | "\nIgnore case: "..tostring(ts[4])..
246 | "\nIgnore Full Duplicates: "..tostring(ts[5])..
247 | "\nSizes of FD: "..(ts[6]==0 and "<>" or ts[6]==1 and "==" or "--")..
248 | "\nAttributes of FD: "..(ts[7]==0 and "<>" or ts[7]==1 and "==" or "--")..
249 | "\nAccuracy (two-pass method): "..tostring(ts[8])..
250 | "\n"..string_rep("-",30).."\n")
251 | for i=#tsel,1,-1 do if tsel[i][1] then h:write(tostring(tsel[i][8]+1).."\t"..win_Utf16ToUtf8(ffi.string(tsel[i][9],C.wcslen(tsel[i][9])*2)).."\n") end table_remove(tsel) end
252 | io.close(h)
253 | editor_Editor(FReport,nil,0,0,-1,-1,bit64_bor(F.EF_NONMODAL,F.EF_IMMEDIATERETURN,F.EF_OPENMODE_RELOADIFOPEN),1,1,65001)
254 | far_Message("mcs: "..far_FarClock()-t0,"EFDFN")
255 | end
256 | end
257 | end;
258 | }
259 |
260 | Macro {
261 | description = "EFDFN - Help"; area = "Dialog"; key = "F1";
262 | condition=function() return Area.Dialog and Dlg.Id==guid end;
263 | action=function()
264 | if Dlg.CurPos<=3 then far_Message("The number of first or last symbols to compare","Help: Number of symbols")
265 | elseif Dlg.CurPos==4 then far_Message("Case of letters in FileName will be ignored","Help: Ignore case")
266 | elseif Dlg.CurPos==5 then far_Message("Full duplicates of FileName will be ignored","Help: Ignore Full Duplicates")
267 | elseif Dlg.CurPos==6 then far_Message("-- ignore, == equal, <> is not equal","Help: Sizes of FD")
268 | elseif Dlg.CurPos==7 then far_Message("-- ignore, == equal, <> is not equal","Help: Attributes of FD")
269 | elseif Dlg.CurPos==8 then far_Message("Two-pass method for\n<> (is not equal) options only","Help: Accuracy")
270 | elseif Dlg.CurPos==9 then far_Message("mcs - total time of execution in mcs\nReport will be saved to:\n"..FReport,"Help: Report",nil,"l")
271 | end
272 | end;
273 | }
274 |
--------------------------------------------------------------------------------
/FarUpdate.lua:
--------------------------------------------------------------------------------
1 | -- FarUpdate.lua
2 | -- v1.9.2
3 | -- Opening changelog and updating Far Manager to any version available on the site
4 | -- 
5 | -- Far: press **[ Reload last ]** to reload the list with files
6 | -- GitHub: press **[ More >> ]** to get more files
7 | -- GitHub: press **[ Reload last ]** to reload last page with files
8 | -- GitHub: press **[ Reload all ]** to reload all pages
9 | -- GitHub: press **[ Goto build ]** to go to enter build number
10 | -- When you run the macro again, the build will be taken from the current line in Far.changelog
11 | -- Required: curl.exe, nircmd.exe, 7z.exe, requires tuning for local conditions
12 | -- Keys: launch from Macro Browser alt.
13 | -- Url: https://forum.ru-board.com/topic.cgi?forum=5&topic=49572&start=700#19
14 |
15 | local function fwrite(f,s) local x,h = nil,io.open(f,"wb") if h then x=h:write(s or "") io.close(h) end return x end
16 | local function GetPage(x) panel.GetUserScreen() local s="" if x then s=io.popen('curl.exe '..x,'rb'):read('*all') end panel.SetUserScreen() return s end
17 |
18 | local F=far.Flags
19 | local guid="0EEE33E2-1E95-4753-982C-B2BD1E63C3C4"
20 | local uGuid=win.Uuid(guid)
21 | -- 32 13 23 -- 44 19 35
22 | local items={
23 | --[[01]] {F.DI_DOUBLEBOX, 0,0, 32,6, 0, 0,0, 0, "Download file?"},
24 | --[[02]] {F.DI_BUTTON, 2,1, 0,1, 0, 0,0, F.DIF_BTNNOCLOSE, "[ &1 Far ]"},
25 | --[[03]] {F.DI_BUTTON, 12,1, 0,1, 0, 0,0, F.DIF_BTNNOCLOSE, "[ &2 x86 ]"},
26 | --[[04]] {F.DI_BUTTON, 22,1, 0,1, 0, 0,0, F.DIF_BTNNOCLOSE, "[ &3 7z ]"},
27 | --[[05]] {F.DI_TEXT, 1,2, 1,2, 0, 0,0, 0, " "},
28 | --[[06]] {F.DI_COMBOBOX, 2,2, 30,2,{}, 0,0, F.DIF_DROPDOWNLIST, ""},
29 | --[[07]] {F.DI_TEXT, 0,3, 0,0, 0, 0,0, F.DIF_SEPARATOR, ""},
30 | --[[08]] {F.DI_CHECKBOX, 8,3, 0,3, 0, 0,0, 0,"&Profile BackUp"},
31 | --[[09]] {F.DI_BUTTON, 0,4, 0,0, 0, 0,0, F.DIF_DEFAULTBUTTON+F.DIF_CENTERGROUP, "&Update"},
32 | --[[10]] {F.DI_BUTTON, 0,4, 0,0, 0, 0,0, F.DIF_CENTERGROUP, "&Yes"},
33 | --[[11]] {F.DI_BUTTON, 0,4, 0,0, 0, 0,0, F.DIF_CENTERGROUP, "&No"}
34 | }
35 | local mark=string.char(24) --
36 | local tmp=win.GetEnv("TEMP").."\\"
37 | local farhome=win.GetEnv("FARHOME")
38 | local farprofile=win.GetEnv("FARPROFILE")
39 | local fp7z=farprofile..'.7z'
40 | local x64=win.IsProcess64bit()
41 | local pages,FileName = {}
42 | local GitItemsPerPage,ListActions = 100,{"* [ More >> ]","* [ Reload last ]","* [ Reload all ]","* [ Goto build ]"}
43 | local RealPos,FileList = 1,{}
44 | local box={true,x64,1,false} -- [ Far ] [ x64 ] [ 1=7z 2=msi 3=pdb.7z ] [ ] Profile BackUp
45 | local EGI,StringText,build,xbuild,XD,YD
46 | local WaitCloseFar='nircmd.exe waitprocess "'..farhome..'\\Far.exe"'
47 | local ProfileBackUp='\n7z.exe a -aoa -xr!CrashLogs "'..fp7z..'" "'..farprofile..'" > '..tmp..'FarProfileBackUp.log'
48 | local ConEmu=farhome..'\\ConEmu'..(box[2] and '64' or '')..'.exe'
49 | local FarLnk=farhome..'\\Far.lnk'
50 | local FarExe=farhome..'\\Far.exe'
51 | local StartFar=function() return '\nstart "" "'..(win.GetFileAttr(ConEmu) and ConEmu or (win.GetFileAttr(FarLnk) and FarLnk or FarExe))..'"\nexit' end
52 | local FarProfileBackUpBat=tmp..'FarProfileBackUp.bat'
53 | local FarUpdateBat=tmp..'FarUpdate.bat'
54 |
55 | XItems={
56 | {F.DI_DOUBLEBOX, 0,0,17,2,0, 0,0, 0, "Goto"},
57 | {F.DI_TEXT, 2,1, 7,1,0, 0,0, 0,"build:"},
58 | {F.DI_EDIT, 9,1,15,1,0, 0,0, 0, ""}
59 | }
60 |
61 | local function XDlgProc(hDlg,Msg,Param1,Param2)
62 | if Msg==F.DN_INITDIALOG then hDlg:send(F.DM_SETTEXT,3,tostring(build or ""))
63 | elseif Msg==F.DN_CLOSE and Param1==3 then xbuild=tonumber(tostring(hDlg:send(F.DM_GETTEXT,Param1)):match("%d+"))
64 | end
65 | end
66 |
67 | -- Create FarUpdate.bat
68 | local function FarUpdate(FileName)
69 | local s,u = '',not string.find(FileName,'%.pdb%.[^%.]+$')
70 | if u then
71 | s=s..WaitCloseFar
72 | if box[4] then win.MoveFile(fp7z,fp7z..'_','r') s=s..ProfileBackUp end
73 | end
74 | s=s..'\n7z.exe x -aoa -o"'..farhome..'" -x!PluginSDK -xr@"'..tmp..'FarUpdExc.txt" "'..tmp..FileName..'" > '..tmp..'FarUpdate.log'
75 | if u then s=s..StartFar() end
76 | fwrite(FarUpdateBat,s)
77 | s='*Spa.lng\n*Sky.lng\n*Sky.hlf\n*Ger.lng\n*Ger.hlf\n*Hun.lng\n*Hun.hlf\n*Ita.lng\n*Pol.lng\n*Pol.hlf\n*.pol.*\n*Cze.lng\n*Cze.hlf\n*Ukr.lng\n*Ukr.hlf\n*Bel.lng\n*Bel.hlf\n*.bel.*\n*Lit.lng'
78 | if u then s=s..'\n*.map\n*.pdb' end
79 | fwrite(tmp..'FarUpdExc.txt',s)
80 | end
81 |
82 | local function FLFAR()
83 | local urlh='https://farmanager.com/nightly'
84 | local text=GetPage(urlh..'.php')
85 | -- fwrite(tmp..'nightly.php',text)
86 | -- nightly%/(Far30b%d-)%.x86%.(%d%d%d%d)(%d%d)(%d%d)%.7z
87 | for fname,build,xx,year,month,day,ext in text:gmatch('"nightly%/(Far30b(%d-)%.(x%d%d)%.(%d%d%d%d)(%d%d)(%d%d)%.(%w+)[^"]-)"') do
88 | if ext then table.insert(FileList,{build..xx..' '..year..'-'..month..'-'..day..' '..ext,urlh..'/'..fname,0,fname}) end
89 | end
90 | end
91 |
92 | local function FLGIT(page,items)
93 | items=items or GitItemsPerPage
94 | local text=GetPage('--get "https://api.github.com/repos/FarGroup/FarManager/releases" --data "page='..page..'&per_page='..items..'"')
95 | --fwrite(tmp..'nightly.php',text)
96 | -- /Far.x64.3.0.5523.1332.0e89356681209509d3db8c5dcfbe6a82194d14a4.pdb.7z
97 | local patt='%},(%c%c-[^%}%{]-"browser_download_url" ?: ?"(http[^"]-)"[^%}%{]-)%}'
98 | for txt,url in text:gmatch(patt) do
99 | local size=txt:match('"size" ?: ?(%d+)')
100 | if size then size=math.floor(tonumber(size)/100000+1)/10 size=' '..tostring(size)..'MB' else size='' end
101 | -- 2019-12-10T18:59:06Z
102 | local date=txt:match('"updated_at" ?: ?"([^"]-)"') or txt:match('"created_at" ?: ?"([^"]-)"')
103 | if date then date=' '..date:gsub("T"," "):gsub("Z","") else date='' end
104 | local fname,xx,build,ext = url:match('%/(Far%.(x%d%d)%.3%.0%.(%d-)%.%d-%.[0-9a-f]-%.(%w+).-)$')
105 | if ext then table.insert(FileList,{build..xx..date..' '..ext..size,url,page,fname}) end
106 | end
107 | end
108 |
109 | local function GetFileList(page,items)
110 | local brk
111 | if not page then page=box[1] and 0 or 1 end
112 | for _,v in pairs(pages) do if page==v then brk=true break end end
113 | if not brk then
114 | if page==0
115 | then FLFAR() if #FileList==0 then page=1 FLGIT(page,items) end
116 | else FLGIT(page,items) if #FileList==0 then page=0 FLFAR() end
117 | end
118 | table.insert(pages,page)
119 | end
120 | end
121 |
122 | local ListT,PosProtect = {}
123 | local function DlgProc(hDlg,Msg,Param1,Param2)
124 | local function BoxUpdate()
125 | hDlg:send(F.DM_SETTEXT,2,box[1] and '[ &1 Far ]' or '[ &1 Git ]')
126 | hDlg:send(F.DM_SETTEXT,3,box[2] and '[ &2 x64 ]' or '[ &2 x86 ]')
127 | hDlg:send(F.DM_SETTEXT,4,box[3]==1 and '[ &3 7z ]' or (box[3]==2 and '[ &3 msi ]' or '[ &3 pdb ]'))
128 | end
129 | local function RefreshList()
130 | local ListInfo=hDlg:send(F.DM_LISTINFO,6)
131 | local LastPos=ListInfo.ItemsNumber
132 | hDlg:send(F.DM_LISTDELETE,6,{StartIndex=1,Count=LastPos}) ListT={}
133 | for i=1,#FileList do
134 | if FileList[i][4]:find('^Far'..(box[1] and '30b%d-%.' or '%.')..(box[2] and 'x64' or 'x86')..'%..+'..(box[3]==1 and '[^%.]...%.7z' or (box[3]==2 and '%.msi' or '%.pdb%.7z')))
135 | then hDlg:send(F.DM_LISTADD,6,{{Text=FileList[i][1]}}) table.insert(ListT,{FileList[i][1],FileList[i][3]})
136 | end
137 | end
138 | if box[1]
139 | then hDlg:send(F.DM_LISTADD,6,{{Text=ListActions[2]}}) table.insert(ListT,ListActions[2])
140 | else
141 | for i=1,#ListActions do
142 | hDlg:send(F.DM_LISTADD,6,{{Text=ListActions[i]}}) table.insert(ListT,ListActions[i])
143 | end
144 | end
145 | if build then
146 | local ans
147 | for i=1,#ListT do
148 | if type(ListT[i])=="table" then ans=ListT[i][1]:find("^"..build) end
149 | if ans then RealPos=PosProtect and RealPos or i PosProtect=false break end
150 | end
151 | end
152 | hDlg:send(F.DM_LISTSETCURPOS,6,{SelectPos=RealPos})
153 | FileName=tostring(hDlg:send(F.DM_GETTEXT,6))
154 | hDlg:send(F.DM_SETFOCUS,6)
155 | end
156 | local function RemoveListActions(pos)
157 | for i=pos,pos-#ListActions-1,-1 do
158 | local FarListItem=hDlg:send(F.DM_LISTGETITEM,6,i)
159 | if FarListItem and FarListItem.Text:sub(1,1)=="*" then
160 | hDlg:send(F.DM_LISTDELETE,6,{StartIndex=i,Count=1})
161 | table.remove(ListT,i)
162 | else break
163 | end
164 | end
165 | end
166 | if Msg==F.DN_INITDIALOG then
167 | BoxUpdate()
168 | RefreshList()
169 | hDlg:send(F.DM_SETTEXT,5,RealPos>1 and mark or ' ')
170 | hDlg:send(F.DM_SETCHECK,8,box[4] and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED)
171 | elseif (Msg==F.DN_EDITCHANGE or Msg==F.DN_LISTCHANGE) and Param1==6 then
172 | local ListInfo=hDlg:send(F.DM_LISTINFO,6)
173 | local LastPos=ListInfo.ItemsNumber
174 | local SelectPos=ListInfo.SelectPos
175 | local str=tostring(hDlg:send(F.DM_GETTEXT,6))
176 | RealPos=SelectPos==0 and RealPos or SelectPos
177 | if Msg==F.DN_EDITCHANGE and str and str:sub(1,1)=="*"
178 | then
179 | if str==ListActions[1] and FileList[#FileList] then
180 | RemoveListActions(LastPos)
181 | GetFileList(FileList[#FileList][3]+1)
182 | PosProtect=true
183 | elseif str==ListActions[2] and FileList[#FileList] then
184 | RemoveListActions(LastPos)
185 | if #ListT>0 then
186 | local page=FileList[#FileList][3]
187 | table.remove(pages)
188 | for i=#FileList,1,-1 do if FileList[i][3]==page then table.remove(FileList,i) else break end end
189 | GetFileList(page)
190 | local p=ListT[#ListT][2]
191 | for i=#ListT,1,-1 do if ListT[i][2]==p then table.remove(ListT,i) else RealPos=i+1 PosProtect=true break end end
192 | end
193 | elseif str==ListActions[3] then
194 | RemoveListActions(LastPos)
195 | local p={} for i=1,#pages do p[i]=pages[i] end
196 | pages={} FileList={}
197 | for i=1,#p do GetFileList(p[i]) end
198 | RealPos=1
199 | elseif str==ListActions[4] and FileList[#FileList] then
200 | RemoveListActions(LastPos)
201 | far.Dialog("",XD+7,YD+1,XD+7+XItems[1][4],YD+3,nil,XItems,F.FDLG_SMALLDIALOG+F.FDLG_WARNING,XDlgProc)
202 | build=xbuild or build
203 | if build and #FileList>0 and build<=tonumber(FileList[1][1]:match("^(%d+)")) then
204 | while build1 and mark or ' ')
212 | elseif Msg==F.DN_BTNCLICK and Param1>=2 and Param1<=4 then -- [ Far ] [ x86 ] [ 7z ]
213 | local p=Param1-1
214 | box[p]=p==3 and (box[p]==3 and 1 or box[p]+1) or not box[p]
215 | BoxUpdate()
216 | local ListInfo=hDlg:send(F.DM_LISTINFO,6)
217 | local LastPos=ListInfo.ItemsNumber
218 | local str=tostring(hDlg:send(F.DM_GETTEXT,6))
219 | build=tonumber(str:match("^%d+"))
220 | RemoveListActions(LastPos)
221 | if Param1==2 then GetFileList() end
222 | RealPos=1
223 | RefreshList()
224 | elseif Msg==F.DN_BTNCLICK and Param1==8 then -- [ ] Profile BackUp
225 | box[4]=not box[4]
226 | end
227 | end
228 |
229 | Macro {
230 | area="Common"; flags=""; description="! FarUpdate";
231 | action=function()
232 | local changelog="Far.changelog"
233 | local f=tmp..changelog
234 | --fwrite(f,GetPage('-L https://github.com/FarGroup/FarManager/raw/master/far/changelog'))
235 | fwrite(f,GetPage('https://raw.githubusercontent.com/FarGroup/FarManager/master/far/changelog'))
236 | repeat
237 | GetFileList()
238 | if #FileList>0 then break end
239 | until far.Message("Servers don't answer\n\nTry again?","WARNING!",";YesNo","w")~=1
240 | if #FileList==0 then return end
241 | editor.Editor(f,nil,0,0,-1,-1,bit64.bor(F.EF_NONMODAL,F.EF_IMMEDIATERETURN,F.EF_OPENMODE_USEEXISTING),1,1,nil)
242 | EGI=editor.GetInfo()
243 | if EGI then
244 | local FileName=EGI.FileName
245 | if FileName then
246 | FileName=FileName:match("[^%\\]+$")
247 | if FileName==changelog then
248 | for CurLine=EGI.CurLine,1,-1 do
249 | StringText=editor.GetString(EGI.EditorID,CurLine).StringText
250 | if StringText then build=tonumber(StringText:match(' build (%d+)%s*$')) end
251 | if build then break end
252 | end
253 | end
254 | end
255 | end
256 | local w=far.AdvControl(F.ACTL_GETFARRECT)
257 | XD,YD = w.Right-items[1][4]-2,w.Bottom-w.Top-7
258 | local res=far.Dialog(uGuid,XD,YD,w.Right-2,w.Bottom-w.Top-2,nil,items,F.FDLG_SMALLDIALOG,DlgProc)
259 | if res==#items-2 or res==#items-1 then
260 | if FileName and #FileList>0 then
261 | local url
262 | for _,v in pairs(FileList) do if v[1]==FileName then url,FileName = v[2],v[4] break end end
263 | if url and (not win.GetFileInfo(tmp..FileName) or far.Message("Download it again?","WARNING! File exist",";YesNo","w")==1)
264 | then panel.GetUserScreen() win.system('curl.exe -g -L --location-trusted "'..url..'" -o "'..tmp..FileName..'"') panel.SetUserScreen()
265 | end
266 | if res==#items-2 then
267 | FarUpdate(FileName)
268 | panel.GetUserScreen() win.system('start /MIN '..FarUpdateBat) panel.SetUserScreen()
269 | end
270 | end
271 | end
272 | end;
273 | }
274 |
275 | -- FarProfileBackUp.lua 1.0.2
276 | Macro {
277 | area="Common"; flags=""; description="! FarProfileBackUp";
278 | action=function()
279 | win.MoveFile(fp7z,fp7z..'_','r')
280 | fwrite(FarProfileBackUpBat,WaitCloseFar..ProfileBackUp..StartFar())
281 | panel.GetUserScreen() win.system('start /MIN '..FarProfileBackUpBat) panel.SetUserScreen()
282 | end;
283 | }
--------------------------------------------------------------------------------
/ChessKnight.lua:
--------------------------------------------------------------------------------
1 | -- ChessKnight.lua
2 | -- v0.9.2.4
3 | -- Finding the path of the chess knight. The path can be closed. The chessboard can be up to 127x127 in size, with any aspect ratio. Rules: previously visited squares and squares with holes are not available for moving.
4 | -- 
5 | -- Launch: in cmdline Far.exe: lua:@ChessKnight.lua
6 |
7 | -- Обход конём шахматной доски произвольного размера, посещённые ранее клетки и клетки с дырами для ходов недоступны.
8 | local log = 0 -- logging in %TEMP%\ChessKnight.log, max board 15x15, 1 move = 1 byte storing xy
9 | local ret0 = 0 -- =0 без обязательного возврата к клетке старта, =1 с возвратом (замкнутый путь)
10 | local name="ChessKnight"
11 | local logname = name..".log"
12 | local txtname = name..".txt"
13 |
14 | local ffi = require"ffi"
15 | local C=ffi.C
16 | local NULL = ffi.cast("void*",0)
17 | local ffi_copy=ffi.copy
18 | local s=string
19 | local string_byte,string_format = s.byte,s.format
20 |
21 | local F = far.Flags
22 | local title="Chess Knight"
23 | local uuid=win.Uuid"F625937B-B79A-4D58-92B7-9B40BC374F21"
24 | local temp=win.GetEnv"TEMP".."\\"
25 | local status,variants = 0
26 |
27 | ::ANSWER::
28 | local answer = far.InputBox(uuid,title,"board 6x6, start 1 1, ret 1, log 1, holes 42,43: 6 6 1 1 1 1 42 43",name..".lua",nil,nil,nil,F.FIB_NONE) or ""
29 | local holes,bx,by,fbx,fby,x0,y0 = {}
30 | if answer=="" then bx,by,x0,y0 = 8,8,1,1
31 | elseif string.find(answer,"^%d+%s+%d+$") then x0,y0,bx,by = 1,1,string.match(answer,"(%d+)%s+(%d+)") bx,by = tonumber(bx),tonumber(by)
32 | else
33 | local t={}
34 | for n in string.gmatch(answer,"%d+") do table.insert(t,tonumber(n)) end
35 | bx,by,x0,y0,ret0,log = unpack(t)
36 | if x0<1 then x0=1 end
37 | if y0<1 then y0=1 end
38 | if x0>bx then x0=bx end
39 | if y0>by then y0=by end
40 | if #t>6 then for i=7,#t do local s=tostring(t[i]) table.insert(holes,{tonumber(string.sub(s,1,#tostring(bx))),tonumber(string.sub(s,#tostring(bx)+1,#s))}) end end
41 | end
42 | ret0,log = ret0==1,log==1
43 | local full=bx*by-#holes -- количество клеток для ходов
44 | local fbx,fby = "%0"..#tostring(bx).."d","%0"..#tostring(by).."d"
45 | local function holes_check(x,y) for _,v in ipairs(holes) do if v[1]==x and v[2]==y then return true end end return false end
46 | local function holes_show()
47 | if #holes==0 then return "no" end
48 | local s="" for _,v in ipairs(holes) do s=s..string_format(fbx,v[1])..string_format(fby,v[2]).."," end
49 | return string.sub(s,1,-2)
50 | end
51 | local function console()
52 | panel.GetUserScreen()
53 | io.write("Board: "..bx.."x"..by..", Start: "..string_format(fbx,x0)..string_format(fby,y0)..", Closed path: "..(ret0 and "yes" or "no")..", Logging: "..(log and "yes" or "no")..", Holes: "..holes_show())
54 | panel.SetUserScreen()
55 | end
56 | local function Msg() far.Message("For a closed path, the number of squares must be even, add"..(#holes==0 and "" or "/remove").." a hole.",title) end
57 | if ret0 and math.fmod(full,2)==1 then
58 | local x,y = math.floor((bx+1)/2),math.floor((by+1)/2) -- центр доски
59 | if x0==x and y0==y -- старт в центре доски?
60 | then if holes_check(bx,by) then Msg() goto ANSWER else table.insert(holes,{bx,by}) console() end
61 | else if holes_check( x, y) then Msg() goto ANSWER else table.insert(holes,{ x, y}) console() end
62 | end
63 | else console()
64 | end
65 | full=bx*by-#holes -- количество клеток для ходов
66 |
67 | local ttime=far.FarClock()
68 | -- {dx,dy} - вектор хода
69 | -- порядок следования векторов в массиве определяет приоритет выбора клетки для хода среди клеток с одинаковым количеством доступных для движения векторов
70 | --local dx=ffi.new("int8_t[8]",{-1,-2,-2,-1, 1, 2, 2, 1})
71 | --local dy=ffi.new("int8_t[8]",{ 2, 1,-1,-2,-2,-1, 1, 2})
72 | --const int8_t dd[8]={-2,-2, 2, 2, 1,-1, 1,-1}; // RBs 1216870
73 | local dd=ffi.new("const int8_t[8]",{-2,-2, 2, 2, 1,-1, 1,-1}) -- должны быть такими же как и в ChessKnight.exe
74 | --local dy=ffi.new("const int8_t[8]",{ 2,-2, 1, 1,-2, 2,-1,-1}) -- должны быть такими же как и в ChessKnight.exe
75 | -- создаём чистую доску, свободная клетка содержит -1, либо вектор хода с неё 0-7, либо дыру 8
76 | local function array(st,...) st=st..string.rep('[$]',#{...}) local array_ct=ffi.typeof(st,...) return array_ct({{-1}}) end
77 | local t00=array("int8_t" ,bx,by) -- слой векторов с дырами
78 | local t01=array("int16_t",bx,by) -- слой нумерации ходов
79 | for _,v in ipairs(holes) do t00[v[1]-1][v[2]-1]=8 end -- расставляем дыры 0 based
80 | local Tree=ffi.new("uint8_t[?][8]",full) -- дерево, содержащее вектора возможных ходов
81 | local tv=ffi.new("uint8_t[?]",full) -- указатель на активный (последний) вектор
82 |
83 | bx,by,x0,y0,full = bx-1,by-1,x0-1,y0-1,full-1 -- align from 1 to 0 based
84 | for x=0,full do tv[x]=0xFF for y=0,7 do Tree[x][y]=0xFF end end
85 |
86 | local fw,rb,ret,full1,v,x2,y2 = 1,0,ret0,full-1 -- счётчики: ходов вперёд, возвратов (откатов)
87 | if ret and math.fmod(full,2)==0 then ret=false end
88 | local t1s,t1v,x,y -- номер текущего хода, последний (текущий) вектор, координаты текущей клетки
89 |
90 | local function init() t1s,t1v,x,y = 0,0,x0,y0 end -- инициализация
91 | init()
92 |
93 | local exename=name
94 | if not log and not ret then exename=exename.."_noRetLog"
95 | elseif not log and ret then exename=exename.."_noLog"
96 | elseif log and not ret then exename=exename.."_noRet"
97 | end
98 | exename=exename..".exe"
99 |
100 | local exe
101 | if win.GetFileAttr(exename) then exe=true print("Use: "..exename)
102 | elseif win.GetFileAttr(name..".exe") then exe=true exename=name..".exe" print("Use: "..exename)
103 | end
104 | if exe then
105 | local args=" "..(bx+1).." "..(by+1).." "..(x0+1).." "..(y0+1).." "..(ret and 1 or 0).." "..(log and 1 or 0)
106 | if #holes>0 then for _,v in ipairs(holes) do args=args.." "..v[1].." "..v[2] end end
107 | local ans=io.popen('"'..exename..args..'"',"rb"):read("*all")
108 | if ans and win.GetFileAttr(temp..txtname) then
109 | local h=io.open(temp..txtname,"rb")
110 | if h then
111 | local i,s = 1,h:read("*all")
112 | status=string_byte(s,i,i) i=i+1
113 | x=string_byte(s,i,i) i=i+1
114 | y=string_byte(s,i,i) i=i+1
115 | t1s=string_byte(s,i+1,i+1)*256+string_byte(s,i,i) t1s=t1s==65535 and -1 or t1s i=i+2
116 | fw=string_byte(s,i+3,i+3)*16777216+string_byte(s,i+2,i+2)*65536+string_byte(s,i+1,i+1)*256+string_byte(s,i,i) i=i+4
117 | rb=string_byte(s,i+3,i+3)*16777216+string_byte(s,i+2,i+2)*65536+string_byte(s,i+1,i+1)*256+string_byte(s,i,i) i=i+4
118 | variants=string_byte(s,i+3,i+3)*16777216+string_byte(s,i+2,i+2)*65536+string_byte(s,i+1,i+1)*256+string_byte(s,i,i) i=i+4
119 | for x=0,bx do for y=0,by do t00[x][y]=string_byte(s,i,i) i=i+1 end end
120 | for x=0,bx do for y=0,by do t01[x][y]=string_byte(s,i+1,i+1)*256+string_byte(s,i,i) i=i+2 end end
121 | for x=0,full do for y=0,7 do Tree[x][y]=string_byte(s,i,i) i=i+1 end end
122 | for x=0,full do tv[x]=string_byte(s,i,i) i=i+1 end
123 | h:close()
124 | goto RESULTS
125 | end
126 | end
127 | end
128 | print("Use: "..name..".lua")
129 |
130 | do
131 | local cx=ffi.new("int8_t[8]",{-1}) -- массив с x координатами клеток 1-го хода (финиша)
132 | local cy=ffi.new("int8_t[8]",{-1}) -- массив с y координатами клеток 1-го хода (финиша)
133 | local ti=ffi.new("uint8_t[8]") -- массив с индексами векторов на клетки, доступные для хода с клетки x,y
134 | local ta=ffi.new("uint8_t[8]") -- массив с количеством векторов у доступных для хода клеток
135 | -- сортируем вектора по убыванию количества векторов у целевых клеток, обеспечивая приоритет обхода клеток с наименьшим количеством входов
136 | -- алгоритм сохраняет очерёдность одинаковых значений, обеспечивая неизменность маршрутов и их конечное количество
137 | local function around(x,y)
138 | local tl=-1
139 | for i=0,7 do
140 | local x1,y1 = x+dd[i],y+dd[7-i]
141 | if x1>=0 and x1<=bx and y1>=0 and y1<=by and t00[x1][y1]<0 then
142 | tl=tl+1
143 | local a=0
144 | for j=0,7 do
145 | local x2,y2 = x1+dd[j],y1+dd[7-j]
146 | if x2>=0 and x2<=bx and y2>=0 and y2<=by and t00[x2][y2]<0 then a=a+1 end
147 | end
148 | ta[tl],ti[tl] = a,i
149 | if tl>0 then
150 | for i1=tl,1,-1 do
151 | local i0=i1-1
152 | if ta[i1]>ta[i0]
153 | then ta[i0],ti[i0],ta[i1],ti[i1] = ta[i1],ti[i1],ta[i0],ti[i0]
154 | else break
155 | end
156 | end
157 | end
158 | end
159 | end
160 | return tl
161 | end
162 |
163 | local cn,cl = 0,around(x,y) -- индекс клетки финиша, количество клеток на расстоянии 1 хода от старта t1s=1
164 | for i=cl,0,-1 do cx[i],cy[i] = x+dd[ti[i]],y+dd[7-ti[i]] end -- массив координат клеток на расстоянии 1 хода от старта t1s=1
165 |
166 | -- logging max board 15x15 - xy stored in 1 byte
167 | local lshift,pB,buf_size,fname,name_out,mode_out,f_out,obuf = bit.lshift
168 | if bx>15 or by>15 then log=false end
169 | if log then
170 | pB,buf_size = 0,0x1000000
171 | fname = win.GetEnv"TEMP"..logname
172 | name_out = win.Utf8ToUtf16(fname).."\0"
173 | mode_out = "\119\0\98\0\0" -- win.Utf8ToUtf16("wb").."\0"
174 | f_out=assert(C._wfopen(ffi.cast("wchar_t*", name_out), ffi.cast("wchar_t*", mode_out)))
175 | if f_out==NULL
176 | then log=false print("Can't create a "..logname)
177 | else obuf = ffi.new("unsigned char[?]",buf_size)
178 | end
179 | end
180 |
181 | ::START::
182 | if log then if pB=0 then
185 | ffi_copy(Tree[t1s],ti,t1v+1) -- записываем вектора в дерево
186 | -- сохраняем указатель на активный (последний) вектор
187 | tv[t1s]=t1v v=Tree[t1s][t1v] x2,y2 = x+dd[v],y+dd[7-v] -- получаем вектор и координаты следующей клетки
188 | if ret and x2==cx[cn] and y2==cy[cn] and t1s=0
212 | tv[t1s]=t1v v=Tree[t1s][t1v] x2,y2 = x+dd[v],y+dd[7-v] -- получаем вектор и координаты следующей клетки
213 | if ret and x2==cx[cn] and y2==cy[cn] then -- вектор указывает на клетку финиша?
214 | t1v=t1v-1 -- перемещаем указатель на предыдущий вектор
215 | if t1v<0 then goto ROLLBACK else tv[t1s]=t1v v=Tree[t1s][t1v] x2,y2 = x+dd[v],y+dd[7-v] end -- больше векторов нет?
216 | end
217 | t00[x][y],t01[x][y] = v,t1s x,y = x2,y2 fw,t1s = fw+1,t1s+1 -- переходим на следующую клетку
218 | goto START -- следующий ход
219 | ::FINISH::
220 | if log then if pB>0 then C.fwrite(obuf,1,pB,f_out) pB=0 end C.fclose(f_out) end -- logging
221 | end
222 |
223 | ::RESULTS::
224 | ttime = math.floor((far.FarClock()-ttime)/1000)/1000
225 | -- Вывод результатов на экран и в %TEMP%\ChessKnight.txt
226 | local function chk(x,y) for i=0,7 do if x+dd[i]==x0 and y+dd[7-i]==y0 then return true end end return false end
227 | bx,by,x0,y0,full = bx+1,by+1,x0+1,y0+1,full+1 -- align from 0 to 1
228 | local s0="Board: "..bx.."x"..by.."\nHoles: "..holes_show().."\nStart: "..string_format(fbx,x0)..string_format(fby,y0).."\nClosed path: "..(ret0 and "yes" or "no").."\nLogging: "..(log and "yes" or "no")
229 | s0=s0.."\n\nSolution: "..(status==1 and "found " or (status==2 and "partially found " or "not found ")).."\nVisited squares: "..(t1s+1).."/"..full.."\nTime: "..ttime.." s\n"
230 | local s1="\nPath: "..string_format(fbx,x0)..string_format(fby,y0)
231 | x2,y2 = x0,y0
232 | local s4,vs = ""
233 | if not variants then vs,variants = true,0 end
234 | for i=0,t1s-1 do
235 | t1v=tv[i] v=Tree[i][t1v]
236 | if vs then variants=variants+t1v+1 end
237 | x2,y2 = x2+dd[v],y2+dd[7-v]
238 | s1=s1.." "..string_format(fbx,x2)..string_format(fby,y2)
239 | local s=string_format(" %02X %02X",i,tv[i]) for j=0,7 do s=s..string_format(" %02X",Tree[i][j]) end s4=s4..s.."\n"
240 | end
241 | if t1s>=0 then local s=string_format(" %02X %02X",t1s,tv[t1s]) for j=0,7 do s=s..string_format(" %02X",Tree[t1s][j]) end s4=s4..s.."\n" end
242 | t1s,s1 = t1s+1,s1.."\n"
243 | local s2,sf = "\n",#tostring(full)
244 | for y=by-1,0,-1 do for x=0,bx-1 do local dd=t01[x][y]+1 s2=s2..string_format((dd==1 or dd==t1s) and "[%"..sf.."d]" or " %"..sf.."d ",dd) end s2=s2.."\n" end
245 | local s3="\n Moves: "..(fw+rb).."\n Forward: "..fw.."\nRollback: "..rb.."\nVariants: "..variants.."\n Status: "..status
246 | local h=io.open(temp..txtname,"wb") h:write(title.."\n\n"..s0..s1..s2..s3..(s4~="" and "\n\n"..s4 or "")) h:close()
247 |
248 | local MessageX=require"MessageX"
249 |
250 | local function fine(x)
251 | s0=status==1 and string.gsub(s0," found ","<#a2>%1<#rr>") or (status==2 and string.gsub(s0," partially found ","<#b3>%1<#rr>") or string.gsub(s0," not found ","<#c4>%1<#rr>"))
252 | if x then
253 | s2=string.gsub(s2,"%[(.-)%]","<#f1> %1 <#rr>")
254 | s2=string.gsub(s2,string.rep(" ",sf).."0 ","<#ec>%1<#rr>")
255 | end
256 | end
257 |
258 | local rr=far.AdvControl"ACTL_GETFARRECT"
259 | local Width,Height = rr.Right-rr.Left-3,rr.Bottom-rr.Top-17
260 |
261 | local hs1,ws2 = math.ceil((#s1-1)/Width)+by+1<=Height,(#s2-1)/by-1<=Width
262 | if hs1 and ws2 then if MessageX then fine(1) MessageX(s0..s1..s2..s3,title,nil,"c") else far.Message(s0..s1..s2..s3,title) end
263 | elseif by<=Height and ws2 then if MessageX then fine(1) MessageX(s0..s2..s3,title,nil,"c") else far.Message(s0..s2..s3,title) end
264 | else if MessageX then fine() MessageX(s0..s3,title,nil,"c") else far.Message(s0..s3,title) end
265 | end
266 |
--------------------------------------------------------------------------------
/Dialog.Maximize.moon:
--------------------------------------------------------------------------------
1 | -- Dialog.Maximize.moon
2 | -- v1.1.11.6
3 | -- Resizing dialogs, aligning the positions of dialog elements
4 | -- Keys: F2 in dialogs or CtrlAltRight or CtrlAltLeft
5 | -- Url: https://forum.farmanager.com/viewtopic.php?p=148024#p148024
6 | -- Based on https://forum.farmanager.com/viewtopic.php?p=146816#p146816
7 |
8 | XScale=0 -- scale 0<=XScale<=1 for all dialogs: 0 = original width, 1 = full width, 0.5 = (full - original) / 2
9 | XStep=0.25 -- width change step
10 | DX=4 -- indent
11 |
12 | XScale=_G.XScale or XScale
13 | _XScale={id:"",xs:XScale,cw:nil,ch:nil,dw:nil,dh:nil,dl:nil,dt:nil,dr:nil,db:nil,pl:nil,pr:nil} -- original width
14 |
15 | far=far
16 | F,AdvControl,Dialog,GetDlgItem,Guids,SetDlgItem,SendDlgMessage,InputRecordToName = far.Flags,far.AdvControl,far.Dialog,far.GetDlgItem,far.Guids,far.SetDlgItem,far.SendDlgMessage,far.InputRecordToName
17 |
18 | math=math
19 | abs,ceil,floor,fmod,modf = math.abs,math.ceil,math.floor,math.fmod,math.modf
20 |
21 | string=string
22 | match = string.match
23 |
24 | win=win
25 | Uuid=win.Uuid
26 |
27 | build=({AdvControl('ACTL_GETFARMANAGERVERSION',true)})[4]
28 | d=build<6061 and 1 or 0 -- no separate Fuzzy Search yet?
29 |
30 | Guid_DlgXScale=Uuid"D37E1039-B69B-4C63-B750-CBA4B3A7727C"
31 |
32 | transform=
33 | --[Guid_DlgXScale]: {0,"1.16.A27",3.0} -- Set Dlg.XScale
34 | [Uuid Guids.CopyFilesId ]: {1,3,11} -- Shell: Copy
35 | [Uuid Guids.CopyCurrentOnlyFileId ]: {1,3,11} -- Shell: Copy current
36 | [Uuid Guids.MoveFilesId ]: {1,3,11} -- Shell: Move
37 | [Uuid Guids.MoveCurrentOnlyFileId ]: {1,3,11} -- Shell: Move current
38 | [Uuid Guids.MakeFolderId ]: {1,3,6,8} -- Shell: mkdir
39 | [Uuid Guids.HardSymLinkId ]: {1,3,11} -- Shell: Link
40 | [Uuid Guids.FileOpenCreateId ]: {1,3,6} -- Shell: New
41 | [Uuid Guids.FindFileId ]: build<6082 and {1,3,6,7,9,16.1-d,17.1-d,18.1-d,19.1-d,21.1-d,23.2-d,24.1-d} or {1,3,6,11,17.1,18.1,19.1,20.1,22.1,24.2,25.1} -- Find File
42 | [Uuid Guids.EditorSearchId ]: build<6096 and {1,2.3,3.3,5,7,12.1,13.1} or {1,4.3,5.3,7,15.1,16.1} -- Editor Search
43 | [Uuid Guids.EditorReplaceId ]: build<6096 and {1,2.3,3.3,5,7,12.1,13.1,14.1} or {1,4.3,5.3,7,10,15.1,16.1,17.1,18.5} -- Editor Replace
44 | [Uuid Guids.FileSaveAsId ]: {1,3,6} -- File Save As
45 | [Uuid Guids.PluginInformationId ]: {1,3,5,7,9,11,13,15,17}
46 | [Uuid Guids.DescribeFileId ]: {1,3} -- Describe File
47 | [Uuid Guids.ApplyCommandId ]: {1,3} -- Shell: Apply command (CtrlG)
48 | [Uuid Guids.EditUserMenuId ]: {1,5,8,9,10,11,12,13,14,15,16,17}
49 | [Uuid Guids.FileAssocModifyId ]: {1,3,5,8,10,12,14,16,18}
50 | [Uuid Guids.ViewerSearchId ]: build<6078 and {1,3,5,7,8.1,9.1,10.1,11.1} or build<6099 and {1,5,6,11.1,12.1} or {1,7,8,15.1,16.1} -- Viewer Search
51 | [Uuid Guids.SelectDialogId ]: {1,2} -- Select Gray+
52 | [Uuid Guids.UnSelectDialogId ]: {1,2} -- Select Gray-
53 | --[Uuid Guids.FileAttrDlgId ]: {1,37} -- File Attributes
54 | -- ArcLite
55 | [Uuid"08A1229B-AD54-451B-8B53-6D5FD35BCFAA"]: {1,15,19,27,31} -- Configuration
56 | [Uuid"CD57D7FA-552C-4E31-8FA8-73D9704F0666"]: {1,10,23,"43.10.45"} -- Create archive
57 | [Uuid"97877FD0-78E6-4169-B4FB-D76746249F4D"]: {1,3,"8.10.11","9.16.8.15","17.9.0.14"} -- Extract files
58 | [Uuid"0DCE48E5-B205-44A0-B8BF-96B28E2FD3B3"]: {1,9,20,22,33,35,37} -- SFX options
59 | [Uuid"2C4EFD54-A419-47E5-99B6-C9FD2D386AEC"]: {1,3,5} -- PostMacro
60 | -- RESearch
61 | [Uuid"E506EA8F-484F-7261-FEED-9B10267753E9"]: {1,4,6,7.3,26.3} -- Shell: Search
62 | [Uuid"9736CFC1-9F3A-D4F9-02A4-566717182E8B"]: {1,4,6,8,9.3,10.3,"33.10.32",37.3} -- Shell: Replace
63 | [Uuid"3D95792C-E25C-1CE1-EC09-DC409184EC7A"]: {1,4,6,7.3,24,35.3} -- Shell: Grep
64 | [Uuid"AA3CA1C7-062A-67A8-3A73-80B5E9394046"]: {1,5} -- Shell: SelectFiles,UnselectFiles,FlipSelection
65 | [Uuid"0AE75CCC-5872-74A7-3561-BBA1991C0395"]: {1,4,6,8,28.3} -- Shell: RenameFiles
66 | [Uuid"622AAD65-B7CA-7670-6622-A267028B1A06"]: {1,5,7,16.3} -- Shell: RenameSelectedFiles
67 | [Uuid"FF1E3A24-0B7A-0149-EFA2-1ED2309F8410"]: {1,3,4.3,14.3,18.3} -- Viewer,Editor: Search (hack: [Presets] is 14 in V, 18 in E)
68 | [Uuid"411BF77E-5743-D87A-A8E7-0EFDF0C71D79"]: {1,3,5,6.3,7.3,25.3} -- Editor: Replace
69 | [Uuid"6CFCADF6-0935-3160-37C3-806484410AB7"]: {1} -- Editor: Replace Question Dialog
70 | [Uuid"3A6225FC-AD65-75B1-2643-5158B78D6BC4"]: {1,3,4.3,14.3} -- Editor: Filter
71 | [Uuid"6938029A-B71F-09EE-D09D-9982EE2B40BC"]: {1,3,4.3,15.3} -- Editor: Repeat
72 | [Uuid"DCDDDA35-A319-1B82-8410-36C04A1390B0"]: {1,3,5,10.3} -- Editor: Transliterate
73 | -- LFSearch/Shell
74 | --[Uuid"3CD8A0BB-8583-4769-BBBC-5B6667D13EF9"]: {1,3,5,6.3} -- Shell/Find
75 | [Uuid"3CD8A0BB-8583-4769-BBBC-5B6667D13EF9"]: {1,3,5} -- Shell/Find
76 | --[Uuid"F7118D4A-FBC3-482E-A462-0167DF7CC346"]: {1,3,5,7,8.3,9.3,10.4,31.2,32.1,33.5} -- Shell/Replace
77 | [Uuid"F7118D4A-FBC3-482E-A462-0167DF7CC346"]: {1,3,5,7,8.4,29.2,30.5,31.5} -- Shell/Replace
78 | --[Uuid"74D7F486-487D-40D0-9B25-B2BB06171D86"]: {1,3,5,7,8.3,9.3} -- Shell/Grep
79 | [Uuid"74D7F486-487D-40D0-9B25-B2BB06171D86"]: {1,3,5,7} -- Shell/Grep
80 | [Uuid"AF8D7072-FF17-4407-9AF4-7323273BA899"]: {1,3,11,13,14.4,16.4,20.2,21.5,22.5,25,27} -- Shell/Rename
81 | -- LFSearch/Editor
82 | --[Uuid"0B81C198-3E20-4339-A762-FFCBBC0C549C"]: {1,3,4.3,7.1,"8.12.F2.2.13",10.1,14.4,15.4,"16.6.1","19.10.20",25,27.2,28.1,29.5} -- Editor/Find
83 | [Uuid"0B81C198-3E20-4339-A762-FFCBBC0C549C"]: {1,3,13.4,14.4,"15.6.1",24,26.2,27.5,28.5} -- Editor/Find
84 | --[Uuid"FE62AEB9-E0A1-4ED3-8614-D146356F86FF"]: {1,3,5,6.3,7.3,8.4,10.4,"14.10.9","15.16.9.11","17.10.9","20.12.3.1","21.10.20","22.10.20","23.6.1",32,34.2,35.5,36.5} -- Editor/Replace
85 | [Uuid"FE62AEB9-E0A1-4ED3-8614-D146356F86FF"]: {1,3,5,6.4,8.4,19.4,20.4,"21.6.1",30,32.2,33.5,34.5} -- Editor/Replace
86 | [Uuid"87ED8B17-E2B2-47D0-896D-E2956F396F1A"]: {1,3,5,6.4,19.2,20.5,21.5} -- Editor/Multi-Line Replace
87 | -- Editor Find
88 | [Uuid"A0562FC4-25FA-48DC-BA5E-48EFA639865F"]: {1,2.3,4,10.1} -- Find
89 | [Uuid"070544C7-E2F6-4E7B-B348-7583685B5647"]: {1,2.3,4,6,12.1,13.1} -- Replace
90 | -- Calculator
91 | [Uuid"E45555AE-6499-443C-AA04-12A1AADAB989"]: {1,3,10,11,12,13,14}
92 | -- LiveFileSearch
93 | [Uuid"6A69A5AF-FC3F-4B7A-9A3C-6047B7CBA242"]: {1,5,"8.12.2.1","10.12.2.1",11.1,12.1,13.1,14.1,15.1}
94 | -- AudioPlayer
95 | --[Uuid"9C3A61FC-F349-48E8-9B78-DAEBD821694B"]: {1,2,"3.6.0",4.1,5.3,"6.6.0",7.2,8.3,9.3,10.5,12.1,13.3,14} -- don't support width change yet
96 | -- Macroses:
97 | [Uuid"5B40F3FF-6593-48D2-8F78-4A32C8C36BCA"]: {1,5,12,14} -- Panel.CustomSortByName.lua
98 |
99 |
100 | re0,re1,re2,re3,re4,re5 = "^(%d+)%.(%d+)%.(.+)$","[%-%+]?%d+","([%-%+]?%d+)%.([%-%+]?%d+)","([F]?)(%d)%.(%d)%.([%-%+]?%d+)","([F]?)(%d)%.(%d)","([%-%+]?%d+)%.([%-%+]?%d+)%.([%-%+]?%d+)%.([%-%+]?%d+)"
101 |
102 | ConsoleSize=->
103 | rr=AdvControl"ACTL_GETFARRECT"
104 | rr.Right-rr.Left+1,rr.Bottom-rr.Top+1
105 |
106 | _XScale.cw,_XScale.ch = ConsoleSize!
107 |
108 | Proc=(id,hDlg)->
109 | if id~=_XScale.id
110 | _XScale.id=id
111 | if not _XScale[id]
112 | _XScale[id]={}
113 | {Left:_XScale[id].dl,Top:_XScale[id].dt,Right:_XScale[id].dr,Bottom:_XScale[id].db}=SendDlgMessage hDlg,F.DM_GETDLGRECT
114 | _XScale[id].dw=_XScale[id].dr-_XScale[id].dl+1
115 | _XScale[id].dh=_XScale[id].db-_XScale[id].dt+1
116 | _XScale[id].pl=(GetDlgItem hDlg,1)[2]+2
117 | _XScale[id].pr=_XScale[id].dw-_XScale[id].pl-1
118 | idx=0
119 | while true
120 | idx+=1
121 | item=GetDlgItem hDlg,idx
122 | if item
123 | _XScale[id][idx]={}
124 | _XScale[id][idx][2]=item[2]
125 | _XScale[id][idx][3]=item[3]
126 | _XScale[id][idx][4]=item[4]
127 | _XScale[id][idx][5]=item[5]
128 | else
129 | break
130 | cw,ch = ConsoleSize!
131 | if cw~=_XScale.cw or ch~=_XScale.ch
132 | _XScale.cw,_XScale.ch = cw,ch
133 | dh,pl = _XScale[id].dh,_XScale[id].pl
134 | df=cw-DX-_XScale[id].dw
135 | diff=floor((_XScale.xs*df+1)/2)*2 -- even value
136 | dw=_XScale[id].dw+diff
137 | pr=dw-pl-1
138 | SendDlgMessage hDlg,F.DM_ENABLEREDRAW,0,0
139 | SendDlgMessage hDlg,F.DM_RESIZEDIALOG,0,{X:dw,Y:dh}
140 | for ii in *transform[id]
141 | local idx,opt,ref
142 | if "number"==type ii
143 | continue if ii<1
144 | idx,opt = modf ii
145 | opt=floor opt*10+0.5
146 | else
147 | idx,opt,ref = match ii,re0
148 | idx=tonumber idx
149 | opt=tonumber opt
150 | item=GetDlgItem hDlg,idx
151 | if item -- prevent error message for out-of-range index (see "hack" above)
152 | item[2]=_XScale[id][idx][2]
153 | item[3]=_XScale[id][idx][3]
154 | item[4]=_XScale[id][idx][4]
155 | item[5]=_XScale[id][idx][5]
156 | NOTDITEXT=not (item[1]==F.DI_TEXT and item[4]==0)
157 | switch opt
158 | when 0 -- Stretch full
159 | if idx==1 and (item[1]==F.DI_DOUBLEBOX or item[1]==F.DI_SINGLEBOX)
160 | item[4]=pr+2
161 | else
162 | if item[4]==item[2]
163 | item[2]+=diff
164 | if NOTDITEXT
165 | item[4]+=diff
166 | when 1 -- Move half
167 | if NOTDITEXT and item[4]==item[2]
168 | item[4]+=diff/2
169 | item[2]+=diff/2
170 | when 2 -- Stretch half
171 | if item[4]==item[2]
172 | item[2]+=diff/2
173 | if NOTDITEXT
174 | item[4]+=diff/2
175 | when 3 -- Move full
176 | if NOTDITEXT and item[4]==item[2]
177 | item[4]+=diff
178 | item[2]+=diff
179 | when 4 -- Move left
180 | item[2]=pl
181 | when 5 -- Move half & Stretch full
182 | if NOTDITEXT
183 | if item[4]==item[2]
184 | item[4]+=diff/2
185 | if diff>=0
186 | item[4]+=diff
187 | item[2]+=diff/2
188 | when 6 -- Move relative by X
189 | x=tonumber match ref,re1
190 | item[2]+=x
191 | if NOTDITEXT
192 | item[4]+=x
193 | when 7 -- Move relative by Y
194 | y=tonumber match ref,re1
195 | item[3]+=y
196 | item[5]+=y
197 | --when 8 -- MoveX full
198 | -- item[2]+=diff+item[2]-item[4]
199 | -- item[4]+=diff
200 | when 9 -- Move & Size relative by X1 & X2
201 | x1,x2 = match ref,re2
202 | item[2]+=tonumber x1
203 | if NOTDITEXT
204 | item[4]+=tonumber x2
205 | when 10 -- Align to ref.X
206 | ref=tonumber ref
207 | t=_XScale[id][ref]
208 | if NOTDITEXT
209 | item[4]=item[4]+t[2]-item[2]
210 | item[2]=t[2]
211 | when 11 -- Align to ref.Y
212 | ref=tonumber ref
213 | t=_XScale[id][ref]
214 | item[5]=item[5]+t[3]-item[3]
215 | item[3]=t[3]
216 | when 12 -- Move & Stretch: (colons quantity).(colon number).(dx)
217 | m,q,n,x = match ref,re3
218 | if not q
219 | m,q,n = match ref,re4
220 | x=0
221 | wc=(dw-pl*2-1)/tonumber q
222 | n=tonumber n
223 | w=item[4]-item[2]+1
224 | if w>wc
225 | w=wc
226 | x=tonumber x
227 | item[2]=wc*(n-1)+pl+x
228 | if m=="F"
229 | item[4]=item[2]+w-1
230 | else
231 | item[4]=item[2]+wc-1
232 | when 13 -- Free Move & Stretch Relative
233 | x1,x2,y1,y2 = match ref,re5
234 | item[2]+=tonumber x1
235 | item[3]+=tonumber y1
236 | if NOTDITEXT
237 | item[4]+=tonumber x2
238 | item[5]+=tonumber y2
239 | when 14 -- Free Move & Stretch Absolute
240 | x1,x2,y1,y2 = match ref,re5
241 | item[2]=tonumber x1
242 | item[3]=tonumber y1
243 | if NOTDITEXT
244 | item[4]=tonumber x2
245 | item[5]=tonumber y2
246 | when 15 -- Set text
247 | item[10]=ref
248 | when 16 -- Align to ref.X + offset
249 | x1,x2 = match ref,re2
250 | x1=tonumber x1
251 | x2=tonumber x2
252 | t=_XScale[id][x1]
253 | if NOTDITEXT
254 | item[4]=item[4]+t[2]-item[2]+x2
255 | item[2]=t[2]+x2
256 | if idx==1
257 | if item[2]pr+2
260 | item[4]=pr+2
261 | else
262 | if item[2]pr
265 | item[4]=pr
266 | if item[1]==F.DI_EDIT or item[1]==F.DI_FIXEDIT
267 | f=SendDlgMessage hDlg,F.DM_EDITUNCHANGEDFLAG,idx,-1
268 | SetDlgItem hDlg,idx,item
269 | SendDlgMessage hDlg,F.DM_EDITUNCHANGEDFLAG,idx,f
270 | else
271 | SetDlgItem hDlg,idx,item
272 | SendDlgMessage hDlg,F.DM_MOVEDIALOG,1,{X:(cw-dw)/2,Y:(ch-dh)/2}
273 | SendDlgMessage hDlg,F.DM_ENABLEREDRAW,1,0
274 |
275 | XItems={
276 | {F.DI_DOUBLEBOX, 0,0,19,2,0, 0,0, 0, "XScale"}
277 | {F.DI_TEXT, 2,1, 9,1,0, 0,0, 0,"0<=X<=1:"}
278 | {F.DI_EDIT, 11,1,17,1,0,"XScale",0, 0, ""}
279 | }
280 |
281 | XDlgProc=(hDlg,Msg,Param1,Param2)->
282 | if Msg==F.DN_INITDIALOG
283 | SendDlgMessage hDlg,F.DM_SETTEXT,3,tostring _XScale.xs
284 | elseif Msg==F.DN_CLOSE and Param1==3
285 | res=tonumber SendDlgMessage hDlg,F.DM_GETTEXT,Param1
286 | if res
287 | if res<0
288 | res=0
289 | elseif res>1
290 | res=1
291 | _XScale.xs=res
292 |
293 | exec=(hDlg)->
294 | id=SendDlgMessage hDlg,F.DM_GETDIALOGINFO
295 | if id and transform[id.Id]
296 | Proc id.Id,hDlg
297 |
298 | Event
299 | group:"DialogEvent"
300 | description:"Dialog Transform"
301 | action:(event,param)->
302 | if event==F.DE_DLGPROCINIT and (param.Msg==F.DN_INITDIALOG or param.Msg==F.DN_RESIZECONSOLE)
303 | exec param.hDlg
304 | elseif event==F.DE_DEFDLGPROCINIT and param.Msg==F.DN_CONTROLINPUT
305 | if param.Param2.EventType==F.KEY_EVENT
306 | name=InputRecordToName param.Param2
307 | if name=="F2"
308 | res=Dialog Guid_DlgXScale,-1,-1,20,3,nil,XItems,F.FDLG_SMALLDIALOG+F.FDLG_WARNING,XDlgProc
309 | if res==3
310 | exec param.hDlg
311 | elseif name=="CtrlAltRight"
312 | if _XScale.xs<1
313 | _XScale.xs+=XStep
314 | if _XScale.xs>1
315 | _XScale.xs=1
316 | exec param.hDlg
317 | elseif name=="CtrlAltLeft"
318 | if _XScale.xs>0
319 | _XScale.xs-=XStep
320 | if _XScale.xs<0
321 | _XScale.xs=0
322 | exec param.hDlg
323 | false
324 |
--------------------------------------------------------------------------------
/Panel.SelectDuplicatesFileNames.lua:
--------------------------------------------------------------------------------
1 | -- Panel.SelectDuplicatesFileNames.lua
2 | -- v1.3.5.0
3 | -- Select Duplicates File Names in Branch panel with complex logic
4 | -- For the correct result, set default sorting system settings:
5 | -- [ ] Treat digits as numbers
6 | -- [ ] Case sensitive
7 | -- Column **<R>** shows the Result of the comparison
8 | -- The Integrity Checker plugin is required to calculate Hashes
9 | -- 
10 | -- Keys: launch from Macro Browser alt.
11 | -- Tip: In the dialog all elements have prompts, press F1 for help
12 |
13 | if not (bit and jit) then return end
14 |
15 | local bit = bit
16 | local band,bnot,bor = bit.band,bit.bnot,bit.bor
17 |
18 | local F = far.Flags
19 | local guid = "0CCE7734-1558-46AF-8D31-56344AA9C049"
20 | local uGuid = win.Uuid(guid)
21 | local MenuGuid1 = "B8B6E1DA-4221-47D2-AB2E-9EC67D0DC1E3"
22 | local MenuGuid2 = "C323FBCF-6803-4F2C-B8B4-E576E7F125DC"
23 | local IntChecker = "E186306E-3B0D-48C1-9668-ED7CF64C0E65"
24 |
25 | -- Settings --------------------------------------------------------------------
26 | local PanelMode,Description,Indicator = F.SM_USER+113,"PSDFN: Select Duplicates FileName","!?"
27 | local Key = "CtrlShiftF3"
28 | local repfile = "PSDFN-Report.txt"
29 | --------------------------------------------------------------------------------
30 |
31 | local ffi = require"ffi"
32 | local C = ffi.C
33 | local Flags = C.SORT_STRINGSORT
34 | local NULL = ffi.cast("void*",0)
35 | local PANEL_ACTIVE = ffi.cast("HANDLE",-1)
36 | local pBL0,pBL1 = ffi.cast("BOOL*",0),ffi.cast("BOOL*",1)
37 | local BS,ts = string.byte("\\"),{nil,true,9999,true,false,2,2,2,false,true,false}
38 | local tHash = {}
39 | local temp = win.GetEnv("Temp")
40 | repfile = temp.."\\"..repfile
41 | local freport = repfile
42 | local Duplicates = {}
43 |
44 | ffi.cdef[[ wchar_t* wcsrchr(const wchar_t*, wchar_t); ]]
45 |
46 | local c0col = {
47 | GetContentFields = function(ColNames) for i,v in ipairs(ColNames) do if v=="R" then return true end end end;
48 | GetContentData = function(FilePath,ColNames)
49 | local data={}
50 | for i,v in ipairs(ColNames) do if v=="R" then data[i] = Duplicates[FilePath] or "" end end
51 | return next(data) and data
52 | end
53 | }
54 | if not Far then for k,v in pairs(c0col) do export[k]=v end elseif ContentColumns then ContentColumns(c0col) end
55 |
56 | local Items = {
57 | --[[01]] {F.DI_DOUBLEBOX, 3, 1, 57, 12, 0, 0, 0, 0, Description..". Help: F1"},
58 | --[[02]] {F.DI_CHECKBOX, 5, 2, 26, 2, 0, 0, 0, 0, "Num&ber of symbols"},
59 | --[[03]] {F.DI_EDIT, 27, 2, 32, 2, 0, 0, 0, 0, ""},
60 | --[[04]] {F.DI_CHECKBOX, 5, 3, 16, 3, 0, 0, 0, 0, "Ignore &case"},
61 | --[[05]] {F.DI_CHECKBOX, 5, 4, 43, 4, 0, 0, 0, 0, "Ignore Full &Duplicates of FileName"},
62 | --[[06]] {F.DI_CHECKBOX, 5, 5, 21, 5, 0, 0, 0, F.DIF_3STATE, "&Sizes of FD:"},
63 | --[[07]] {F.DI_CHECKBOX, 5, 6, 22, 6, 0, 0, 0, F.DIF_3STATE, "&Hashes of FD:"},
64 | --[[08]] {F.DI_CHECKBOX, 5, 7, 26, 7, 0, 0, 0, F.DIF_3STATE, "&Attributes of FD:"},
65 | --[[09]] {F.DI_CHECKBOX, 5, 8, 47, 8, 0, 0, 0, 0, "Accuracy (&Two-pass method for <> only)"},
66 | --[[10]] {F.DI_CHECKBOX, 5, 9, 37, 9, 0, 0, 0, 0, "Cl&ear selection for begin"},
67 | --[[11]] {F.DI_CHECKBOX, 5,11, 15, 11, 0, 0, 0, 0, "Re&port"},
68 | --[[12]] {F.DI_TEXT, -1,10, 0, 0, 0, 0, 0, F.DIF_SEPARATOR,""},
69 | --[[13]] {F.DI_BUTTON, 0,11, 0, 0, 0, 0, 0, F.DIF_DEFAULTBUTTON+F.DIF_CENTERGROUP,"&Ok"},
70 | --[[14]] {F.DI_BUTTON, 0,11, 0, 0, 0, 0, 0, F.DIF_CENTERGROUP,"Ca&ncel"}
71 | }
72 |
73 | local function StartAndLenW(name)
74 | local ptr = C.wcsrchr(name,BS)
75 | name = ptr==nil and name or ptr+1
76 | local len = tonumber(C.wcslen(name))
77 | if ts[2] and ts[3]<0 and -ts[3]0 and ts[3]hs2 then res=1
114 | end
115 | if res~=0 then return res end
116 | end
117 | if ts[8]~=2 then
118 | local fa1=tonumber(p1.FileAttributes)
119 | local fa2=tonumber(p2.FileAttributes)
120 | res=fa1-fa2
121 | end
122 | return res
123 | end
124 |
125 | local tts={}
126 |
127 | local function DlgProc(hDlg,Msg,Param1,Param2)
128 | if Msg==F.DN_INITDIALOG then
129 | for i=2,#Items-3 do tts[i]=ts[i] end
130 | hDlg:send(F.DM_SETTEXT,3,tts[3])
131 | hDlg:send(F.DM_SETCHECK,2,tts[2] and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED)
132 | hDlg:send(F.DM_SETCHECK,4,tts[4] and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED)
133 | hDlg:send(F.DM_SETCHECK,5,tts[5] and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED)
134 | hDlg:send(F.DM_SETCHECK,6,tts[6]==0 and F.BSTATE_UNCHECKED or tts[6]==1 and F.BSTATE_CHECKED or tts[6]==2 and F.BSTATE_3STATE)
135 | hDlg:send(F.DM_SETTEXT,6,"&Sizes of FD: "..(tts[6]==0 and "<>" or tts[6]==1 and "==" or "--"))
136 | hDlg:send(F.DM_SETCHECK,7,tts[7]==0 and F.BSTATE_UNCHECKED or tts[7]==1 and F.BSTATE_CHECKED or tts[7]==2 and F.BSTATE_3STATE)
137 | hDlg:send(F.DM_SETTEXT,7,"&Hashes of FD: "..(tts[7]==0 and "<>" or tts[7]==1 and "==" or "--"))
138 | hDlg:send(F.DM_SETCHECK,8,tts[8]==0 and F.BSTATE_UNCHECKED or tts[8]==1 and F.BSTATE_CHECKED or tts[8]==2 and F.BSTATE_3STATE)
139 | hDlg:send(F.DM_SETTEXT,8,"&Attributes of FD: "..(tts[8]==0 and "<>" or tts[8]==1 and "==" or "--"))
140 | hDlg:send(F.DM_SETCHECK,9,tts[9] and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED)
141 | hDlg:send(F.DM_SETCHECK,10,tts[10] and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED)
142 | hDlg:send(F.DM_SETCHECK,11,tts[11] and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED)
143 | elseif Msg==F.DN_BTNCLICK and (Param1==2 or Param1==4 or Param1==5 or Param1==9 or Param1==10 or Param1==11) then
144 | tts[Param1] = Param2~=0
145 | elseif Msg==F.DN_BTNCLICK and (Param1==6 or Param1==7 or Param1==8) then
146 | tts[Param1] = Param2
147 | hDlg:send(F.DM_SETTEXT,Param1,(Param1==6 and "&Sizes of FD: " or (Param1==7 and "&Hashes of FD: " or "&Attributes of FD: "))..(Param2==0 and "<>" or (Param2==1 and "==" or "--")))
148 | tts[9]=tts[6]==0 or tts[7]==0 or tts[8]==0
149 | hDlg:send(F.DM_SETCHECK,9,tts[9] and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED)
150 | elseif Msg==F.DN_EDITCHANGE and Param1==3 then -- Number symbols
151 | tts[3] = tonumber(hDlg:send(F.DM_GETTEXT,3)) or tts[3]
152 | else
153 | return
154 | end
155 | return true
156 | end
157 |
158 | Panel.LoadCustomSortMode(PanelMode,{Description=Description;Indicator=Indicator;Compare=Compare})
159 |
160 | Macro {
161 | description=Description.." in Branch panel"; area="Shell Menu"; key = Key.." Enter MsLClick"; name="PSDFN";
162 | condition = function(key) return Area.Shell and key==Key or Area.Menu and (Menu.Id==MenuGuid1 or Menu.Id==MenuGuid2) and Menu.Value:find(Description) and (key=="Enter" or key=="MsLClick") end;
163 | action=function()
164 | if Area.Menu then Keys("Esc") end
165 | if far.Dialog(uGuid,-1,-1,Items[1][4]+4,Items[1][5]+2,nil,Items,nil,DlgProc)==#Items-1 then
166 | local t0=far.FarClock()
167 | for i=2,#Items-3 do ts[i]=tts[i] end
168 | Flags = ts[4] and bor(Flags,C.NORM_IGNORECASE) or band(Flags,bnot(C.NORM_IGNORECASE))
169 | --local PInfo=panel.GetPanelInfo(nil,1)
170 | local PInfo=ffi.new("struct PanelInfo")
171 | PInfo.StructSize=ffi.sizeof(PInfo)
172 | local pc=ffi.cast("struct PluginStartupInfo*",far.CPluginStartupInfo()).PanelControl
173 | if pc(PANEL_ACTIVE,"FCTL_GETPANELINFO",0,PInfo)==1 then
174 | local pin,pif = tonumber(PInfo.ItemsNumber),tonumber(PInfo.Flags)
175 | if pin>1 then
176 | if ts[10] then
177 | local psin=tonumber(PInfo.SelectedItemsNumber)
178 | if psin>0 then
179 | pc(PANEL_ACTIVE,"FCTL_BEGINSELECTION",0,NULL)
180 | for i=0,psin-1 do pc(PANEL_ACTIVE,"FCTL_CLEARSELECTION",i,NULL) end
181 | pc(PANEL_ACTIVE,"FCTL_ENDSELECTION",0,NULL)
182 | end
183 | end
184 | if band(pif,F.PFLAGS_SELECTEDFIRST)>0 then Keys("ShiftF12") end
185 | if band(pif,F.PFLAGS_REVERSESORTORDER)==0 then pc(PANEL_ACTIVE,"FCTL_SETSORTORDER",1,NULL) end
186 | Panel.LoadCustomSortMode(PanelMode,{Description=Description;Indicator=Indicator;Compare=Compare})
187 | Panel.SetCustomSortMode(PanelMode,0)
188 | local st0,ln0,st1,ln1,st2,ln2,st3,ln3,sz0,sz1,fa0,fa1,hs0,hs1,fp0,fp1
189 | local ppi = ffi.new("struct FarGetPluginPanelItem")
190 | ppi.StructSize = ffi.sizeof("struct FarGetPluginPanelItem")
191 | local function PGPI(i)
192 | ppi.Size = pc(PANEL_ACTIVE,"FCTL_GETPANELITEM",i,NULL)
193 | if ppi.Size~=0 then
194 | local buf = ffi.new("char[?]",ppi.Size)
195 | ppi.Item = ffi.cast("struct PluginPanelItem*",buf)
196 | pc(PANEL_ACTIVE,"FCTL_GETPANELITEM",i,ppi)
197 | if ts[2] then st1,ln1,st3,ln3=StartAndLenW(ffi.cast("const unsigned short*",ppi.Item.FileName)) end
198 | sz1=tonumber(ppi.Item.FileSize)
199 | if ts[7]~=2 then
200 | fp1=win.Utf16ToUtf8(ffi.string(ppi.Item.FileName,C.wcslen(ppi.Item.FileName)*2))
201 | hs1=GetHash(fp1)
202 | end
203 | fa1=tonumber(ppi.Item.FileAttributes)
204 | end
205 | end
206 | Duplicates={}
207 | local count,mark,sel,prefix = 0,'0'
208 | pc(PANEL_ACTIVE,"FCTL_BEGINSELECTION",0,NULL)
209 | PGPI(0)
210 | if ts[7]~=2 then
211 | local pre0='\\\\?\\'
212 | local pre1=fp1:sub(1,4)==pre0
213 | local pre2=fp1:sub(2,3)==':\\'
214 | prefix=pre1 and '' or (pre2 and pre0 or pre0..APanel.Path..'\\')
215 | end
216 | for i=1,pin-1 do
217 | st0,ln0,st2,ln2,sz0,fa0,hs0,fp0 = st1,ln1,st3,ln3,sz1,fa1,hs1,fp1
218 | PGPI(i)
219 | if (not ts[2] or ts[2] and C.CompareStringW(C.LOCALE_USER_DEFAULT,Flags,st0,ln0,st1,ln1)==2)
220 | and ((ts[6]==0 and sz0~=sz1 or ts[6]==1 and sz0==sz1 or ts[6]==2)
221 | and (ts[7]==0 and hs0~=hs1 or ts[7]==1 and hs0==hs1 or ts[7]==2)
222 | and (ts[8]==0 and fa0~=fa1 or ts[8]==1 and fa0==fa1 or ts[8]==2))
223 | then
224 | if band(fa0,0x10)==0 then pc(PANEL_ACTIVE,"FCTL_SETSELECTION",i-1,pBL1) if ts[7]~=2 then Duplicates[prefix..fp0]=mark end end
225 | if band(fa1,0x10)==0 then pc(PANEL_ACTIVE,"FCTL_SETSELECTION",i ,pBL1) if ts[7]~=2 then Duplicates[prefix..fp1]=mark end end
226 | sel=true
227 | end
228 | if sz1~=sz0 then count,mark,sel = 0,'0'
229 | elseif sel and sz1==sz0 and hs1~=hs0 then count=count+1 if count>35 then count=0 end mark=tostring(tonumber(count,36))
230 | end
231 | end
232 | if ts[9] then
233 | PGPI(0)
234 | for i=1,pin-1 do
235 | st0,ln0,st2,ln2,sz0,fa0,hs0,fp0 = st1,ln1,st3,ln3,sz1,fa1,hs1,fp1
236 | PGPI(i)
237 | if (not ts[2] or ts[2] and C.CompareStringW(C.LOCALE_USER_DEFAULT,Flags,st2,ln2,st3,ln3)==2) -- Full FileName only
238 | and (((ts[5] and ts[6]==1 or not ts[5] and ts[6]==0) and sz0==sz1)
239 | or ((ts[5] and ts[7]==1 or not ts[5] and ts[7]==0) and hs0==hs1)
240 | or ((ts[5] and ts[8]==1 or not ts[5] and ts[8]==0) and fa0==fa1))
241 | then
242 | if band(fa0,0x10)==0 then pc(PANEL_ACTIVE,"FCTL_SETSELECTION",i-1,pBL0) if ts[7]~=2 then Duplicates[prefix..fp0]=nil end end
243 | if band(fa1,0x10)==0 then pc(PANEL_ACTIVE,"FCTL_SETSELECTION",i ,pBL0) if ts[7]~=2 then Duplicates[prefix..fp1]=nil end end
244 | end
245 | end
246 | end
247 | pc(PANEL_ACTIVE,"FCTL_ENDSELECTION",0,NULL)
248 | pc(PANEL_ACTIVE,"FCTL_REDRAWPANEL",0,NULL)
249 | local t1=far.FarClock()
250 | if ts[11] then
251 | local pisel,pisin=""
252 | if pc(PANEL_ACTIVE,"FCTL_GETPANELINFO",0,PInfo)==1 then
253 | pisin=tonumber(PInfo.SelectedItemsNumber)
254 | pisel=tostring(pisin==1 and 0 or pisin).."/"..tostring(tonumber(PInfo.ItemsNumber))
255 | end
256 | local count=0
257 | while true do
258 | if win.GetFileAttr(freport)
259 | then count=count+1 freport=repfile:gsub("%.txt$","_"..count..".txt")
260 | else break
261 | end
262 | end
263 | local h = io.open(freport,"w+b")
264 | h:write("Items: "..pisel..
265 | "\nExecution time: "..(t1-t0)..
266 | " mcs\nNumber of symbols: "..(ts[2] and ts[3] or "all")..
267 | "\nIgnore case: "..tostring(ts[4])..
268 | "\nIgnore Full Duplicates of FileName: "..tostring(ts[5])..
269 | "\nSizes of FD: "..(ts[6]==0 and "<>" or ts[6]==1 and "==" or "--")..
270 | "\nHashes of FD: "..(ts[7]==0 and "<>" or ts[7]==1 and "==" or "--")..
271 | "\nAttributes of FD: "..(ts[8]==0 and "<>" or ts[8]==1 and "==" or "--")..
272 | "\nAccuracy (Two-pass method): "..tostring(ts[9])..
273 | "\n"..string.rep("-",40).."\nAttr\tSize\tHash\tPath\n"..string.rep("-",40).."\n")
274 | local function PGPSI(i)
275 | ppi.Size = pc(PANEL_ACTIVE,"FCTL_GETSELECTEDPANELITEM",i,NULL)
276 | if ppi.Size~=0 then
277 | local buf = ffi.new("char[?]",ppi.Size)
278 | ppi.Item = ffi.cast("struct PluginPanelItem*",buf)
279 | pc(PANEL_ACTIVE,"FCTL_GETSELECTEDPANELITEM",i,ppi)
280 | local path = win.Utf16ToUtf8(ffi.string(ppi.Item.FileName,C.wcslen(ppi.Item.FileName)*2))
281 | h:write(
282 | tostring(tonumber(ppi.Item.FileAttributes)).."\t"..
283 | tostring(tonumber(ppi.Item.FileSize)).."\t"..
284 | tostring(GetHash(path)).."\t"..
285 | path.."\n"
286 | )
287 | end
288 | end
289 | if pisin then for i=0,pisin-1 do PGPSI(i) end end
290 | io.close(h)
291 | far.Message("mcs: "..far.FarClock()-t0,"PSDFN")
292 | end
293 | end
294 | end
295 | end
296 | end;
297 | }
298 |
299 | Macro {
300 | description = "PSDFN - Help"; area = "Dialog"; key = "F1";
301 | condition=function() return Area.Dialog and Dlg.Id==guid end;
302 | action=function()
303 | if Dlg.CurPos<=3 then far.Message("The number of first (>0) or last (<0) symbols to compare","Help: Number of symbols")
304 | elseif Dlg.CurPos==4 then far.Message("Case of letters in FileName will be ignored","Help: Ignore case")
305 | elseif Dlg.CurPos==5 then far.Message("Full Duplicates of FileName will be ignored","Help: Ignore Full Duplicates of FileName")
306 | elseif Dlg.CurPos==6 then far.Message("-- ignore, == equal, <> is not equal","Help: Sizes of FD")
307 | elseif Dlg.CurPos==7 then far.Message("-- ignore, == equal, <> is not equal","Help: Hashes of FD")
308 | elseif Dlg.CurPos==8 then far.Message("-- ignore, == equal, <> is not equal","Help: Attributes of FD")
309 | elseif Dlg.CurPos==9 then far.Message("Two-pass method for\n<> (is not equal) options only","Help: Accuracy")
310 | elseif Dlg.CurPos==10 then far.Message("Clear selection for begin","Help: Clear selection")
311 | elseif Dlg.CurPos==11 then far.Message("mcs - total time of execution in mcs\nReport will be saved to:\n"..freport,"Help: Report",nil,"l")
312 | end
313 | end;
314 | }
315 |
--------------------------------------------------------------------------------
/Panel.CustomSortByName.lua:
--------------------------------------------------------------------------------
1 | -- Panel.CustomSortByName.lua
2 | -- v1.1.0.3
3 | -- Very powerful panel file sorting
4 | -- 
5 | -- Сортировки файлов в панели:
6 | --
7 | -- 1. С вводом Offset при нажатии шорката, если вместо ввода числа нажать Enter, то будет использовано прежнее значение. Стартовое значение (по умолчанию) 0, т.е. обычная сортировка по имени.
8 | -- 2. C вводом Symbols аналогично п.1, значение по умолчанию "-_ ".
9 | -- п.1 и п.2 с игнорированием символов - игнорируется то, что Майкрософт считает символами.
10 | -- 3. По группе цифр в имени файла с поиском в прямом, либо обратном направлении.
11 | -- 4. По подстроке, захваченной регэкспом. Регэкспы можно комментировать, в этом случае первую строку начинаем с -- (2-х минусов), далее комментарий, затем перевод строки и на второй строке пишем сам регэксп. Порядок сортировки можно изменить, добавив в конец регэкспа конструкцию {!:...}, где вместо ... указываем порядок возврата захваченных групп, например {!:$3$2$1}. Для поиска каждой группы по всей строке вне зависимости от их позиции, используется конструкция {?:pat1}{?:pat2}{?:pat3}{!:$3$2$1}, где patN - характерный паттерн группы, захватывается первый совпавший.
12 | -- 5. По функции пользователя. Примеры:
13 | -- [x] Offset=0
14 | -- [x] Func
15 | -- by BOM
16 | --
17 | -- ``` lua
18 | -- -- by BOM
19 | -- local efbbbf,fffe,feff,ffi,sub = '\239\187\191','\255\254','\254\255',require'ffi',string.sub
20 | -- local C=ffi.C
21 | -- local function bom(fp)
22 | -- local res=0
23 | -- local f=win.WideCharToMultiByte(ffi.string(fp,tonumber(C.wcslen(fp))*2),65001)
24 | -- local h=io.open(f,"rb")
25 | -- if h then
26 | -- local s=h:read(3) or '' h:close()
27 | -- if s==efbbbf then res=3 else s=sub(s,1,2) if s==fffe then res=2 elseif s==feff then res=1 end end
28 | -- end
29 | -- return res
30 | -- end
31 | -- return bom(_G.sFuncTbl.fp1)-bom(_G.sFuncTbl.fp2)
32 | -- ```
33 | --
34 | -- by BOM ffi
35 | --
36 | -- ``` lua
37 | -- -- by BOM ffi
38 | -- local ffi = require'ffi'
39 | -- local C = ffi.C
40 | -- local NULL = ffi.cast("void*",0)
41 | -- local ibuf=ffi.new"unsigned char[3]"
42 | --
43 | -- local mode_in = "\114\0\98\0\0" -- "rb" UTF-16LE..'\0'
44 | -- local function bom(fp)
45 | -- local res=0
46 | -- local f_in=assert(C._wfopen(ffi.cast("wchar_t*",fp),ffi.cast("wchar_t*",mode_in)))
47 | -- if f_in~=NULL then
48 | -- ffi.fill(ibuf,3)
49 | -- local n=C.fread(ibuf,1,ffi.sizeof(ibuf),f_in)
50 | -- C.fclose(f_in)
51 | -- local n,b0,b1,b2 = tonumber(n),tonumber(ibuf[0]),tonumber(ibuf[1]),tonumber(ibuf[2])
52 | -- if n==3 and b0==0xef and b1==0xbb and b2==0xbf then res=3
53 | -- elseif n>=2 then
54 | -- if b0==0xff and b1==0xfe then res=2
55 | -- elseif b0==0xfe and b1==0xff then res=1
56 | -- end
57 | -- end
58 | -- end
59 | -- return res
60 | -- end
61 | -- return bom(_G.sFuncTbl.fp1)-bom(_G.sFuncTbl.fp2)
62 | -- ```
63 | --
64 | -- by FullPath length
65 | --
66 | -- ``` lua
67 | -- -- by FullPath length
68 | -- local ffi = require'ffi'
69 | -- local C=ffi.C
70 | -- return tonumber(C.wcslen(_G.sFuncTbl.fp1))-tonumber(C.wcslen(_G.sFuncTbl.fp2))
71 | -- ```
72 | --
73 | -- by FileName length
74 | --
75 | -- ``` lua
76 | -- -- by FileName length
77 | -- return _G.sFuncTbl.ln1-_G.sFuncTbl.ln2
78 | -- ```
79 | --
80 | -- by level Folder
81 | --
82 | -- ``` lua
83 | -- -- by level Folder
84 | -- local ffi,BS = require'ffi',[[\\]]
85 | -- local C=ffi.C
86 | -- local _,x1 = regex.gsubW(ffi.string(_G.sFuncTbl.fp1,tonumber(C.wcslen(_G.sFuncTbl.fp1))*2),BS,BS)
87 | -- local _,x2 = regex.gsubW(ffi.string(_G.sFuncTbl.fp2,tonumber(C.wcslen(_G.sFuncTbl.fp2))*2),BS,BS)
88 | -- return x1-x2
89 | -- ```
90 | --
91 | -- by HEX in FileName
92 | --
93 | -- ``` lua
94 | -- -- by HEX in FileName
95 | -- local ffi,RE,huge,gsub = require'ffi',regex.new'[0-9A-Fa-f]+$',math.huge,string.gsub
96 | -- local C=ffi.C
97 | -- local function p(s)
98 | -- local num=huge
99 | -- local fp=ffi.string(s,tonumber(C.wcslen(s))*2)
100 | -- local hex=RE:matchW(fp)
101 | -- if hex then num=tonumber(gsub(hex,'\000',''),16) end
102 | -- return num
103 | -- end
104 | -- return p(_G.sFuncTbl.fp1)-p(_G.sFuncTbl.fp2)
105 | -- ```
106 | --
107 | -- LastWriteTime in Day
108 | --
109 | -- ``` lua
110 | -- -- by LastWriteTime in Day
111 | -- local guid="8EA08735-AF4A-4B90-A79F-6D453ADFA3B6"
112 | -- local ffi = require "ffi"
113 | -- local C = ffi.C
114 | --
115 | -- if not _G.sFuncTbl[guid] then _G.sFuncTbl[guid]=""
116 | -- ffi.cdef [[
117 | -- typedef struct { WORD wYear,wMonth,wDayOfWeek,wDay,wHour,wMinute,wSecond,wMilliseconds; } SYSTEMTIME;
118 | -- BOOL FileTimeToSystemTime(const FILETIME*, SYSTEMTIME*);
119 | -- BOOL SystemTimeToTzSpecificLocalTime(void*, const SYSTEMTIME*, SYSTEMTIME*);
120 | -- ]]
121 | -- end
122 | --
123 | -- local ft1, ft2, ftmp = ffi.new("SYSTEMTIME"), ffi.new("SYSTEMTIME"), ffi.new("SYSTEMTIME")
124 | --
125 | -- local function ms(st)
126 | -- return ((st.wHour*60+st.wMinute)*60+st.wSecond)*1000+st.wMilliseconds
127 | -- end
128 | --
129 | -- C.FileTimeToSystemTime(_G.sFuncTbl.lwt1, ftmp)
130 | -- C.SystemTimeToTzSpecificLocalTime(nil, ftmp, ft1)
131 | -- C.FileTimeToSystemTime(_G.sFuncTbl.lwt2, ftmp)
132 | -- C.SystemTimeToTzSpecificLocalTime(nil, ftmp, ft2)
133 | -- return ms(ft1) - ms(ft2)
134 | -- ```
135 | --
136 | --
137 | -- ---
138 | -- Keys: CtrlShiftF3 or from Menu "Sort by"
139 | -- Tip: In the dialog all elements have prompts, press F1 for help
140 | -- Url: https://forum.ru-board.com/topic.cgi?forum=5&topic=49572&start=2240#16
141 |
142 | if not (bit and jit) then return end
143 |
144 | local F = far.Flags
145 | local guid = "5B40F3FF-6593-48D2-8F78-4A32C8C36BCA"
146 | local uGuid = win.Uuid(guid)
147 | local MenuGuid = "B8B6E1DA-4221-47D2-AB2E-9EC67D0DC1E3"
148 |
149 | -- Settings --------------------------------------------------------------------
150 | local ModeNumber = 100110
151 | local GFocus,tSort = 3,{nil,true,0,false,"",false,false,false,4,true,false,"",false,"",false}
152 | local First,AlgSort,Offset,Symbols,DigSort,Digits,DirectSeek,xRegexp,sRegexp,xFunc,sFunc,sRgxTbl,sRgxRet,sRgxTrue = true,tSort[2],tSort[3],tSort[5],tSort[8],tSort[9],tSort[10],tSort[11],tSort[12],tSort[13],tSort[14],{}
153 | local Desc1,Indi1 = "Custom: by Name","!?"
154 | local Indicator = Indi1
155 | local Key = "CtrlShiftF3"
156 | --------------------------------------------------------------------------------
157 |
158 | local ffi = require'ffi'
159 | local C = ffi.C
160 | local Flags = C.SORT_STRINGSORT
161 | local DOT,BS = string.byte("."),string.byte("\\")
162 | local maxnum,count,ttime0,count0 = math.pow(10,tSort[9]),0
163 | local re0 = regex.new("\\$(\\d+)")
164 |
165 | ffi.cdef[[
166 | wchar_t* wcschr(const wchar_t*, wchar_t);
167 | wchar_t* wcsrchr(const wchar_t*, wchar_t);
168 | wchar_t* wcspbrk(const wchar_t*, const wchar_t*);
169 | ]]
170 |
171 | local edtFlags = F.DIF_HISTORY+F.DIF_USELASTHISTORY
172 | local Items = {
173 | --[[01]] {F.DI_DOUBLEBOX, 3,1, 65,9, 0, 0,0, 0, "Custom sort by Name. Help: F1"},
174 | --[[02]] {F.DI_CHECKBOX, 5,2, 15,0, 0, 0,0, 0, "O&ffset"},
175 | --[[03]] {F.DI_EDIT, 16,2, 22,0, 0, 0,0, 0, ""},
176 | --[[04]] {F.DI_CHECKBOX, 25,2, 36,0, 0, 0,0, 0, "Sy&mbols"},
177 | --[[05]] {F.DI_EDIT, 37,2, 63,0, 0, "CustomSortByName_Symbols",0, edtFlags, ""},
178 | --[[06]] {F.DI_CHECKBOX, 5,3, 20,0, 0, 0,0, 0, "Ignore &case"},
179 | --[[07]] {F.DI_CHECKBOX, 37,3, 56,0, 0, 0,0, 0, "Ignore &symbols"},
180 | --[[08]] {F.DI_CHECKBOX, 5,4, 15,0, 0, 0,0, 0, "&Digits"},
181 | --[[09]] {F.DI_EDIT, 16,4, 19,0, 0, 0,0, 0, ""},
182 | --[[10]] {F.DI_CHECKBOX, 37,4, 52,0, 0, 0,0, 0, "Direct s&eek"},
183 | --[[11]] {F.DI_CHECKBOX, 5,5, 15,0, 0, 0,0, 0, "Re&gexp"},
184 | --[[12]] {F.DI_EDIT, 16,5, 63,0, 0, "CustomSortByName_Regexp",0, edtFlags, ""},
185 | --[[13]] {F.DI_CHECKBOX, 5,6, 15,0, 0, 0,0, 0, "F&unc()"},
186 | --[[14]] {F.DI_EDIT, 16,6, 63,0, 0, "CustomSortByName_Function",0, edtFlags, ""},
187 | --[[15]] {F.DI_CHECKBOX, 5,8, 15,0, 0, 0,0, 0, "Re&port"},
188 | --[[16]] {F.DI_TEXT, -1,7, 0,0, 0, 0,0, F.DIF_SEPARATOR,""},
189 | --[[17]] {F.DI_BUTTON, 0,8, 0,0, 0, 0,0, F.DIF_DEFAULTBUTTON+F.DIF_CENTERGROUP,"&Ok"},
190 | --[[18]] {F.DI_BUTTON, 0,8, 0,0, 0, 0,0, F.DIF_CENTERGROUP,"Ca&ncel"}
191 | }
192 |
193 | local function ToWChar(str)
194 | str=win.Utf8ToUtf16(str)
195 | local res=ffi.new("wchar_t[?]",#str/2+1)
196 | ffi.copy(res,str)
197 | return res
198 | end
199 |
200 | local function GetStartAndLen(name)
201 | local ptr = C.wcsrchr(name,BS)
202 | name = ptr==nil and name or ptr+1
203 | local len = tonumber(C.wcslen(name))
204 | if AlgSort then
205 | if Offset==0 or Offset<=-len then
206 | elseif Offset<0 then name,len = name+len+Offset,-Offset
207 | elseif Offset=48 and code<=57 then
223 | if DirectSeek then num=num*10+code-48 else num=num+(code-48)*nm end
224 | nm = nm*10
225 | if j==b and nm==maxnum then
226 | lastnum = num
227 | if DirectSeek then pos = j+1-Digits else pos=j end
228 | end
229 | else
230 | if nm==maxnum then
231 | lastnum = num
232 | if DirectSeek then pos = j-Digits else pos=j+1 end
233 | break
234 | end
235 | num,nm = 0,1
236 | end
237 | end
238 | return lastnum,name+pos,len-pos
239 | end
240 |
241 | local Compare = function(p1,p2)
242 | count = count+1
243 | local st1,len1 = GetStartAndLen(p1.FileName)
244 | local st2,len2 = GetStartAndLen(p2.FileName)
245 | if DigSort then
246 | local res1 = GetDigits(st1,len1)
247 | local res2 = GetDigits(st2,len2)
248 | local res = res1-res2
249 | if res~=0 then
250 | return res
251 | else
252 | return -2 + C.CompareStringW(C.LOCALE_USER_DEFAULT,Flags,st1,len1,st2,len2)
253 | end
254 | elseif xRegexp then
255 | local function sRegFind(st,ln)
256 | local fname = ffi.string(st,ln*2)
257 | if sRgxRet then
258 | local t={}
259 | if sRgxTrue then
260 | t = {sRegexp:matchW(fname)}
261 | else
262 | for i=1,#sRgxTbl do t[i]=sRgxTbl[i]:matchW(fname) end
263 | end
264 | st = re0:gsub(sRgxRet,function(n) return t[tonumber(n)] end)
265 | else
266 | st = sRegexp:matchW(fname)
267 | end
268 | if st then
269 | ln = #st/2+1
270 | local s = ffi.new("wchar_t[?]",ln)
271 | ffi.copy(s,st)
272 | st = s
273 | end
274 | return st,ln
275 | end
276 | local st10,len10 = sRegFind(st1,len1)
277 | local st20,len20 = sRegFind(st2,len2)
278 | if not st10 and not st20 then return -2 + C.CompareStringW(C.LOCALE_USER_DEFAULT,Flags,st1,len1,st2,len2)
279 | elseif st10 and not st20 then return -1
280 | elseif not st10 and st20 then return 1
281 | elseif st10 and st20 then return -2 + C.CompareStringW(C.LOCALE_USER_DEFAULT,Flags,st10,len10,st20,len20)
282 | end
283 | elseif xFunc then
284 | _G.sFuncTbl = {lwt1=p1.LastWriteTime,lwt2=p2.LastWriteTime,fp1=p1.FileName,fp2=p2.FileName,st1=st1,ln1=len1,st2=st2,ln2=len2}
285 | return sFunc()
286 | else
287 | return -2 + C.CompareStringW(C.LOCALE_USER_DEFAULT,Flags,st1,len1,st2,len2)
288 | end
289 | end
290 |
291 | local ttSort={}
292 |
293 | local function DlgProc(hDlg,Msg,Param1,Param2)
294 | local function SetAlg()
295 | hDlg:send(F.DM_SETCHECK,2,ttSort[2] and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED)
296 | hDlg:send(F.DM_SETCHECK,4,ttSort[4] and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED)
297 | hDlg:send(F.DM_ENABLE,3,ttSort[2] and 1 or 0)
298 | hDlg:send(F.DM_ENABLE,5,ttSort[2] and 0 or 1)
299 | end
300 | local function Set2()
301 | hDlg:send(F.DM_SETCHECK,8,ttSort[8] and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED)
302 | hDlg:send(F.DM_SETCHECK,11,ttSort[11] and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED)
303 | hDlg:send(F.DM_SETCHECK,13,ttSort[13] and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED)
304 | hDlg:send(F.DM_ENABLE,9,ttSort[8] and 1 or 0)
305 | hDlg:send(F.DM_ENABLE,10,ttSort[8] and 1 or 0)
306 | hDlg:send(F.DM_ENABLE,12,ttSort[11] and 1 or 0)
307 | hDlg:send(F.DM_ENABLE,14,ttSort[13] and 1 or 0)
308 | end
309 | local function SetAlg2(p1,p2)
310 | if p2 then
311 | ttSort[8],ttSort[11],ttSort[13] = false,false,false
312 | ttSort[p1]=true
313 | Set2()
314 | else
315 | ttSort[p1]=false
316 | hDlg:send(F.DM_ENABLE,p1+1,0)
317 | if p1==8 then hDlg:send(F.DM_ENABLE,10,0) end
318 | end
319 | end
320 | if Msg==F.DN_INITDIALOG then
321 | for i=2,#Items-3 do ttSort[i]=tSort[i] end
322 | SetAlg()
323 | hDlg:send(F.DM_SETTEXT,3,ttSort[3])
324 | hDlg:send(F.DM_SETCHECK,6,ttSort[6] and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED)
325 | hDlg:send(F.DM_SETCHECK,7,ttSort[7] and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED)
326 | hDlg:send(F.DM_SETTEXT,9,ttSort[9])
327 | ttSort[5] = tostring(hDlg:send(F.DM_GETTEXT,5))
328 | ttSort[12] = tostring(hDlg:send(F.DM_GETTEXT,12))
329 | ttSort[14] = tostring(hDlg:send(F.DM_GETTEXT,14))
330 | Set2()
331 | hDlg:send(F.DM_SETCHECK,10,ttSort[10] and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED)
332 | hDlg:send(F.DM_SETFOCUS,GFocus)
333 | elseif Msg==F.DN_BTNCLICK and Param1==2 then -- [x] Offset
334 | ttSort[2] = Param2~=0 ttSort[4] = not ttSort[2] SetAlg()
335 | GFocus = ttSort[2] and 3 or 5
336 | hDlg:send(F.DM_SETFOCUS,GFocus)
337 | elseif Msg==F.DN_BTNCLICK and Param1==4 then -- [x] Symbols
338 | ttSort[4] = Param2~=0 ttSort[2] = not ttSort[4] SetAlg()
339 | GFocus = ttSort[2] and 3 or 5
340 | hDlg:send(F.DM_SETFOCUS,GFocus)
341 | elseif Msg==F.DN_EDITCHANGE and Param1==3 then -- Offset changed
342 | ttSort[3] = tonumber(hDlg:send(F.DM_GETTEXT,3)) or ttSort[3]
343 | elseif (Msg==F.DN_EDITCHANGE or Msg==F.DN_LISTCHANGE) and Param1==5 then -- Symbols changed
344 | ttSort[5] = tostring(hDlg:send(F.DM_GETTEXT,5)) or ttSort[5]
345 | elseif Msg==F.DN_BTNCLICK and Param1==6 then -- [x] IgnoreCase
346 | ttSort[6] = Param2~=0 -- C.NORM_IGNORECASE
347 | elseif Msg==F.DN_BTNCLICK and Param1==7 then -- [x] IgnoreSymbols
348 | ttSort[7] = Param2~=0 -- C.NORM_IGNORESYMBOLS
349 | elseif Msg==F.DN_BTNCLICK and Param1==8 then -- [x] Digits
350 | SetAlg2(Param1,Param2~=0)
351 | GFocus = ttSort[8] and 9 or 11
352 | hDlg:send(F.DM_SETFOCUS,GFocus)
353 | elseif Msg==F.DN_EDITCHANGE and Param1==9 then -- Digits changed
354 | ttSort[9] = tonumber(hDlg:send(F.DM_GETTEXT,9)) or ttSort[9]
355 | maxnum = math.pow(10,ttSort[9])
356 | elseif Msg==F.DN_BTNCLICK and Param1==10 then -- [x] DirectSeek
357 | ttSort[10] = Param2~=0
358 | elseif Msg==F.DN_BTNCLICK and Param1==11 then -- [x] Regexp
359 | SetAlg2(Param1,Param2~=0)
360 | GFocus = ttSort[11] and 12 or 13
361 | hDlg:send(F.DM_SETFOCUS,GFocus)
362 | elseif (Msg==F.DN_EDITCHANGE or Msg==F.DN_LISTCHANGE) and Param1==12 then -- Regexp changed
363 | ttSort[12] = tostring(hDlg:send(F.DM_GETTEXT,12)) or ttSort[12]
364 | elseif Msg==F.DN_BTNCLICK and Param1==13 then -- [x] Func()
365 | SetAlg2(Param1,Param2~=0)
366 | GFocus = ttSort[13] and 14 or 15
367 | hDlg:send(F.DM_SETFOCUS,GFocus)
368 | elseif (Msg==F.DN_EDITCHANGE or Msg==F.DN_LISTCHANGE) and Param1==14 then -- Func() changed
369 | ttSort[14] = tostring(hDlg:send(F.DM_GETTEXT,14)) or ttSort[14]
370 | elseif Msg==F.DN_BTNCLICK and Param1==15 then -- [x] Report
371 | ttSort[15] = Param2~=0
372 | elseif Msg==F.DN_GOTFOCUS then
373 | if Param1>2 and Param1<#Items-2 then GFocus=Param1 end
374 | else
375 | return
376 | end
377 | return true
378 | end
379 |
380 | Panel.LoadCustomSortMode(ModeNumber,{Description=Desc1;Indicator=Indicator;Compare=Compare})
381 |
382 | Macro {
383 | description = Desc1; area = "Shell Menu"; key = Key.." Enter MsLClick";
384 | condition = function(key) return Area.Shell and key==Key or Area.Menu and Menu.Id==MenuGuid and Menu.Value:match(Desc1) and (key=="Enter" or key=="MsLClick") end;
385 | action=function()
386 | if Area.Menu then Keys("Esc") end
387 | if far.Dialog(uGuid,-1,-1,69,11,nil,Items,nil,DlgProc)==#Items-1 then
388 | local res=false for i=2,#Items-3 do res = res or tSort[i]~=ttSort[i] tSort[i]=ttSort[i] end
389 | if res or First then panel.SetSortOrder(nil,1,bit.band(panel.GetPanelInfo(nil,1).Flags,F.PFLAGS_REVERSESORTORDER)==0) First=false end
390 | AlgSort,Offset,Symbols,DigSort,Digits,DirectSeek,xRegexp,sRegexp,xFunc,sFunc = tSort[2],tSort[3],ToWChar(tSort[5]),tSort[8],tSort[9],tSort[10],tSort[11],tSort[12],tSort[13],loadstring(tSort[14])
391 | if xRegexp then
392 | sRegexp,sRgxRet = regex.match(sRegexp,"^(?:--[^\\n]+?\\n)?(.*?)(?:\\{!:(.*?)\\}|)$")
393 | if sRegexp:match("%[%[..-%]%]") then sRegexp = regex.gsub(sRegexp,"\\[\\[(.+?)\\]\\]",function(s) return regex.gsub(s,"[^\\|]","\\%1") end) end
394 | --far.Message(sRegexp,"Regexp",nil,"l")
395 | for i=1,#sRgxTbl do sRgxTbl[i]=nil end
396 | local i=0 for v in regex.gmatch(sRegexp,"\\{\\?:(.*?)\\}(?=\\{\\?:|$)") do i=i+1 sRgxTbl[i]=regex.new(v) end
397 | if not sRgxRet or #sRgxTbl==0 then sRegexp,sRgxTrue = regex.new(sRegexp),true else sRgxTrue=false end
398 | end
399 | Flags = tSort[6] and bit.bor(Flags,C.NORM_IGNORECASE) or bit.band(Flags,bit.bnot(C.NORM_IGNORECASE))
400 | Flags = tSort[7] and bit.bor(Flags,C.NORM_IGNORESYMBOLS) or bit.band(Flags,bit.bnot(C.NORM_IGNORESYMBOLS))
401 | count = 0
402 | local ttime=far.FarClock()
403 | Panel.LoadCustomSortMode(ModeNumber,{Description=Desc1;Indicator=Indicator;Compare=Compare})
404 | Panel.SetCustomSortMode(ModeNumber,0)
405 | ttime = far.FarClock()-ttime
406 | local report = "Curr count: "..count.." mcs: "..ttime
407 | if count0 then
408 | report = report.."\nPrev count: "..count0.." mcs: "..ttime0.."\nDifference:"..string.format("%+"..(string.len(tostring(count0))+1).."d",count-count0).." mcs:"..string.format("%+"..(string.len(tostring(ttime0))+1).."d",ttime-ttime0)
409 | end
410 | count0,ttime0 = count,ttime
411 | if tSort[15] then
412 | panel.RedrawPanel(nil,1)
413 | far.Message(report,"Report",nil,"l")
414 | end
415 | end
416 | end;
417 | }
418 |
419 | Macro {
420 | description = Desc1.." - Help"; area = "Dialog"; key = "F1";
421 | condition=function() return Area.Dialog and Dlg.Id==guid end;
422 | action=function()
423 | if Dlg.CurPos<=3 then far.Message("Offset for capture substring in FileName","Help: Offset")
424 | elseif Dlg.CurPos<=5 then far.Message("Substring will be captured after these symbols","Help: Symbols")
425 | elseif Dlg.CurPos==6 then far.Message("Case of letters in FileName will be ignored","Help: Ignore case")
426 | elseif Dlg.CurPos==7 then far.Message("Symbols like &()[]{}-!?.,:; and other will be ignored","Help: Ignore symbols")
427 | elseif Dlg.CurPos<=9 then far.Message("Number of digits for sorting FileName by captured digits","Help: Digits")
428 | elseif Dlg.CurPos==10 then far.Message("Search direction of digits: [x] Forward seek, [ ] Reverse seek","Help: Direct seek")
429 | elseif Dlg.CurPos<=12 then far.Message("Use regex syntax for regexp\n\nFor comment use design like:\n1st line: -- comment\n2nd line: regexp \n\nAdditionally for change the sort order,\nyou can use non standard design like:\n\nmultigroup_pattern{!:$2$1}\nor\n{?:singlegroup_pattern}{?:singlegroup_pattern}{!:$2$1}\n\nIn the second case, groups are searched independently.","Help: Regexp")
430 | elseif Dlg.CurPos<=14 then far.Message("_G.sFuncTbl.fp1 FullPath1\n_G.sFuncTbl.st1 substring by offset\n_G.sFuncTbl.ln1 length of substring\n\n_G.sFuncTbl.fp2 FullPath2\n_G.sFuncTbl.st2 substring by offset\n_G.sFuncTbl.ln2 length of substring","Help: Func()",nil,"l")
431 | elseif Dlg.CurPos==15 then far.Message("count - the number of calls the comparison function\ntime - total time of execution","Help: Report",nil,"l")
432 | end
433 | end;
434 | }
435 |
--------------------------------------------------------------------------------
/ChessKnight.c:
--------------------------------------------------------------------------------
1 | // ChessKnight.c
2 | // v0.9.2.4
3 | // For fast find solution, put the compiled ChessKnight.exe to one folder with ChessKnight.lua
4 |
5 | #include
6 | #include
7 |
8 | char *getenv(const char *name);
9 | char *strcat(char *dest, const char *source);
10 | char *strcpy(char *dest, const char *source);
11 |
12 | const char *pTemp;
13 | const char *logname="\\ChessKnight.log";
14 | const char *txtname="\\ChessKnight.txt";
15 | uint8_t status;
16 | uint8_t bx; // ширина доски
17 | uint8_t by; // высота доски
18 | uint8_t x00; // X координата старта
19 | uint8_t y00; // Y координата старта
20 | uint8_t ret0; // замкнутый путь (0/1)
21 | uint8_t log0; // вывод лога (0/1)
22 | uint8_t x,y; // номер текущего хода, последний (текущий) вектор, координаты текущей клетки
23 | uint32_t fw; // счётчик ходов вперёд
24 | uint32_t rb; // счётчик возвратов (откатов)
25 | int16_t t1s; // номер хода
26 | int8_t t1v; // указатель на текущий вектор
27 | const uint32_t buf_size=0x10000000; // размер кэширующего буфера в памяти для последующей записи лога на диск
28 | unsigned char obuf[0x10000000];
29 | // {dx,dy} - вектор хода
30 | // порядок следования векторов в массиве определяет приоритет выбора клетки для хода среди клеток с одинаковым количеством доступных для движения векторов
31 | const int8_t dd[8]={-1,-1, 2,-2, 1, 1,-2, 2};
32 | uint8_t ti[8]; // массив с индексами векторов на клетки, доступные для хода с клетки x,y
33 | uint8_t ta[8]; // массив с количеством векторов у доступных для хода клеток
34 | // 5 6 3 2 1 1 -- 13-14s
35 | // сортируем вектора по убыванию количества векторов у целевых клеток, обеспечивая приоритет обхода клеток с наименьшим количеством входов
36 | // алгоритм сохраняет очерёдность одинаковых значений, обеспечивая неизменность маршрутов и их конечное количество
37 | //int8_t around(int8_t x,int8_t y)
38 | //{
39 | // int8_t tl=-1;
40 | // for(int8_t i=7; i>=0; i--)
41 | // {
42 | // int8_t x1=x+dd[i];
43 | // int8_t y1=y+dd[7-i];
44 | // if(x1>=0 && x1<=bx && y1>=0 && y1<=by && t00[x1][y1]<0)
45 | // {
46 | // tl++;
47 | // uint8_t a=0;
48 | // for(int8_t j=7; j>=0; j--)
49 | // {
50 | // int8_t x2=x1+dd[j];
51 | // int8_t y2=y1+dd[7-j];
52 | // if(x2>=0 && x2<=bx && y2>=0 && y2<=by && t00[x2][y2]<0){a++;}
53 | // }
54 | // ta[tl]=a; ti[tl]=i;
55 | // if(tl>0)
56 | // {
57 | // for(int8_t i1=tl; i1>0; i1--)
58 | // {
59 | // int8_t i0=i1-1;
60 | // if(ta[i1]>ta[i0])
61 | // {
62 | // uint8_t tmp;
63 | // tmp=ta[i0]; ta[i0]=ta[i1]; ta[i1]=tmp;
64 | // tmp=ti[i0]; ti[i0]=ti[i1]; ti[i1]=tmp;
65 | // }
66 | // else break;
67 | // }
68 | // }
69 | // }
70 | // }
71 | // return tl;
72 | //}
73 |
74 | int main(int argc, char *argv[])
75 | {
76 | pTemp=getenv("TEMP");
77 | int tmp;
78 | if(argc==1){printf("\nArgumets: bx by x0 y0 ret log hx hy...\n Example: ChessKnight.exe 7 7 1 1 1 0 4 4 4 3 4 2\nMax board size 127x127\nMax logging board size 15x15\nSee ChessKnight.log in %%TEMP%%\n"); return 1;}
79 | if(argc>=2){sscanf(argv[1], "%d", &tmp); bx = tmp & 127;}else{bx = 8;}
80 | if(argc>=3){sscanf(argv[2], "%d", &tmp); by = tmp & 127;}else{by = 8;}
81 | if(argc>=4){sscanf(argv[3], "%d", &tmp); x00 = tmp & 127;}else{x00 = 1;}
82 | if(argc>=5){sscanf(argv[4], "%d", &tmp); y00 = tmp & 127;}else{y00 = 1;}
83 | if(argc>=6){sscanf(argv[5], "%d", &tmp); ret0 = tmp & 1;}else{ret0 = 0;}
84 | if(argc>=7){sscanf(argv[6], "%d", &tmp); log0 = tmp & 1;}else{log0 = 0;}
85 | if(x00<1){x00=1;}
86 | if(y00<1){y00=1;}
87 | if(x00>bx){x00=bx;}
88 | if(y00>by){y00=by;}
89 | uint8_t ret=ret0;
90 | int8_t t00[bx][by]; // слой векторов с дырами
91 | int16_t t01[bx][by]; // слой нумерации ходов
92 | printf("Looking for a solution...\n");
93 | printf("\nBoard size: %dx%d, ret %d, log %d", bx, by, ret0, log0);
94 | if(argc>7){printf("\nHoles:"); for(uint8_t i=0; i1) printf(","); printf(" h%d %s %s", i>>1, argv[i+7], argv[i+8]);}}
95 | int16_t full = argc>7 ? bx*by-((argc-7)>>1) : bx*by;
96 | if(ret!=0 && (full & 1)!=0){ret=0;}
97 | uint8_t Tree[full][8]; // дерево, содержащее вектора возможных ходов
98 | uint8_t tv[full]; // активный (последний) вектор
99 | bx--; by--; x00--; y00--; full--; // align from 1 to 0 based
100 | for(uint8_t x=0; x<=full; x++){tv[x]=0xFF; for(uint8_t y=0; y<=7; y++){Tree[x][y]=0xFF;}} // инициализация Tree {{0xFF}}
101 | if(ret!=ret0 || (log0!=0 && (bx>15 || by>15)))
102 | {
103 | printf("\nUse:");
104 | if(ret!=ret0){printf(" ret %d", ret);}
105 | if(log0!=0 && (bx>15 || by>15)){log0=0; if(ret!=ret0){printf(",");} printf(" log %d", log0);}
106 | }
107 | printf("\n Start: %d %d", x00+1, y00+1);
108 | for(uint8_t x=0; x<=bx; x++){for(uint8_t y=0; y<=by; y++){t00[x][y]=-1; t01[x][y]=-1;}} // инициализация t00, t01 {{-1}}
109 | // расставляем дыры
110 | if(argc>7)
111 | {
112 | uint8_t x,y;
113 | for(uint8_t i=7; i=0 && x1<=bx && y1>=0 && y1<=by && t00[x1][y1]<0)
134 | {
135 | cl++;
136 | uint8_t a=0;
137 | for(uint8_t j=0; j<=7; j++)
138 | {
139 | int8_t x2=x1+dd[j];
140 | int8_t y2=y1+dd[7-j];
141 | if(x2>=0 && x2<=bx && y2>=0 && y2<=by && t00[x2][y2]<0){a++;}
142 | }
143 | ta[cl]=a; ti[cl]=i;
144 | if(cl>0)
145 | {
146 | for(int8_t i1=cl; i1>0; i1--)
147 | {
148 | int8_t i0=i1-1;
149 | if(ta[i0]=0) && (x8<=bx);
190 | uint8_t yy=(y8>=0) && (y8<=by);
191 | if((xx>0) && (yy>0) && (t00[x8][y8]<0))
192 | {
193 | int8_t x8m1=x8-1;
194 | int8_t x8m2=x8-2;
195 | int8_t x8p1=x8+1;
196 | int8_t x8p2=x8+2;
197 | int8_t y8m1=y8-1;
198 | int8_t y8m2=y8-2;
199 | int8_t y8p1=y8+1;
200 | int8_t y8p2=y8+2;
201 | uint8_t xm1=(x8m1>=0) && (x8m1<=bx);
202 | uint8_t xm2=(x8m2>=0) && (x8m2<=bx);
203 | uint8_t xp1=(x8p1>=0) && (x8p1<=bx);
204 | uint8_t xp2=(x8p2>=0) && (x8p2<=bx);
205 | uint8_t ym1=(y8m1>=0) && (y8m1<=by);
206 | uint8_t ym2=(y8m2>=0) && (y8m2<=by);
207 | uint8_t yp1=(y8p1>=0) && (y8p1<=by);
208 | uint8_t yp2=(y8p2>=0) && (y8p2<=by);
209 | uint8_t a=0;
210 | if((xm2>0) && (yp1>0) && (t00[x8m2][y8p1]<0)){a++;}
211 | if((xm2>0) && (ym1>0) && (t00[x8m2][y8m1]<0)){a++;}
212 | if((xm1>0) && (yp2>0) && (t00[x8m1][y8p2]<0)){a++;}
213 | if((xm1>0) && (ym2>0) && (t00[x8m1][y8m2]<0)){a++;}
214 | if((xp1>0) && (ym2>0) && (t00[x8p1][y8m2]<0)){a++;}
215 | if((xp1>0) && (yp2>0) && (t00[x8p1][y8p2]<0)){a++;}
216 | if((xp2>0) && (yp1>0) && (t00[x8p2][y8p1]<0)){a++;}
217 | if((xp2>0) && (ym1>0) && (t00[x8p2][y8m1]<0)){a++;}
218 | t1v++; ta[t1v]=a; ti[t1v]=0;
219 | }
220 | }
221 | //int8_t dx[8]={-1,-1, 2,-2, 1, 1,-2, 2};
222 | //int8_t dy[8]={ 2,-2, 1, 1,-2, 2,-1,-1};
223 | {
224 | int8_t x8=x-1;
225 | int8_t y8=y-2;
226 | uint8_t xx=(x8>=0) && (x8<=bx);
227 | uint8_t yy=(y8>=0) && (y8<=by);
228 | if((xx>0) && (yy>0) && (t00[x8][y8]<0))
229 | {
230 | int8_t x8m1=x8-1;
231 | int8_t x8m2=x8-2;
232 | int8_t x8p1=x8+1;
233 | int8_t x8p2=x8+2;
234 | int8_t y8m1=y8-1;
235 | int8_t y8m2=y8-2;
236 | int8_t y8p1=y8+1;
237 | int8_t y8p2=y8+2;
238 | uint8_t xm1=(x8m1>=0) && (x8m1<=bx);
239 | uint8_t xm2=(x8m2>=0) && (x8m2<=bx);
240 | uint8_t xp1=(x8p1>=0) && (x8p1<=bx);
241 | uint8_t xp2=(x8p2>=0) && (x8p2<=bx);
242 | uint8_t ym1=(y8m1>=0) && (y8m1<=by);
243 | uint8_t ym2=(y8m2>=0) && (y8m2<=by);
244 | uint8_t yp1=(y8p1>=0) && (y8p1<=by);
245 | uint8_t yp2=(y8p2>=0) && (y8p2<=by);
246 | uint8_t a=0;
247 | if((xm2>0) && (yp1>0) && (t00[x8m2][y8p1]<0)){a++;}
248 | if((xm2>0) && (ym1>0) && (t00[x8m2][y8m1]<0)){a++;}
249 | if((xm1>0) && (yp2>0) && (t00[x8m1][y8p2]<0)){a++;}
250 | if((xm1>0) && (ym2>0) && (t00[x8m1][y8m2]<0)){a++;}
251 | if((xp1>0) && (ym2>0) && (t00[x8p1][y8m2]<0)){a++;}
252 | if((xp1>0) && (yp2>0) && (t00[x8p1][y8p2]<0)){a++;}
253 | if((xp2>0) && (yp1>0) && (t00[x8p2][y8p1]<0)){a++;}
254 | if((xp2>0) && (ym1>0) && (t00[x8p2][y8m1]<0)){a++;}
255 | t1v++; ta[t1v]=a; ti[t1v]=1;
256 | }
257 | }
258 | //int8_t dx[8]={-1,-1, 2,-2, 1, 1,-2, 2};
259 | //int8_t dy[8]={ 2,-2, 1, 1,-2, 2,-1,-1};
260 | {
261 | int8_t x8=x+2;
262 | int8_t y8=y+1;
263 | uint8_t xx=(x8>=0) && (x8<=bx);
264 | uint8_t yy=(y8>=0) && (y8<=by);
265 | if((xx>0) && (yy>0) && (t00[x8][y8]<0))
266 | {
267 | int8_t x8m1=x8-1;
268 | int8_t x8m2=x8-2;
269 | int8_t x8p1=x8+1;
270 | int8_t x8p2=x8+2;
271 | int8_t y8m1=y8-1;
272 | int8_t y8m2=y8-2;
273 | int8_t y8p1=y8+1;
274 | int8_t y8p2=y8+2;
275 | uint8_t xm1=(x8m1>=0) && (x8m1<=bx);
276 | uint8_t xm2=(x8m2>=0) && (x8m2<=bx);
277 | uint8_t xp1=(x8p1>=0) && (x8p1<=bx);
278 | uint8_t xp2=(x8p2>=0) && (x8p2<=bx);
279 | uint8_t ym1=(y8m1>=0) && (y8m1<=by);
280 | uint8_t ym2=(y8m2>=0) && (y8m2<=by);
281 | uint8_t yp1=(y8p1>=0) && (y8p1<=by);
282 | uint8_t yp2=(y8p2>=0) && (y8p2<=by);
283 | uint8_t a=0;
284 | if((xm2>0) && (yp1>0) && (t00[x8m2][y8p1]<0)){a++;}
285 | if((xm2>0) && (ym1>0) && (t00[x8m2][y8m1]<0)){a++;}
286 | if((xm1>0) && (yp2>0) && (t00[x8m1][y8p2]<0)){a++;}
287 | if((xm1>0) && (ym2>0) && (t00[x8m1][y8m2]<0)){a++;}
288 | if((xp1>0) && (ym2>0) && (t00[x8p1][y8m2]<0)){a++;}
289 | if((xp1>0) && (yp2>0) && (t00[x8p1][y8p2]<0)){a++;}
290 | if((xp2>0) && (yp1>0) && (t00[x8p2][y8p1]<0)){a++;}
291 | if((xp2>0) && (ym1>0) && (t00[x8p2][y8m1]<0)){a++;}
292 | t1v++; ta[t1v]=a; ti[t1v]=2;
293 | }
294 | }
295 | //int8_t dx[8]={-1,-1, 2,-2, 1, 1,-2, 2};
296 | //int8_t dy[8]={ 2,-2, 1, 1,-2, 2,-1,-1};
297 | {
298 | int8_t x8=x-2;
299 | int8_t y8=y+1;
300 | uint8_t xx=(x8>=0) && (x8<=bx);
301 | uint8_t yy=(y8>=0) && (y8<=by);
302 | if((xx>0) && (yy>0) && (t00[x8][y8]<0))
303 | {
304 | int8_t x8m1=x8-1;
305 | int8_t x8m2=x8-2;
306 | int8_t x8p1=x8+1;
307 | int8_t x8p2=x8+2;
308 | int8_t y8m1=y8-1;
309 | int8_t y8m2=y8-2;
310 | int8_t y8p1=y8+1;
311 | int8_t y8p2=y8+2;
312 | uint8_t xm1=(x8m1>=0) && (x8m1<=bx);
313 | uint8_t xm2=(x8m2>=0) && (x8m2<=bx);
314 | uint8_t xp1=(x8p1>=0) && (x8p1<=bx);
315 | uint8_t xp2=(x8p2>=0) && (x8p2<=bx);
316 | uint8_t ym1=(y8m1>=0) && (y8m1<=by);
317 | uint8_t ym2=(y8m2>=0) && (y8m2<=by);
318 | uint8_t yp1=(y8p1>=0) && (y8p1<=by);
319 | uint8_t yp2=(y8p2>=0) && (y8p2<=by);
320 | uint8_t a=0;
321 | if((xm2>0) && (yp1>0) && (t00[x8m2][y8p1]<0)){a++;}
322 | if((xm2>0) && (ym1>0) && (t00[x8m2][y8m1]<0)){a++;}
323 | if((xm1>0) && (yp2>0) && (t00[x8m1][y8p2]<0)){a++;}
324 | if((xm1>0) && (ym2>0) && (t00[x8m1][y8m2]<0)){a++;}
325 | if((xp1>0) && (ym2>0) && (t00[x8p1][y8m2]<0)){a++;}
326 | if((xp1>0) && (yp2>0) && (t00[x8p1][y8p2]<0)){a++;}
327 | if((xp2>0) && (yp1>0) && (t00[x8p2][y8p1]<0)){a++;}
328 | if((xp2>0) && (ym1>0) && (t00[x8p2][y8m1]<0)){a++;}
329 | t1v++; ta[t1v]=a; ti[t1v]=3;
330 | }
331 | }
332 | //int8_t dx[8]={-1,-1, 2,-2, 1, 1,-2, 2};
333 | //int8_t dy[8]={ 2,-2, 1, 1,-2, 2,-1,-1};
334 | {
335 | int8_t x8=x+1;
336 | int8_t y8=y-2;
337 | uint8_t xx=(x8>=0) && (x8<=bx);
338 | uint8_t yy=(y8>=0) && (y8<=by);
339 | if((xx>0) && (yy>0) && (t00[x8][y8]<0))
340 | {
341 | int8_t x8m1=x8-1;
342 | int8_t x8m2=x8-2;
343 | int8_t x8p1=x8+1;
344 | int8_t x8p2=x8+2;
345 | int8_t y8m1=y8-1;
346 | int8_t y8m2=y8-2;
347 | int8_t y8p1=y8+1;
348 | int8_t y8p2=y8+2;
349 | uint8_t xm1=(x8m1>=0) && (x8m1<=bx);
350 | uint8_t xm2=(x8m2>=0) && (x8m2<=bx);
351 | uint8_t xp1=(x8p1>=0) && (x8p1<=bx);
352 | uint8_t xp2=(x8p2>=0) && (x8p2<=bx);
353 | uint8_t ym1=(y8m1>=0) && (y8m1<=by);
354 | uint8_t ym2=(y8m2>=0) && (y8m2<=by);
355 | uint8_t yp1=(y8p1>=0) && (y8p1<=by);
356 | uint8_t yp2=(y8p2>=0) && (y8p2<=by);
357 | uint8_t a=0;
358 | if((xm2>0) && (yp1>0) && (t00[x8m2][y8p1]<0)){a++;}
359 | if((xm2>0) && (ym1>0) && (t00[x8m2][y8m1]<0)){a++;}
360 | if((xm1>0) && (yp2>0) && (t00[x8m1][y8p2]<0)){a++;}
361 | if((xm1>0) && (ym2>0) && (t00[x8m1][y8m2]<0)){a++;}
362 | if((xp1>0) && (ym2>0) && (t00[x8p1][y8m2]<0)){a++;}
363 | if((xp1>0) && (yp2>0) && (t00[x8p1][y8p2]<0)){a++;}
364 | if((xp2>0) && (yp1>0) && (t00[x8p2][y8p1]<0)){a++;}
365 | if((xp2>0) && (ym1>0) && (t00[x8p2][y8m1]<0)){a++;}
366 | t1v++; ta[t1v]=a; ti[t1v]=4;
367 | }
368 | }
369 | //int8_t dx[8]={-1,-1, 2,-2, 1, 1,-2, 2};
370 | //int8_t dy[8]={ 2,-2, 1, 1,-2, 2,-1,-1};
371 | {
372 | int8_t x8=x+1;
373 | int8_t y8=y+2;
374 | uint8_t xx=(x8>=0) && (x8<=bx);
375 | uint8_t yy=(y8>=0) && (y8<=by);
376 | if((xx>0) && (yy>0) && (t00[x8][y8]<0))
377 | {
378 | int8_t x8m1=x8-1;
379 | int8_t x8m2=x8-2;
380 | int8_t x8p1=x8+1;
381 | int8_t x8p2=x8+2;
382 | int8_t y8m1=y8-1;
383 | int8_t y8m2=y8-2;
384 | int8_t y8p1=y8+1;
385 | int8_t y8p2=y8+2;
386 | uint8_t xm1=(x8m1>=0) && (x8m1<=bx);
387 | uint8_t xm2=(x8m2>=0) && (x8m2<=bx);
388 | uint8_t xp1=(x8p1>=0) && (x8p1<=bx);
389 | uint8_t xp2=(x8p2>=0) && (x8p2<=bx);
390 | uint8_t ym1=(y8m1>=0) && (y8m1<=by);
391 | uint8_t ym2=(y8m2>=0) && (y8m2<=by);
392 | uint8_t yp1=(y8p1>=0) && (y8p1<=by);
393 | uint8_t yp2=(y8p2>=0) && (y8p2<=by);
394 | uint8_t a=0;
395 | if((xm2>0) && (yp1>0) && (t00[x8m2][y8p1]<0)){a++;}
396 | if((xm2>0) && (ym1>0) && (t00[x8m2][y8m1]<0)){a++;}
397 | if((xm1>0) && (yp2>0) && (t00[x8m1][y8p2]<0)){a++;}
398 | if((xm1>0) && (ym2>0) && (t00[x8m1][y8m2]<0)){a++;}
399 | if((xp1>0) && (ym2>0) && (t00[x8p1][y8m2]<0)){a++;}
400 | if((xp1>0) && (yp2>0) && (t00[x8p1][y8p2]<0)){a++;}
401 | if((xp2>0) && (yp1>0) && (t00[x8p2][y8p1]<0)){a++;}
402 | if((xp2>0) && (ym1>0) && (t00[x8p2][y8m1]<0)){a++;}
403 | t1v++; ta[t1v]=a; ti[t1v]=5;
404 | }
405 | }
406 | //int8_t dx[8]={-1,-1, 2,-2, 1, 1,-2, 2};
407 | //int8_t dy[8]={ 2,-2, 1, 1,-2, 2,-1,-1};
408 | {
409 | int8_t x8=x-2;
410 | int8_t y8=y-1;
411 | uint8_t xx=(x8>=0) && (x8<=bx);
412 | uint8_t yy=(y8>=0) && (y8<=by);
413 | if((xx>0) && (yy>0) && (t00[x8][y8]<0))
414 | {
415 | int8_t x8m1=x8-1;
416 | int8_t x8m2=x8-2;
417 | int8_t x8p1=x8+1;
418 | int8_t x8p2=x8+2;
419 | int8_t y8m1=y8-1;
420 | int8_t y8m2=y8-2;
421 | int8_t y8p1=y8+1;
422 | int8_t y8p2=y8+2;
423 | uint8_t xm1=(x8m1>=0) && (x8m1<=bx);
424 | uint8_t xm2=(x8m2>=0) && (x8m2<=bx);
425 | uint8_t xp1=(x8p1>=0) && (x8p1<=bx);
426 | uint8_t xp2=(x8p2>=0) && (x8p2<=bx);
427 | uint8_t ym1=(y8m1>=0) && (y8m1<=by);
428 | uint8_t ym2=(y8m2>=0) && (y8m2<=by);
429 | uint8_t yp1=(y8p1>=0) && (y8p1<=by);
430 | uint8_t yp2=(y8p2>=0) && (y8p2<=by);
431 | uint8_t a=0;
432 | if((xm2>0) && (yp1>0) && (t00[x8m2][y8p1]<0)){a++;}
433 | if((xm2>0) && (ym1>0) && (t00[x8m2][y8m1]<0)){a++;}
434 | if((xm1>0) && (yp2>0) && (t00[x8m1][y8p2]<0)){a++;}
435 | if((xm1>0) && (ym2>0) && (t00[x8m1][y8m2]<0)){a++;}
436 | if((xp1>0) && (ym2>0) && (t00[x8p1][y8m2]<0)){a++;}
437 | if((xp1>0) && (yp2>0) && (t00[x8p1][y8p2]<0)){a++;}
438 | if((xp2>0) && (yp1>0) && (t00[x8p2][y8p1]<0)){a++;}
439 | if((xp2>0) && (ym1>0) && (t00[x8p2][y8m1]<0)){a++;}
440 | t1v++; ta[t1v]=a; ti[t1v]=6;
441 | }
442 | }
443 | //int8_t dx[8]={-1,-1, 2,-2, 1, 1,-2, 2};
444 | //int8_t dy[8]={ 2,-2, 1, 1,-2, 2,-1,-1};
445 | {
446 | int8_t x8=x+2;
447 | int8_t y8=y-1;
448 | uint8_t xx=(x8>=0) && (x8<=bx);
449 | uint8_t yy=(y8>=0) && (y8<=by);
450 | if((xx>0) && (yy>0) && (t00[x8][y8]<0))
451 | {
452 | int8_t x8m1=x8-1;
453 | int8_t x8m2=x8-2;
454 | int8_t x8p1=x8+1;
455 | int8_t x8p2=x8+2;
456 | int8_t y8m1=y8-1;
457 | int8_t y8m2=y8-2;
458 | int8_t y8p1=y8+1;
459 | int8_t y8p2=y8+2;
460 | uint8_t xm1=(x8m1>=0) && (x8m1<=bx);
461 | uint8_t xm2=(x8m2>=0) && (x8m2<=bx);
462 | uint8_t xp1=(x8p1>=0) && (x8p1<=bx);
463 | uint8_t xp2=(x8p2>=0) && (x8p2<=bx);
464 | uint8_t ym1=(y8m1>=0) && (y8m1<=by);
465 | uint8_t ym2=(y8m2>=0) && (y8m2<=by);
466 | uint8_t yp1=(y8p1>=0) && (y8p1<=by);
467 | uint8_t yp2=(y8p2>=0) && (y8p2<=by);
468 | uint8_t a=0;
469 | if((xm2>0) && (yp1>0) && (t00[x8m2][y8p1]<0)){a++;}
470 | if((xm2>0) && (ym1>0) && (t00[x8m2][y8m1]<0)){a++;}
471 | if((xm1>0) && (yp2>0) && (t00[x8m1][y8p2]<0)){a++;}
472 | if((xm1>0) && (ym2>0) && (t00[x8m1][y8m2]<0)){a++;}
473 | if((xp1>0) && (ym2>0) && (t00[x8p1][y8m2]<0)){a++;}
474 | if((xp1>0) && (yp2>0) && (t00[x8p1][y8p2]<0)){a++;}
475 | if((xp2>0) && (yp1>0) && (t00[x8p2][y8p1]<0)){a++;}
476 | if((xp2>0) && (ym1>0) && (t00[x8p2][y8m1]<0)){a++;}
477 | t1v++; ta[t1v]=a; ti[t1v]=7;
478 | }
479 | }
480 | if(t1v>0)
481 | {
482 | for(uint8_t i2=t1v; i2>0; i2--)
483 | {
484 | for(int8_t i0=0; i0=0)
496 | {
497 | for(uint8_t i=0; i<=t1v; i++){Tree[t1s][i]=ti[i];} // записываем векторы в дерево вариантов пути
498 | FORWARD:
499 | {
500 | // сохраняем указатель на активный (последний) вектор
501 | tv[t1s]=t1v; uint8_t v=Tree[t1s][t1v]; uint8_t x2=x+dd[v]; uint8_t y2=y+dd[7-v]; // получаем вектор и координаты следующей клетки
502 | if(((ret!=0) && (t1s0){fwrite(obuf,1,bsz,f_out);} fclose(f_out);} // logging
537 |
538 | // экспорт данных для ChessKnight.lua
539 | char pPath[512];
540 | strcpy(pPath, pTemp);
541 | f_out=fopen(strcat(pPath, txtname),"wb");
542 | if(f_out==NULL){printf("Error: can't open the file\n"); return 1;} // exit
543 | uint32_t variants=0;
544 | if(t1s>=0){for(int16_t i=t1s; i>=0; i--){if(tv[i]<=7){variants+=tv[i]+1;}}}else{variants=0;}
545 | fwrite(&status,1,sizeof(status),f_out); // статус
546 | fwrite(&x,1,sizeof(x),f_out); // X координата финиша
547 | fwrite(&y,1,sizeof(y),f_out); // Y координата финиша
548 | fwrite(&t1s,1,sizeof(t1s),f_out); // количество ходов
549 | fwrite(&fw,1,sizeof(fw),f_out); // количество ходов вперёд
550 | fwrite(&rb,1,sizeof(rb),f_out); // количество откатов
551 | fwrite(&variants,1,sizeof(variants),f_out); // сумма вариантов ходов
552 | fwrite(t00,1,sizeof(t00),f_out);
553 | fwrite(t01,1,sizeof(t01),f_out);
554 | fwrite(Tree,1,sizeof(Tree),f_out);
555 | fwrite(tv,1,sizeof(tv),f_out);
556 | fclose(f_out);
557 |
558 | printf("\nFinish: %d %d", ++x, ++y);
559 | printf("\nVisited squares: %d/%d", ++t1s, ++full);
560 | printf("\n Moves: %d", fw+rb);
561 | printf("\n Forward: %d", fw);
562 | printf("\nRollback: %d", rb);
563 | printf("\nVariants: %d", variants);
564 | printf("\n Status: %d", status);
565 | }
566 | return 0; // exit
567 | }
568 |
--------------------------------------------------------------------------------