ZNZNCOOP

MC 1.8

Apr 5th, 2016
1,095
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. --[[      Midday Commander Color Ver. 1.8 ]]--
  2. --[[ Created by Zer0Galaxy & Neo & Totoro ]]--
  3. --[[              (c)  No rights reserved ]]--
  4.  
  5. local unicode = require('unicode')
  6. local len=unicode.len
  7. local sub=unicode.sub
  8. local fs = require('filesystem')
  9. local term = require('term')
  10. local shell = require('shell')
  11. local event = require('event')
  12. local com = require('component')
  13. local gpu = com.gpu
  14. local keyboard = require('keyboard')
  15.  
  16. local colors = {
  17.   white = 0xFFFFFF,
  18.   black = 0x000000,
  19.   blue  = 0x0060A0,
  20.   green = 0x336600,
  21.   orange= 0xffcc33,
  22.   red   = 0xee3b3b
  23. }
  24. local keys = keyboard.keys
  25. local Left,Rght,Active,Find
  26. local wScr, hScr = gpu.maxResolution()
  27. if wScr>80 then wScr,hScr=80,25 end
  28. local cmd, scr, Menu
  29. local NormalCl, PanelCl, DirCl, SelectCl, WindowCl, AlarmWinCl
  30. local xMenu,cmdstr,curpos,work=-1,'',0,true
  31. local Shift,Ctrl,Alt=256,512,1024
  32.  
  33. local function SetColor(cl)
  34.   gpu.setForeground(cl[1])
  35.   gpu.setBackground(cl[2])
  36. end
  37.  
  38. local function saveScreen()
  39.   scr={cl={}}
  40.   scr.W,scr.H = gpu.getResolution()
  41.   scr.cl[1]=gpu.getForeground()
  42.   scr.cl[2]=gpu.getBackground()
  43.   scr.posX, scr.posY = term.getCursor()
  44.   for i=1,scr.H do
  45.     scr[i]={}
  46.     local FC,BC
  47.     for j=1,scr.W do
  48.       local c,fc,bc=gpu.get(j,i)
  49.       if fc==FC then fc=nil end
  50.       if bc==BC then bc=nil end
  51.       if fc or bc then
  52.         table.insert(scr[i],{fc=fc,bc=bc,c=""})
  53.         FC,BC=fc or FC, bc or BC
  54.       end
  55.       scr[i][#scr[i]].c=scr[i][#scr[i]].c .. c
  56.     end
  57.   end
  58.   gpu.setResolution(wScr,hScr)
  59. end
  60.  
  61. local function loadScreen()
  62.   gpu.setResolution(scr.W,scr.H)
  63.   term.setCursorBlink(false)
  64.   for i=1,scr.H do
  65.     local curX=1
  66.     for j=1,#scr[i] do
  67.       if scr[i][j].fc then gpu.setForeground(scr[i][j].fc) end
  68.       if scr[i][j].bc then gpu.setBackground(scr[i][j].bc) end
  69.       gpu.set(curX,i,scr[i][j].c) curX=curX+len(scr[i][j].c)
  70.     end
  71.   end
  72.   SetColor(scr.cl)
  73.   term.setCursor(scr.posX,scr.posY)
  74.   term.setCursorBlink(true)
  75. end
  76.  
  77. local function ShowCmd()
  78.   SetColor(NormalCl)
  79.   term.setCursor(1, hScr-1)
  80.   term.clearLine()
  81.   term.write(shell.getWorkingDirectory()..'> '..cmdstr)
  82.   term.setCursor(term.getCursor()-curpos, hScr-1)
  83. end
  84.  
  85. local panel ={wPan=math.ceil(wScr / 2)}
  86. function panel:ShowFirst()
  87.   local p=self.Path..'/'
  88.   if len(p)> self.wPan-6 then p='..'..sub(p,-self.wPan+7) end
  89.   p=' '..p..' '
  90.   gpu.set(self.X, 1,'┌'..string.rep('─',self.wPan-2)..'┐')
  91.   term.setCursor(self.X+(self.wPan-len(p))/2,1)
  92.   if self==Active then
  93.     SetColor(SelectCl)
  94.     term.write(p)
  95.     SetColor(PanelCl)
  96.   else
  97.     term.write(p)
  98.   end
  99. end
  100.  
  101. function panel:ShowLine(Line)
  102.   term.setCursor(self.X, Line-self.Shift+2)
  103.   term.write('│')
  104.   if self.tFiles[Line]~=nil then
  105.     local Name=self.tFiles[Line]
  106.     if self.tSize[Line]=='DIR' then Name='/'..Name SetColor(DirCl) end
  107.     if len(Name)>self.wPan-4 then Name=sub(Name,1,self.wPan-6)..'..' end
  108.     Name=' '..Name..string.rep(' ',self.wPan-len(Name)-4)..' '
  109.     if self==Active and Line==self.CurLine then SetColor(SelectCl) end
  110.     term.write(Name)
  111.   else
  112.     term.write(string.rep(' ',self.wPan-2))
  113.   end
  114.   SetColor(PanelCl)
  115.   term.write('│')
  116. end
  117.  
  118. function panel:ShowLines()
  119.   for i=self.Shift, self.Shift+hScr-5 do self:ShowLine(i) end
  120. end
  121.  
  122. function panel:ShowLast()
  123.   gpu.set(self.X, hScr-2,'└'..string.rep('─',self.wPan-2)..'┘')
  124.   gpu.set(self.X+2, hScr-2, self.tSize[self.CurLine])
  125. end
  126.  
  127. function panel:Show()
  128.   if self.CurLine>#self.tFiles then self.CurLine=#self.tFiles end  
  129.   SetColor(PanelCl)
  130.   self:ShowFirst()
  131.   self:ShowLines()
  132.   self:ShowLast()
  133. end
  134.  
  135. function panel:GetFiles()
  136.   local Files={}
  137.   for name in fs.list(self.Path) do
  138.     table.insert(Files, name)
  139.   end
  140.   if self.Path=='' then
  141.     self.tFiles={}
  142.     self.tSize={}
  143.   else
  144.     self.tFiles={'..'}
  145.     self.tSize={'DIR'}
  146.   end
  147.   for n,Item in pairs(Files) do
  148.     if Item:sub(-1) == '/' then
  149.       table.insert(self.tFiles,Item)
  150.       table.insert(self.tSize,'DIR')
  151.     end
  152.   end
  153.   for n,Item in pairs(Files) do
  154.     if Item:sub(-1) ~= '/' then
  155.       local sPath=fs.concat(self.Path,Item)
  156.       table.insert(self.tFiles,Item)
  157.       table.insert(self.tSize,fs.size(sPath).." b")
  158.     end
  159.   end
  160.   self:Show()
  161. end
  162.  
  163. function panel:SetPos(FileName)
  164.   if fs.isDirectory(FileName) then FileName=FileName..'/' end
  165.   self.Path,FileName=FileName:match('(.-)/?([^/]+/?)$')
  166.   shell.setWorkingDirectory(self.Path)
  167.   self.CurLine=1
  168.   self.Shift=1
  169.   self:GetFiles()
  170.   for i=1,#self.tFiles do
  171.     if self.tFiles[i]==FileName then
  172.       self.CurLine=i
  173.       break
  174.     end
  175.   end
  176.   if Active.CurLine>hScr-4 then
  177.     Active.Shift=Active.CurLine-hScr+6
  178.   end
  179. end
  180.  
  181. function panel:new(x,path)
  182.   local obj={X = x, Path =path, tFiles={}, tSize={}, CurLine=1, Shift=1}
  183.   return setmetatable(obj,{__index=panel})
  184. end
  185.  
  186. local Fpanel ={wPan=wScr}
  187. setmetatable(Fpanel,{__index=panel})
  188.  
  189. function Fpanel:new(x,path)
  190.   local obj=panel:new(x,path)
  191.   return setmetatable(obj,{__index=Fpanel})
  192. end
  193.  
  194. local function FindFile(FileName,Path)
  195.   local Result={}
  196.   local SubDir={}
  197.   for name in fs.list(Path) do
  198.     if string.sub(name, -1) == '/' then
  199.       table.insert(SubDir, Path..name)
  200.       name=name..".."
  201.     end
  202.     if string.match(name, FileName) then
  203.       table.insert(Result, Path..name)
  204.     end
  205.   end
  206.   for i=1,#SubDir do
  207.     local Files = FindFile(FileName,SubDir[i])
  208.     for j=1,#Files do table.insert(Result,Files[j]) end
  209.   end
  210.   return Result
  211. end
  212.  
  213. function Fpanel:GetFiles()
  214.   local code={{'%.','%%.'},{'*','.-'},{'?','.'}}
  215.   local Templ=self.Path
  216.   for i=1,#code do Templ=Templ:gsub(code[i][1],code[i][2]) end
  217.   self.tFiles=FindFile('^'..Templ..'$','')
  218.   table.insert(self.tFiles,1,'..')
  219.   self.tSize={'DIR'}
  220.   for i=2,#self.tFiles do
  221.     if fs.isDirectory(self.tFiles[i]) then
  222.       self.tSize[i]='DIR'
  223.     else
  224.       self.tSize[i]=tostring(fs.size(self.tFiles[i]))
  225.     end
  226.   end
  227.   self:Show()
  228. end
  229.  
  230. function Fpanel:ShowFirst()
  231.   local p='Find:'..self.Path
  232.   if len(p)> self.wPan-6 then p='..'..sub(p,-self.wPan+7) end
  233.   p=' '..p..' '
  234.   gpu.set(self.X, 1,'┌'..string.rep('─',self.wPan-2)..'┐')
  235.   SetColor(SelectCl)
  236.   gpu.set(self.X+(self.wPan-len(p))/2,1,p)
  237.   SetColor(PanelCl)
  238. end
  239.  
  240. local function ShowPanels()
  241.   SetColor(NormalCl)
  242.   term.clear()
  243.   if Active==Find then
  244.     Find:Show()
  245.   else
  246.     Left:GetFiles()
  247.     Rght:GetFiles()
  248.   end
  249.   term.setCursor(xMenu, hScr)
  250.   for i=1,#Menu do
  251.     if #Menu[i]>0 then
  252.     SetColor(NormalCl)
  253.     term.write(' F'..i)
  254.     SetColor(SelectCl)
  255.     term.write(Menu[i])
  256.     end
  257.   end
  258.   term.setCursorBlink(true)
  259. end
  260.  
  261. local function Dialog(cl,Lines,Str,But)
  262.   SetColor(cl)
  263.   local H=#Lines+3
  264.   local CurBut=1
  265.   if Str then H=H+1 CurBut=0 end
  266.   if not But then But={'Ok'} end
  267.   local function Buttons()
  268.     local Butt=''
  269.     for i=1,#But do
  270.       if i==CurBut then
  271.         Butt=Butt..'['..But[i]..']'
  272.       else
  273.         Butt=Butt..' '..But[i]..' '
  274.       end
  275.     end
  276.     return Butt
  277.   end
  278.   local W=len(Buttons())
  279.   for i=1,#Lines do
  280.     if len(Lines[i])>W then W=len(Lines[i]) end
  281.   end
  282.   if Str and (len(Str)>W) then W=len(Str) end
  283.   W=W+4
  284.   local x= math.ceil((wScr-W)/2)
  285.   local y= math.ceil((hScr-H)/2)+1
  286.   gpu.set(x-1, y, ' ╔'..string.rep('═',W-2)..'╗ ')
  287.   for i=1,#Lines+2 do
  288.     gpu.set(x-1, y+i, ' ║'..string.rep(' ',W-2)..'║ ')
  289.   end
  290.   gpu.set(x-1, y+H-1,' ╚'..string.rep('═',W-2)..'╝ ')
  291.   for i=1,#Lines do
  292.     if Lines.left then gpu.set(x+2, y+i, Lines[i])
  293.     else gpu.set(x+(W-len(Lines[i]))/2, y+i, Lines[i]) end
  294.   end
  295.  
  296.   while true do
  297.     term.setCursorBlink(CurBut==0)
  298.     term.setCursor(x+(W-len(Buttons()))/2, y+H-2)
  299.     term.write(Buttons())
  300.     if CurBut==0 then
  301.       local S=Str
  302.       if len(S)>W-4 then S='..'..sub(S,-W+6) end
  303.       term.setCursor(x+2, y+H-3)  term.write(S)
  304.     end
  305.  
  306.     local eventname, _, ch, code = event.pull('key_down')
  307.     if eventname == 'key_down' then
  308.       if code == keys.enter then
  309.         if CurBut==0 then CurBut=1 end
  310.         return But[CurBut],Str
  311.       elseif code == keys.left and CurBut~=0 then
  312.         if CurBut>1 then CurBut=CurBut-1 end
  313.       elseif code == keys.right and CurBut~=0 then
  314.         if CurBut<#But then CurBut=CurBut+1 end
  315.       elseif code == keys.tab then
  316.         if CurBut<#But then CurBut=CurBut+1
  317.         else CurBut=Str and 0 or 1
  318.         end
  319.       elseif code == keys.back and CurBut==0 then
  320.        if #Str>0 then gpu.set(x+1, y+H-3, string.rep(' ',W-2)) Str=sub(Str,1,-2) end
  321.       elseif ch > 0 and CurBut == 0 then
  322.         Str = Str..unicode.char(ch)
  323.       end
  324.     end
  325.   end
  326. end
  327.  
  328. local function call(func,...)
  329.   local r,e=func(...)
  330.   if not r then Dialog(AlarmWinCl,{e}) end
  331.   return r
  332. end
  333.  
  334. local function CpMv(func,from,to)
  335.   if fs.isDirectory(from) then
  336.     if not fs.exists(to) then call(fs.makeDirectory,to) end
  337.     for name in fs.list(from) do
  338.       CpMv(func,fs.concat(from,name),fs.concat(to,name))
  339.     end
  340.     if func==fs.rename then call(fs.remove,from) end
  341.   else
  342.     if fs.exists(to) then
  343.       if Dialog(AlarmWinCl,{'File already exists!',to,'Overwrite it?'},nil,{'Yes','No'})=='Yes' then
  344.         if not call(fs.remove,to) then return end
  345.       end
  346.     end
  347.     call(func,from,to)
  348.   end
  349. end
  350.  
  351. local function CopyMove(action,func)
  352.   if Active==Find then return end
  353.   Name = ((Active==Rght) and Left or Rght).Path..'/'..cmd
  354.   cmd=Active.Path..'/'..cmd
  355.   local Ok,Name=Dialog(WindowCl,{action,cmd,'to:'},Name,{'<Ok>','Cancel'})
  356.   if Ok=='<Ok>' then
  357.     if Name:find("^"..cmd) then
  358.       Dialog(AlarmWinCl,{'Cannot copy/move file to itself!'})
  359.     else
  360.       CpMv(func, cmd, Name)
  361.     end
  362.   end
  363.   ShowPanels()
  364. end
  365.  
  366. local eventKey={}
  367. eventKey[keys.up]=function()
  368.   if Active.CurLine>1 then
  369.     local Line=Active.CurLine
  370.     Active.CurLine=Line-1
  371.     if Active.CurLine<Active.Shift then
  372.       Active.Shift=Active.CurLine
  373.       Active:ShowLines()
  374.     else
  375.       Active:ShowLine(Active.CurLine)
  376.       Active:ShowLine(Line)
  377.     end
  378.     Active:ShowLast()
  379.   end
  380. end
  381.  
  382. eventKey[keys.down]=function()
  383.   if Active.CurLine<#Active.tFiles then
  384.     local Line=Active.CurLine
  385.     Active.CurLine=Active.CurLine+1
  386.     if Active.CurLine>Active.Shift+hScr-5 then
  387.       Active.Shift=Active.CurLine-hScr+5
  388.       Active:ShowLines()
  389.     else
  390.       Active:ShowLine(Active.CurLine)
  391.       Active:ShowLine(Line)
  392.     end
  393.     Active:ShowLast()
  394.   end
  395. end
  396.  
  397. eventKey[keys.left]=function()
  398.   if curpos<len(cmdstr) then curpos=curpos+1 end
  399. end
  400.  
  401. eventKey[keys.right]=function()
  402.   if curpos>0 then curpos=curpos-1 end
  403. end
  404.  
  405. eventKey[keys.tab]=function()
  406.   if Active==Find then return end
  407.   Active = (Active==Rght) and Left or Rght
  408.   shell.setWorkingDirectory(Active.Path)
  409.   ShowPanels()
  410. end
  411.  
  412. eventKey[keys.enter]=function()
  413.   local function exec(cmd)
  414.     loadScreen() scr=nil
  415.     shell.execute(cmd)
  416.     saveScreen()
  417.     ShowPanels()
  418.   end
  419.   curpos=0
  420.   if cmdstr~='' then
  421.     exec(cmdstr)
  422.     cmdstr=''
  423.     return
  424.   end
  425.   if Active==Find then
  426.     Active=Find.Last
  427.     if cmd~='..' then Active:SetPos("/"..cmd) end
  428.     ShowPanels()
  429.     return
  430.   end
  431.   if Active.tSize[Active.CurLine]=='DIR' then
  432.     if cmd=='..' then  Active:SetPos(Active.Path)
  433.     else  Active:SetPos(shell.resolve(cmd)..'/..')  end
  434.     Active:Show()
  435.   else
  436.     exec(cmd)
  437.   end
  438. end
  439.  
  440. eventKey[Ctrl+keys.enter]=function()
  441.   cmdstr=cmdstr..cmd..' '
  442. end
  443.  
  444. eventKey[Alt+keys.enter]=function()
  445.   loadScreen()
  446.   event.pull("key_down")
  447.   gpu.setResolution(wScr,hScr)
  448.   ShowPanels()
  449. end
  450.  
  451. eventKey[keys.back]=function()
  452.   if cmdstr~='' then
  453.     if curpos==0 then cmdstr=sub(cmdstr,1,-2)
  454.     else cmdstr=sub(cmdstr,1,-2-curpos)..sub(cmdstr,-curpos)
  455.     end
  456.   end
  457. end
  458.  
  459. eventKey[keys.delete]=function()
  460.   if cmdstr~='' then
  461.     if curpos>0 then
  462.       curpos=curpos-1
  463.       if curpos==0 then
  464.         cmdstr=sub(cmdstr,1,-2)
  465.       else
  466.         cmdstr=sub(cmdstr,1,-2-curpos)..sub(cmdstr,-curpos)
  467.       end
  468.     end
  469.   end
  470. end
  471.  
  472. eventKey[keys['end']]=function() curpos=0 end
  473.  
  474. eventKey[keys.home]=function() curpos=len(cmdstr) end
  475.  
  476. eventKey[keys.f1]=function()
  477.   if Active==Find then return end
  478.   Dialog(SelectCl,{
  479. "Up,Down,Tab- Navigation",
  480. 'Enter      - Change dir/run program',
  481. 'Ctrl+Enter - Insert into command line',
  482. 'Alt+Enter  - Hide panels',
  483. 'F1 - This help',
  484. 'F4 - Edit file',
  485. 'Shift+F4 - Create new file',
  486. 'F5 - Copy file/dir',
  487. 'F6 - Move file/dir',
  488. 'F7 - Create directory',
  489. 'Alt+F7 - Find file/dir',
  490. 'F8  - Delete file/dir',
  491. 'F10 - Exit from MC',left=true})
  492.   ShowPanels()
  493. end
  494.  
  495. eventKey[keys.f4]=function()
  496.   if Active.tSize[Active.CurLine]=='DIR' then
  497.     Dialog(AlarmWinCl,{'Error!', cmd, 'is not a file'})
  498.   else
  499.     SetColor(NormalCl)
  500.     term.setCursorBlink(false)
  501.     shell.execute('edit '..cmd)
  502.   end
  503.   ShowPanels()
  504. end
  505.  
  506. eventKey[Shift+keys.f4]=function()
  507.   local Ok,Name=Dialog(WindowCl,{'File name:'},'',{'<Ok>','Cancel'})
  508.   if Ok=='<Ok>' then
  509.     SetColor(NormalCl)
  510.     shell.execute('edit '..Name)
  511.   end
  512.   ShowPanels()
  513. end
  514.  
  515. eventKey[keys.f5]=function()
  516.   CopyMove('Copy file:',fs.copy)
  517. end
  518.  
  519. eventKey[keys.f6]=function()
  520.   CopyMove('Move file:',fs.rename)
  521. end
  522.  
  523. eventKey[keys.f7]=function()
  524.   if Active==Find then return end
  525.   local Ok,Name=Dialog(WindowCl,{'Directory name:'},'',{'<Ok>','Cancel'})
  526.   if Ok=='<Ok>' then
  527.     if Name=='..' or fs.exists(shell.resolve(Name)) then
  528.       ShowPanels()
  529.       Dialog(AlarmWinCl,{' File exists '})
  530.     else
  531.       fs.makeDirectory(shell.resolve(Name))
  532.     end
  533.   end
  534.   ShowPanels()
  535. end
  536.  
  537. eventKey[Alt+keys.f7]=function()
  538.   local Ok,Name=Dialog(WindowCl,{'Find file/dir:','Use ? and * for any char(s)'},'',{'<Ok>','Cancel'})
  539.   if Ok=='<Ok>' then
  540.     Find.Path=Name
  541.     Find.CurLine=1
  542.     Find.Shift=1
  543.     if Active~=Find then
  544.       Find.Last=Active
  545.       Active=Find
  546.     end
  547.     Find:GetFiles()
  548.   end
  549.   ShowPanels()
  550. end
  551.  
  552. eventKey[keys.f8]=function()
  553.   if Active==Find then return end
  554.   if Dialog(AlarmWinCl,{'Do you want to delete', cmd..'?'}, nil, {'Yes','No'})=='Yes' then
  555.     call(fs.remove,shell.resolve(cmd))
  556.   end
  557.   ShowPanels()
  558. end
  559.  
  560. eventKey[keys.f10]=function()
  561.   work=false
  562. end
  563.  
  564. NormalCl={colors.white,colors.black}
  565. if gpu.getDepth() > 1 then
  566.   PanelCl={colors.white,colors.blue}
  567.   DirCl={colors.orange,colors.blue}
  568.   SelectCl={colors.black,colors.orange}
  569.   WindowCl={colors.white,colors.green}
  570.   AlarmWinCl={colors.white,colors.red}
  571. else
  572.   PanelCl=NormalCl
  573.   DirCl=NormalCl
  574.   SelectCl={colors.black,colors.white}
  575.   WindowCl=NormalCl
  576.   AlarmWinCl=NormalCl
  577. end
  578. if wScr<80 then
  579.   Menu={'Help','','','Edit','Copy','Move','Dir','Del','','Exit'}
  580. else
  581.   Menu={' Help ','','',' Edit ',' Copy ',' Move ',' Dir  ',' Del  ','',' Exit '}
  582. end
  583. for i=1,#Menu do
  584.   if #Menu[i]>0 then xMenu=xMenu+#tostring(i)+len(Menu[i])+2 end
  585. end
  586. xMenu=math.floor((wScr-xMenu) / 2)
  587. Left =panel:new(1,'')
  588. Rght =panel:new(Left.wPan+1,shell.getWorkingDirectory():sub(1,-2))
  589. Find =Fpanel:new(1,'')
  590. Active =Rght
  591.  
  592. saveScreen()
  593. ShowPanels()
  594. ShowCmd()
  595. while work do
  596.   local eventname, _, char, code, dir = event.pull()
  597.   cmd=Active.tFiles[Active.CurLine]
  598.   if eventname =='key_down' then
  599.     if keyboard.isShiftDown() then code=code+Shift end
  600.     if keyboard.isControlDown() then code=code+Ctrl end
  601.     if keyboard.isAltDown() then code=code+Alt end
  602.     if eventKey[code] ~= nil then
  603.       SetColor(PanelCl)
  604.       eventKey[code]()
  605.       ShowCmd()
  606.     elseif char > 0 then
  607.       if curpos==0 then cmdstr=cmdstr..unicode.char(char)
  608.       else cmdstr=cmdstr:sub(1,-1-curpos)..unicode.char(char)..cmdstr:sub(-curpos)
  609.       end
  610.       ShowCmd()
  611.     end
  612.   end
  613. end
  614. loadScreen()
  615. print('Thank you for using Midday Commander!')
RAW Paste Data