Oeed

Edit

May 4th, 2013
115
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. -- Get file to edit
  2. local tArgs = { ... }
  3. if #tArgs == 0 then
  4. print( "Usage: edit <path>" )
  5. return
  6. end
  7.  
  8. -- Error checking
  9. local sPath = shell.resolve( tArgs[1] )
  10. local bReadOnly = fs.isReadOnly( sPath )
  11. if fs.exists( sPath ) and fs.isDir( sPath ) then
  12. print( "Cannot edit a directory." )
  13. return
  14. end
  15.  
  16. local x,y = 1,1
  17. local w,h = term.getSize()
  18. local scrollX, scrollY = 0,0
  19.  
  20. local tLines = {}
  21. local bRunning = true
  22.  
  23. -- Colours
  24. local highlightColour, keywordColour, commentColour, textColour, bgColour
  25. if term.isColour() then
  26. bgColour = colours.black
  27. textColour = colours.white
  28. highlightColour = colours.yellow
  29. keywordColour = colours.yellow
  30. commentColour = colours.lime
  31. stringColour = colours.red
  32. else
  33. bgColour = colours.black
  34. textColour = colours.white
  35. highlightColour = colours.white
  36. keywordColour = colours.white
  37. commentColour = colours.white
  38. stringColour = colours.white
  39. end
  40.  
  41. -- Menus
  42. local bMenu = false
  43. local nMenuItem = 1
  44. local tMenuItems = {"Save", "Exit", "Print"}
  45. local sStatus = "Press Ctrl to access menu"
  46.  
  47. local function load(_sPath)
  48. tLines = {}
  49. if fs.exists( _sPath ) then
  50. local file = io.open( _sPath, "r" )
  51. local sLine = file:read()
  52. while sLine do
  53. table.insert( tLines, sLine )
  54. sLine = file:read()
  55. end
  56. file:close()
  57. end
  58.  
  59. if #tLines == 0 then
  60. table.insert( tLines, "" )
  61. end
  62. end
  63.  
  64. local function save( _sPath )
  65. -- Create intervening folder
  66. local sDir = sPath:sub(1, sPath:len() - fs.getName(sPath):len() )
  67. if not fs.exists( sDir ) then
  68. fs.makeDir( sDir )
  69. end
  70.  
  71. -- Save
  72. local file = nil
  73. local function innerSave()
  74. file = fs.open( _sPath, "w" )
  75. if file then
  76. for n, sLine in ipairs( tLines ) do
  77. file.write( sLine .. "\n" )
  78. end
  79. else
  80. error( "Failed to open ".._sPath )
  81. end
  82. end
  83.  
  84. local ok = pcall( innerSave )
  85. if file then
  86. file.close()
  87. end
  88. return ok
  89. end
  90.  
  91. local tKeywords = {
  92. ["and"] = true,
  93. ["break"] = true,
  94. ["do"] = true,
  95. ["else"] = true,
  96. ["elseif"] = true,
  97. ["end"] = true,
  98. ["false"] = true,
  99. ["for"] = true,
  100. ["function"] = true,
  101. ["if"] = true,
  102. ["in"] = true,
  103. ["local"] = true,
  104. ["nil"] = true,
  105. ["not"] = true,
  106. ["or"] = true,
  107. ["repeat"] = true,
  108. ["return"] = true,
  109. ["then"] = true,
  110. ["true"] = true,
  111. ["until"]= true,
  112. ["while"] = true,
  113. }
  114.  
  115. local function tryWrite( sLine, regex, colour )
  116. local match = string.match( sLine, regex )
  117. if match then
  118. if type(colour) == "number" then
  119. term.setTextColour( colour )
  120. else
  121. term.setTextColour( colour(match) )
  122. end
  123. term.write( match )
  124. term.setTextColour( textColour )
  125. return string.sub( sLine, string.len(match) + 1 )
  126. end
  127. return nil
  128. end
  129.  
  130. local function writeHighlighted( sLine )
  131. while string.len(sLine) > 0 do
  132. sLine =
  133. tryWrite( sLine, "^%-%-%[%[.-%]%]", commentColour ) or
  134. tryWrite( sLine, "^%-%-.*", commentColour ) or
  135. tryWrite( sLine, "^\".-[^\\]\"", stringColour ) or
  136. tryWrite( sLine, "^\'.-[^\\]\'", stringColour ) or
  137. tryWrite( sLine, "^%[%[.-%]%]", stringColour ) or
  138. tryWrite( sLine, "^[%w_]+", function( match )
  139. if tKeywords[ match ] then
  140. return keywordColour
  141. end
  142. return textColour
  143. end ) or
  144. tryWrite( sLine, "^[^%w_]", textColour )
  145. end
  146. end
  147.  
  148. local function redrawText()
  149. for y=1,h-1 do
  150. term.setCursorPos( 1 - scrollX, y )
  151. term.clearLine()
  152.  
  153. local sLine = tLines[ y + scrollY ]
  154. if sLine ~= nil then
  155. writeHighlighted( sLine )
  156. end
  157. end
  158. term.setCursorPos( x - scrollX, y - scrollY )
  159. end
  160.  
  161. local function redrawLine(_nY)
  162. local sLine = tLines[_nY]
  163. term.setCursorPos( 1 - scrollX, _nY - scrollY )
  164. term.clearLine()
  165. writeHighlighted( sLine )
  166. term.setCursorPos( x - scrollX, _nY - scrollY )
  167. end
  168.  
  169. local function setLeftStatus()
  170. end
  171.  
  172. local function redrawMenu()
  173. term.setCursorPos( 1, h )
  174. term.clearLine()
  175.  
  176. local sLeft, sRight
  177. local nLeftColour, nLeftHighlight1, nLeftHighlight2
  178. if bMenu then
  179. local sMenu = ""
  180. for n,sItem in ipairs( tMenuItems ) do
  181. if n == nMenuItem then
  182. nLeftHighlight1 = sMenu:len() + 1
  183. nLeftHighlight2 = sMenu:len() + sItem:len() + 2
  184. end
  185. sMenu = sMenu.." "..sItem.." "
  186. end
  187. sLeft = sMenu
  188. nLeftColour = textColour
  189. else
  190. sLeft = sStatus
  191. nLeftColour = highlightColour
  192. end
  193.  
  194. -- Left goes last so that it can overwrite the line numbers.
  195. sRight = "Ln "..y
  196. term.setTextColour( highlightColour )
  197. term.setCursorPos( w-sRight:len() + 1, h )
  198. term.write(sRight)
  199.  
  200. sRight = tostring(y)
  201. term.setTextColour( textColour )
  202. term.setCursorPos( w-sRight:len() + 1, h )
  203. term.write(sRight)
  204.  
  205. if sLeft then
  206. term.setCursorPos( 1, h )
  207. term.setTextColour( nLeftColour )
  208. term.write(sLeft)
  209. if nLeftHighlight1 then
  210. term.setTextColour( highlightColour )
  211. term.setCursorPos( nLeftHighlight1, h )
  212. term.write( "[" )
  213. term.setCursorPos( nLeftHighlight2, h )
  214. term.write( "]" )
  215. end
  216. term.setTextColour( textColour )
  217. end
  218.  
  219. -- Cursor highlights selection
  220. term.setCursorPos( x - scrollX, y - scrollY )
  221. end
  222.  
  223. local tMenuFuncs = {
  224. Save=function()
  225. if bReadOnly then
  226. sStatus = "Access denied"
  227. else
  228. local ok, err = save( sPath )
  229. if ok then
  230. sStatus="Saved to "..sPath
  231. else
  232. sStatus="Error saving to "..sPath
  233. end
  234. end
  235. redrawMenu()
  236. end,
  237. Print=function()
  238. local sPrinterSide = nil
  239. for n,sName in ipairs(peripheral.getNames()) do
  240. if peripheral.isPresent(sName) and peripheral.getType(sName) == "printer" then
  241. sPrinterSide = sName
  242. break
  243. end
  244. end
  245.  
  246. if not sPrinterSide then
  247. sStatus = "No printer attached"
  248. return
  249. end
  250.  
  251. local nPage = 0
  252. local sName = fs.getName( sPath )
  253. local printer = peripheral.wrap(sPrinterSide)
  254. if printer.getInkLevel() < 1 then
  255. sStatus = "Printer out of ink"
  256. return
  257. elseif printer.getPaperLevel() < 1 then
  258. sStatus = "Printer out of paper"
  259. return
  260. end
  261.  
  262. local terminal = {
  263. getCursorPos = printer.getCursorPos,
  264. setCursorPos = printer.setCursorPos,
  265. getSize = printer.getPageSize,
  266. write = printer.write,
  267. }
  268. terminal.scroll = function()
  269. if nPage == 1 then
  270. printer.setPageTitle( sName.." (page "..nPage..")" )
  271. end
  272.  
  273. while not printer.newPage() do
  274. if printer.getInkLevel() < 1 then
  275. sStatus = "Printer out of ink, please refill"
  276. elseif printer.getPaperLevel() < 1 then
  277. sStatus = "Printer out of paper, please refill"
  278. else
  279. sStatus = "Printer output tray full, please empty"
  280. end
  281.  
  282. term.restore()
  283. redrawMenu()
  284. term.redirect( terminal )
  285.  
  286. local timer = os.startTimer(0.5)
  287. sleep(0.5)
  288. end
  289.  
  290. nPage = nPage + 1
  291. if nPage == 1 then
  292. printer.setPageTitle( sName )
  293. else
  294. printer.setPageTitle( sName.." (page "..nPage..")" )
  295. end
  296. end
  297.  
  298. bMenu = false
  299. term.redirect( terminal )
  300. local ok, error = pcall( function()
  301. term.scroll()
  302. for n, sLine in ipairs( tLines ) do
  303. print( sLine )
  304. end
  305. end )
  306. term.restore()
  307. if not ok then
  308. print( error )
  309. end
  310.  
  311. while not printer.endPage() do
  312. sStatus = "Printer output tray full, please empty"
  313. redrawMenu()
  314. sleep( 0.5 )
  315. end
  316. bMenu = true
  317.  
  318. if nPage > 1 then
  319. sStatus = "Printed "..nPage.." Pages"
  320. else
  321. sStatus = "Printed 1 Page"
  322. end
  323. redrawMenu()
  324. end,
  325. Exit=function()
  326. bRunning = false
  327. end
  328. }
  329.  
  330. local function doMenuItem( _n )
  331. tMenuFuncs[tMenuItems[_n]]()
  332. if bMenu then
  333. bMenu = false
  334. term.setCursorBlink( true )
  335. end
  336. redrawMenu()
  337. end
  338.  
  339. local function setCursor( x, y )
  340. local screenX = x - scrollX
  341. local screenY = y - scrollY
  342.  
  343. local bRedraw = false
  344. if screenX < 1 then
  345. scrollX = x - 1
  346. screenX = 1
  347. bRedraw = true
  348. elseif screenX > w then
  349. scrollX = x - w
  350. screenX = w
  351. bRedraw = true
  352. end
  353.  
  354. if screenY < 1 then
  355. scrollY = y - 1
  356. screenY = 1
  357. bRedraw = true
  358. elseif screenY > h-1 then
  359. scrollY = y - (h-1)
  360. screenY = h-1
  361. bRedraw = true
  362. end
  363.  
  364. if bRedraw then
  365. redrawText()
  366. end
  367. term.setCursorPos( screenX, screenY )
  368.  
  369. -- Statusbar now pertains to menu, it would probably be safe to redraw the menu on every key event.
  370. redrawMenu()
  371. end
  372.  
  373. -- Actual program functionality begins
  374. load(sPath)
  375.  
  376. term.setBackgroundColour( bgColour )
  377. term.clear()
  378. term.setCursorPos(x,y)
  379. term.setCursorBlink( true )
  380.  
  381. redrawText()
  382. redrawMenu()
  383.  
  384. -- Handle input
  385. while bRunning do
  386. local sEvent, param, param2, param3 = os.pullEvent()
  387. if sEvent == "key" then
  388. if param == keys.up then
  389. -- Up
  390. if not bMenu then
  391. if y > 1 then
  392. -- Move cursor up
  393. y = y - 1
  394. x = math.min( x, string.len( tLines[y] ) + 1 )
  395. setCursor( x, y )
  396. end
  397. end
  398. elseif param == keys.down then
  399. -- Down
  400. if not bMenu then
  401. -- Move cursor down
  402. if y < #tLines then
  403. y = y + 1
  404. x = math.min( x, string.len( tLines[y] ) + 1 )
  405. setCursor( x, y )
  406. end
  407. end
  408. elseif param == keys.tab then
  409. -- Tab
  410. if not bMenu then
  411. local sLine = tLines[y]
  412.  
  413. -- Indent line
  414. -- IN CASE OF INSERT TAB IN PLACE:
  415. -- tLines[y] = string.sub(sLine,1,x-1) .. " " .. string.sub(sLine,x)
  416. tLines[y]=" "..tLines[y]
  417. x = x + 2
  418. setCursor( x, y )
  419. redrawLine(y)
  420. end
  421. elseif param == keys.pageUp then
  422. -- Page Up
  423. if not bMenu then
  424. -- Move up a page
  425. local sx,sy=term.getSize()
  426. y=y-sy-1
  427. if y<1 then y=1 end
  428. x = math.min( x, string.len( tLines[y] ) + 1 )
  429. setCursor( x, y )
  430. end
  431. elseif param == keys.pageDown then
  432. -- Page Down
  433. if not bMenu then
  434. -- Move down a page
  435. local sx,sy=term.getSize()
  436. if y<#tLines-sy-1 then
  437. y = y+sy-1
  438. else
  439. y = #tLines
  440. end
  441. x = math.min( x, string.len( tLines[y] ) + 1 )
  442. setCursor( x, y )
  443. end
  444. elseif param == keys.home then
  445. -- Home
  446. if not bMenu then
  447. -- Move cursor to the beginning
  448. x=1
  449. setCursor(x,y)
  450. end
  451. elseif param == keys["end"] then
  452. -- End
  453. if not bMenu then
  454. -- Move cursor to the end
  455. x = string.len( tLines[y] ) + 1
  456. setCursor(x,y)
  457. end
  458. elseif param == keys.left then
  459. -- Left
  460. if not bMenu then
  461. if x > 1 then
  462. -- Move cursor left
  463. x = x - 1
  464. elseif x==1 and y>1 then
  465. x = string.len( tLines[y-1] ) + 1
  466. y = y - 1
  467. end
  468. setCursor( x, y )
  469. else
  470. -- Move menu left
  471. nMenuItem = nMenuItem - 1
  472. if nMenuItem < 1 then
  473. nMenuItem = #tMenuItems
  474. end
  475. redrawMenu()
  476. end
  477. elseif param == keys.right then
  478. -- Right
  479. if not bMenu then
  480. if x < string.len( tLines[y] ) + 1 then
  481. -- Move cursor right
  482. x = x + 1
  483. elseif x==string.len( tLines[y] ) + 1 and y<#tLines then
  484. x = 1
  485. y = y + 1
  486. end
  487. setCursor( x, y )
  488. else
  489. -- Move menu right
  490. nMenuItem = nMenuItem + 1
  491. if nMenuItem > #tMenuItems then
  492. nMenuItem = 1
  493. end
  494. redrawMenu()
  495. end
  496. elseif param == keys.delete then
  497. -- Delete
  498. if not bMenu then
  499. if x < string.len( tLines[y] ) + 1 then
  500. local sLine = tLines[y]
  501. tLines[y] = string.sub(sLine,1,x-1) .. string.sub(sLine,x+1)
  502. redrawLine(y)
  503. elseif y<#tLines then
  504. tLines[y] = tLines[y] .. tLines[y+1]
  505. table.remove( tLines, y+1 )
  506. redrawText()
  507. redrawMenu()
  508. end
  509. end
  510. elseif param == keys.backspace then
  511. -- Backspace
  512. if not bMenu then
  513. if x > 1 then
  514. -- Remove character
  515. local sLine = tLines[y]
  516. tLines[y] = string.sub(sLine,1,x-2) .. string.sub(sLine,x)
  517. redrawLine(y)
  518.  
  519. x = x - 1
  520. setCursor( x, y )
  521. elseif y > 1 then
  522. -- Remove newline
  523. local sPrevLen = string.len( tLines[y-1] )
  524. tLines[y-1] = tLines[y-1] .. tLines[y]
  525. table.remove( tLines, y )
  526. redrawText()
  527.  
  528. x = sPrevLen + 1
  529. y = y - 1
  530. setCursor( x, y )
  531. end
  532. end
  533. elseif param == keys.enter then
  534. -- Enter
  535. if not bMenu then
  536. -- Newline
  537. local sLine = tLines[y]
  538. local _,spaces=string.find(sLine,"^[ ]+")
  539. if not spaces then
  540. spaces=0
  541. end
  542. tLines[y] = string.sub(sLine,1,x-1)
  543. table.insert( tLines, y+1, string.rep(' ',spaces)..string.sub(sLine,x) )
  544. redrawText()
  545.  
  546. x = spaces+1
  547. y = y + 1
  548. setCursor( x, y )
  549. else
  550. -- Menu selection
  551. doMenuItem( nMenuItem )
  552. end
  553. elseif param == keys.leftCtrl or param == keys.rightCtrl then
  554. -- Menu toggle
  555. bMenu = not bMenu
  556. if bMenu then
  557. term.setCursorBlink( false )
  558. nMenuItem = 1
  559. else
  560. term.setCursorBlink( true )
  561. end
  562. redrawMenu()
  563. end
  564.  
  565. elseif sEvent == "char" then
  566. if not bMenu then
  567. -- Input text
  568. local sLine = tLines[y]
  569. tLines[y] = string.sub(sLine,1,x-1) .. param .. string.sub(sLine,x)
  570. redrawLine(y)
  571.  
  572. x = x + string.len( param )
  573. setCursor( x, y )
  574. else
  575. -- Select menu items
  576. for n,sMenuItem in ipairs( tMenuItems ) do
  577. if string.lower(string.sub(sMenuItem,1,1)) == string.lower(param) then
  578. doMenuItem( n )
  579. break
  580. end
  581. end
  582. end
  583.  
  584. elseif sEvent == "mouse_click" then
  585. if not bMenu then
  586. if param == 1 then
  587. -- Left click
  588. local cx,cy = param2, param3
  589. if cy < h then
  590. y = math.min( math.max( scrollY + cy, 1 ), #tLines )
  591. x = math.min( math.max( scrollX + cx, 1 ), string.len( tLines[y] ) + 1 )
  592. setCursor( x, y )
  593. end
  594. end
  595. end
  596.  
  597. elseif sEvent == "mouse_scroll" then
  598. if not bMenu then
  599. if param == -1 then
  600. -- Scroll up
  601. if scrollY > 0 then
  602. -- Move cursor up
  603. scrollY = scrollY - 1
  604. redrawText()
  605. end
  606.  
  607. elseif param == 1 then
  608. -- Scroll down
  609. local nMaxScroll = #tLines - (h-1)
  610. if scrollY < nMaxScroll then
  611. -- Move cursor down
  612. scrollY = scrollY + 1
  613. redrawText()
  614. end
  615.  
  616. end
  617. end
  618. end
  619. end
  620.  
  621. -- Cleanup
  622. term.clear()
  623. term.setCursorBlink( false )
  624. term.setCursorPos( 1, 1 )
RAW Paste Data