Advertisement
MoonlightOwl

Midday Commander (OC Port)

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