kd2bwzgen

Edit template

Jul 2nd, 2017
401
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 17.47 KB | None | 0 0
  1. -- Get file to edit
  2. local tArgs = { ... }
  3. if #tArgs == 0 then
  4. print( "Usage: "..fs.getName(shell.getRunningProgram()).." <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. if not settings then
  16. _G.settings = {}
  17. settings.get = function(s) return false end
  18. end
  19.  
  20. local x,y = 1,1
  21. local w,h = term.getSize()
  22. local scrollX, scrollY = 0,0
  23. local bRunOption = true
  24.  
  25. local tLines = {}
  26. local bRunning = true
  27.  
  28. -- Colours
  29. local highlightColour, keywordColour, commentColour, textColour, bgColour, stringColour
  30. if term.isColour() then
  31. bgColour = colours.black
  32. textColour = colours.white
  33. highlightColour = colours.yellow
  34. keywordColour = colours.yellow
  35. commentColour = colours.green
  36. stringColour = colours.red
  37. else
  38. bgColour = colours.black
  39. textColour = colours.white
  40. highlightColour = colours.white
  41. keywordColour = colours.white
  42. commentColour = colours.white
  43. stringColour = colours.white
  44. end
  45.  
  46. -- Menus
  47. local bMenu = false
  48. local nMenuItem = 1
  49. local tMenuItems = {}
  50. if not bReadOnly then
  51. table.insert( tMenuItems, "Save" )
  52. end
  53. if shell.openTab and bRunOption then
  54. table.insert( tMenuItems, "Run" )
  55. end
  56. if peripheral.find( "printer" ) then
  57. table.insert( tMenuItems, "Print" )
  58. end
  59. table.insert( tMenuItems, "Exit" )
  60.  
  61. local sStatus = "Press Ctrl to access menu"
  62. if string.len( sStatus ) > w - 5 then
  63. sStatus = "Press Ctrl for menu"
  64. end
  65.  
  66. local function load( _sPath )
  67. tLines = {}
  68. if fs.exists( _sPath ) then
  69. local file = io.open( _sPath, "r" )
  70. local sLine = file:read()
  71. while sLine do
  72. table.insert( tLines, sLine )
  73. sLine = file:read()
  74. end
  75. file:close()
  76. end
  77.  
  78. if #tLines == 0 then
  79. table.insert( tLines, "" )
  80. end
  81. end
  82.  
  83. local function save( _sPath )
  84. -- Create intervening folder
  85. local sDir = _sPath:sub(1, _sPath:len() - fs.getName(_sPath):len() )
  86. if not fs.exists( sDir ) then
  87. fs.makeDir( sDir )
  88. end
  89.  
  90. -- Save
  91. local file = nil
  92. local function innerSave()
  93. file = fs.open( _sPath, "w" )
  94. if file then
  95. for n, sLine in ipairs( tLines ) do
  96. file.write( sLine .. "\n" )
  97. end
  98. else
  99. error( "Failed to open ".._sPath )
  100. end
  101. end
  102.  
  103. local ok, err = pcall( innerSave )
  104. if file then
  105. file.close()
  106. end
  107. return ok, err
  108. end
  109.  
  110. local tKeywords = {
  111. ["testkey"] = true
  112. }
  113.  
  114. local function tryWrite( sLine, regex, colour )
  115. local match = string.match( sLine, regex )
  116. if match then
  117. if type(colour) == "number" then
  118. term.setTextColour( colour )
  119. else
  120. term.setTextColour( colour(match) )
  121. end
  122. term.write( match )
  123. term.setTextColour( textColour )
  124. return string.sub( sLine, string.len(match) + 1 )
  125. end
  126. return nil
  127. end
  128.  
  129. local function writeHighlighted( sLine )
  130. while string.len(sLine) > 0 do
  131. sLine =
  132. tryWrite( sLine, "^%-%-%[%[.-%]%]", commentColour ) or
  133. tryWrite( sLine, "^%-%-.*", commentColour ) or
  134. tryWrite( sLine, "^\"\"", stringColour ) or
  135. tryWrite( sLine, "^\".-[^\\]\"", stringColour ) or
  136. tryWrite( sLine, "^\'\'", stringColour ) or
  137. tryWrite( sLine, "^\'.-[^\\]\'", stringColour ) or
  138. tryWrite( sLine, "^%[%[.-%]%]", stringColour ) or
  139. tryWrite( sLine, "^[%w_]+", function( match )
  140. if tKeywords[ match ] then
  141. return keywordColour
  142. end
  143. return textColour
  144. end ) or
  145. tryWrite( sLine, "^[^%w_]", textColour )
  146. end
  147. end
  148.  
  149. local tCompletions
  150. local nCompletion
  151.  
  152. local tCompleteEnv = {}
  153. for k,v in pairs(tKeywords) do table.insert(tCompleteEnv,k) end
  154. local function complete( sLine )
  155. if settings.get( "edit.autocomplete" ) then
  156. local nStartPos = string.find( sLine, "[a-zA-Z0-9_%.]+$" )
  157. if nStartPos then
  158. sLine = string.sub( sLine, nStartPos )
  159. end
  160. if #sLine > 0 then
  161. return textutils.complete( sLine, tCompleteEnv )
  162. end
  163. end
  164. return nil
  165. end
  166.  
  167. local function recomplete()
  168. local sLine = tLines[y]
  169. if not bMenu and not bReadOnly and x == string.len(sLine) + 1 then
  170. tCompletions = complete( sLine )
  171. if tCompletions and #tCompletions > 0 then
  172. nCompletion = 1
  173. else
  174. nCompletion = nil
  175. end
  176. else
  177. tCompletions = nil
  178. nCompletion = nil
  179. end
  180. end
  181.  
  182. local function writeCompletion( sLine )
  183. if nCompletion then
  184. local sCompletion = tCompletions[ nCompletion ]
  185. term.setTextColor( colours.white )
  186. term.setBackgroundColor( colours.grey )
  187. term.write( sCompletion )
  188. term.setTextColor( textColour )
  189. term.setBackgroundColor( bgColour )
  190. end
  191. end
  192.  
  193. local function redrawText()
  194. local cursorX, cursorY = x, y
  195. for y=1,h-1 do
  196. term.setCursorPos( 1 - scrollX, y )
  197. term.clearLine()
  198.  
  199. local sLine = tLines[ y + scrollY ]
  200. if sLine ~= nil then
  201. writeHighlighted( sLine )
  202. if cursorY == y and cursorX == #sLine + 1 then
  203. writeCompletion()
  204. end
  205. end
  206. end
  207. term.setCursorPos( x - scrollX, y - scrollY )
  208. end
  209.  
  210. local function redrawLine(_nY)
  211. local sLine = tLines[_nY]
  212. if sLine then
  213. term.setCursorPos( 1 - scrollX, _nY - scrollY )
  214. term.clearLine()
  215. writeHighlighted( sLine )
  216. if _nY == y and x == #sLine + 1 then
  217. writeCompletion()
  218. end
  219. term.setCursorPos( x - scrollX, _nY - scrollY )
  220. end
  221. end
  222.  
  223. local function redrawMenu()
  224. -- Clear line
  225. term.setCursorPos( 1, h )
  226. term.clearLine()
  227.  
  228. -- Draw line numbers
  229. term.setCursorPos( w - string.len( "Ln "..y ) + 1, h )
  230. term.setTextColour( highlightColour )
  231. term.write( "Ln " )
  232. term.setTextColour( textColour )
  233. term.write( y )
  234.  
  235. term.setCursorPos( 1, h )
  236. if bMenu then
  237. -- Draw menu
  238. term.setTextColour( textColour )
  239. for nItem,sItem in pairs( tMenuItems ) do
  240. if nItem == nMenuItem then
  241. term.setTextColour( highlightColour )
  242. term.write( "[" )
  243. term.setTextColour( textColour )
  244. term.write( sItem )
  245. term.setTextColour( highlightColour )
  246. term.write( "]" )
  247. term.setTextColour( textColour )
  248. else
  249. term.write( " "..sItem.." " )
  250. end
  251. end
  252. else
  253. -- Draw status
  254. term.setTextColour( highlightColour )
  255. term.write( sStatus )
  256. term.setTextColour( textColour )
  257. end
  258.  
  259. -- Reset cursor
  260. term.setCursorPos( x - scrollX, y - scrollY )
  261. end
  262.  
  263. local tMenuFuncs = {
  264. Save = function()
  265. if bReadOnly then
  266. sStatus = "Access denied"
  267. else
  268. local ok, err = save( sPath )
  269. if ok then
  270. sStatus="Saved to "..sPath
  271. else
  272. sStatus="Error saving to "..sPath
  273. end
  274. end
  275. redrawMenu()
  276. end,
  277. Print = function()
  278. local printer = peripheral.find( "printer" )
  279. if not printer then
  280. sStatus = "No printer attached"
  281. return
  282. end
  283.  
  284. local nPage = 0
  285. local sName = fs.getName( sPath )
  286. if printer.getInkLevel() < 1 then
  287. sStatus = "Printer out of ink"
  288. return
  289. elseif printer.getPaperLevel() < 1 then
  290. sStatus = "Printer out of paper"
  291. return
  292. end
  293.  
  294. local screenTerminal = term.current()
  295. local printerTerminal = {
  296. getCursorPos = printer.getCursorPos,
  297. setCursorPos = printer.setCursorPos,
  298. getSize = printer.getPageSize,
  299. write = printer.write,
  300. }
  301. printerTerminal.scroll = function()
  302. if nPage == 1 then
  303. printer.setPageTitle( sName.." (page "..nPage..")" )
  304. end
  305.  
  306. while not printer.newPage() do
  307. if printer.getInkLevel() < 1 then
  308. sStatus = "Printer out of ink, please refill"
  309. elseif printer.getPaperLevel() < 1 then
  310. sStatus = "Printer out of paper, please refill"
  311. else
  312. sStatus = "Printer output tray full, please empty"
  313. end
  314.  
  315. term.redirect( screenTerminal )
  316. redrawMenu()
  317. term.redirect( printerTerminal )
  318.  
  319. local timer = os.startTimer(0.5)
  320. sleep(0.5)
  321. end
  322.  
  323. nPage = nPage + 1
  324. if nPage == 1 then
  325. printer.setPageTitle( sName )
  326. else
  327. printer.setPageTitle( sName.." (page "..nPage..")" )
  328. end
  329. end
  330.  
  331. bMenu = false
  332. term.redirect( printerTerminal )
  333. local ok, error = pcall( function()
  334. term.scroll()
  335. for n, sLine in ipairs( tLines ) do
  336. print( sLine )
  337. end
  338. end )
  339. term.redirect( screenTerminal )
  340. if not ok then
  341. print( error )
  342. end
  343.  
  344. while not printer.endPage() do
  345. sStatus = "Printer output tray full, please empty"
  346. redrawMenu()
  347. sleep( 0.5 )
  348. end
  349. bMenu = true
  350.  
  351. if nPage > 1 then
  352. sStatus = "Printed "..nPage.." Pages"
  353. else
  354. sStatus = "Printed 1 Page"
  355. end
  356. redrawMenu()
  357. end,
  358. Exit = function()
  359. bRunning = false
  360. end,
  361. Run = function()
  362. local sTempPath = "/.temp"
  363. local ok, err = save( sTempPath )
  364. if ok then
  365. local nTask = shell.openTab( sTempPath )
  366. if nTask then
  367. shell.switchTab( nTask )
  368. else
  369. sStatus="Error starting Task"
  370. end
  371. fs.delete( sTempPath )
  372. else
  373. sStatus="Error saving to "..sTempPath
  374. end
  375. redrawMenu()
  376. end
  377. }
  378.  
  379. local function doMenuItem( _n )
  380. tMenuFuncs[tMenuItems[_n]]()
  381. if bMenu then
  382. bMenu = false
  383. term.setCursorBlink( true )
  384. end
  385. redrawMenu()
  386. end
  387.  
  388. local function setCursor( newX, newY )
  389. local oldX, oldY = x, y
  390. x, y = newX, newY
  391. local screenX = x - scrollX
  392. local screenY = y - scrollY
  393.  
  394. local bRedraw = false
  395. if screenX < 1 then
  396. scrollX = x - 1
  397. screenX = 1
  398. bRedraw = true
  399. elseif screenX > w then
  400. scrollX = x - w
  401. screenX = w
  402. bRedraw = true
  403. end
  404.  
  405. if screenY < 1 then
  406. scrollY = y - 1
  407. screenY = 1
  408. bRedraw = true
  409. elseif screenY > h-1 then
  410. scrollY = y - (h-1)
  411. screenY = h-1
  412. bRedraw = true
  413. end
  414.  
  415. recomplete()
  416. if bRedraw then
  417. redrawText()
  418. elseif y ~= oldY then
  419. redrawLine( oldY )
  420. redrawLine( y )
  421. else
  422. redrawLine( y )
  423. end
  424. term.setCursorPos( screenX, screenY )
  425.  
  426. redrawMenu()
  427. end
  428.  
  429. -- Actual program functionality begins
  430. load(sPath)
  431.  
  432. term.setBackgroundColour( bgColour )
  433. term.clear()
  434. term.setCursorPos(x,y)
  435. term.setCursorBlink( true )
  436.  
  437. recomplete()
  438. redrawText()
  439. redrawMenu()
  440.  
  441. local function acceptCompletion()
  442. if nCompletion then
  443. -- Append the completion
  444. local sCompletion = tCompletions[ nCompletion ]
  445. tLines[y] = tLines[y] .. sCompletion
  446. setCursor( x + string.len( sCompletion ), y )
  447. end
  448. end
  449.  
  450. -- Handle input
  451. while bRunning do
  452. local sEvent, param, param2, param3 = os.pullEvent()
  453. if sEvent == "key" then
  454. local oldX, oldY = x, y
  455. if param == keys.up then
  456. -- Up
  457. if not bMenu then
  458. if nCompletion then
  459. -- Cycle completions
  460. nCompletion = nCompletion - 1
  461. if nCompletion < 1 then
  462. nCompletion = #tCompletions
  463. end
  464. redrawLine(y)
  465.  
  466. elseif y > 1 then
  467. -- Move cursor up
  468. setCursor(
  469. math.min( x, string.len( tLines[y - 1] ) + 1 ),
  470. y - 1
  471. )
  472. end
  473. end
  474.  
  475. elseif param == keys.down then
  476. -- Down
  477. if not bMenu then
  478. -- Move cursor down
  479. if nCompletion then
  480. -- Cycle completions
  481. nCompletion = nCompletion + 1
  482. if nCompletion > #tCompletions then
  483. nCompletion = 1
  484. end
  485. redrawLine(y)
  486.  
  487. elseif y < #tLines then
  488. -- Move cursor down
  489. setCursor(
  490. math.min( x, string.len( tLines[y + 1] ) + 1 ),
  491. y + 1
  492. )
  493. end
  494. end
  495.  
  496. elseif param == keys.tab then
  497. -- Tab
  498. if not bMenu and not bReadOnly then
  499. if nCompletion and x == string.len(tLines[y]) + 1 then
  500. -- Accept autocomplete
  501. acceptCompletion()
  502. else
  503. -- Indent line
  504. local sLine = tLines[y]
  505. tLines[y] = string.sub(sLine,1,x-1) .. " " .. string.sub(sLine,x)
  506. setCursor( x + 2, y )
  507. end
  508. end
  509.  
  510. elseif param == keys.pageUp then
  511. -- Page Up
  512. if not bMenu then
  513. -- Move up a page
  514. local newY
  515. if y - (h - 1) >= 1 then
  516. newY = y - (h - 1)
  517. else
  518. newY = 1
  519. end
  520. setCursor(
  521. math.min( x, string.len( tLines[newY] ) + 1 ),
  522. newY
  523. )
  524. end
  525.  
  526. elseif param == keys.pageDown then
  527. -- Page Down
  528. if not bMenu then
  529. -- Move down a page
  530. local newY
  531. if y + (h - 1) <= #tLines then
  532. newY = y + (h - 1)
  533. else
  534. newY = #tLines
  535. end
  536. local newX = math.min( x, string.len( tLines[newY] ) + 1 )
  537. setCursor( newX, newY )
  538. end
  539.  
  540. elseif param == keys.home then
  541. -- Home
  542. if not bMenu then
  543. -- Move cursor to the beginning
  544. if x > 1 then
  545. setCursor(1,y)
  546. end
  547. end
  548.  
  549. elseif param == keys["end"] then
  550. -- End
  551. if not bMenu then
  552. -- Move cursor to the end
  553. local nLimit = string.len( tLines[y] ) + 1
  554. if x < nLimit then
  555. setCursor( nLimit, y )
  556. end
  557. end
  558.  
  559. elseif param == keys.left then
  560. -- Left
  561. if not bMenu then
  562. if x > 1 then
  563. -- Move cursor left
  564. setCursor( x - 1, y )
  565. elseif x==1 and y>1 then
  566. setCursor( string.len( tLines[y-1] ) + 1, y - 1 )
  567. end
  568. else
  569. -- Move menu left
  570. nMenuItem = nMenuItem - 1
  571. if nMenuItem < 1 then
  572. nMenuItem = #tMenuItems
  573. end
  574. redrawMenu()
  575. end
  576.  
  577. elseif param == keys.right then
  578. -- Right
  579. if not bMenu then
  580. local nLimit = string.len( tLines[y] ) + 1
  581. if x < nLimit then
  582. -- Move cursor right
  583. setCursor( x + 1, y )
  584. elseif nCompletion and x == string.len(tLines[y]) + 1 then
  585. -- Accept autocomplete
  586. acceptCompletion()
  587. elseif x==nLimit and y<#tLines then
  588. -- Go to next line
  589. setCursor( 1, y + 1 )
  590. end
  591. else
  592. -- Move menu right
  593. nMenuItem = nMenuItem + 1
  594. if nMenuItem > #tMenuItems then
  595. nMenuItem = 1
  596. end
  597. redrawMenu()
  598. end
  599.  
  600. elseif param == keys.delete then
  601. -- Delete
  602. if not bMenu and not bReadOnly then
  603. local nLimit = string.len( tLines[y] ) + 1
  604. if x < nLimit then
  605. local sLine = tLines[y]
  606. tLines[y] = string.sub(sLine,1,x-1) .. string.sub(sLine,x+1)
  607. recomplete()
  608. redrawLine(y)
  609. elseif y<#tLines then
  610. tLines[y] = tLines[y] .. tLines[y+1]
  611. table.remove( tLines, y+1 )
  612. recomplete()
  613. redrawText()
  614. end
  615. end
  616.  
  617. elseif param == keys.backspace then
  618. -- Backspace
  619. if not bMenu and not bReadOnly then
  620. if x > 1 then
  621. -- Remove character
  622. local sLine = tLines[y]
  623. tLines[y] = string.sub(sLine,1,x-2) .. string.sub(sLine,x)
  624. setCursor( x - 1, y )
  625. elseif y > 1 then
  626. -- Remove newline
  627. local sPrevLen = string.len( tLines[y-1] )
  628. tLines[y-1] = tLines[y-1] .. tLines[y]
  629. table.remove( tLines, y )
  630. setCursor( sPrevLen + 1, y - 1 )
  631. redrawText()
  632. end
  633. end
  634.  
  635. elseif param == keys.enter then
  636. -- Enter
  637. if not bMenu and not bReadOnly then
  638. -- Newline
  639. local sLine = tLines[y]
  640. local _,spaces=string.find(sLine,"^[ ]+")
  641. if not spaces then
  642. spaces=0
  643. end
  644. tLines[y] = string.sub(sLine,1,x-1)
  645. table.insert( tLines, y+1, string.rep(' ',spaces)..string.sub(sLine,x) )
  646. setCursor( spaces + 1, y + 1 )
  647. redrawText()
  648.  
  649. elseif bMenu then
  650. -- Menu selection
  651. doMenuItem( nMenuItem )
  652.  
  653. end
  654.  
  655. elseif param == keys.leftCtrl or param == keys.rightCtrl or param == keys.rightAlt then
  656. -- Menu toggle
  657. bMenu = not bMenu
  658. if bMenu then
  659. term.setCursorBlink( false )
  660. else
  661. term.setCursorBlink( true )
  662. end
  663. redrawMenu()
  664.  
  665. end
  666.  
  667. elseif sEvent == "char" then
  668. if not bMenu and not bReadOnly then
  669. -- Input text
  670. local sLine = tLines[y]
  671. tLines[y] = string.sub(sLine,1,x-1) .. param .. string.sub(sLine,x)
  672. setCursor( x + 1, y )
  673.  
  674. elseif bMenu then
  675. -- Select menu items
  676. for n,sMenuItem in ipairs( tMenuItems ) do
  677. if string.lower(string.sub(sMenuItem,1,1)) == string.lower(param) then
  678. doMenuItem( n )
  679. break
  680. end
  681. end
  682. end
  683.  
  684. elseif sEvent == "paste" then
  685. if not bMenu and not bReadOnly then
  686. -- Input text
  687. local sLine = tLines[y]
  688. tLines[y] = string.sub(sLine,1,x-1) .. param .. string.sub(sLine,x)
  689. setCursor( x + string.len( param ), y )
  690. end
  691.  
  692. elseif sEvent == "mouse_click" then
  693. if not bMenu then
  694. if param == 1 then
  695. -- Left click
  696. local cx,cy = param2, param3
  697. if cy < h then
  698. local newY = math.min( math.max( scrollY + cy, 1 ), #tLines )
  699. local newX = math.min( math.max( scrollX + cx, 1 ), string.len( tLines[newY] ) + 1 )
  700. setCursor( newX, newY )
  701. end
  702. end
  703. end
  704.  
  705. elseif sEvent == "mouse_scroll" then
  706. if not bMenu then
  707. if param == -1 then
  708. -- Scroll up
  709. if scrollY > 0 then
  710. -- Move cursor up
  711. scrollY = scrollY - 1
  712. redrawText()
  713. end
  714.  
  715. elseif param == 1 then
  716. -- Scroll down
  717. local nMaxScroll = #tLines - (h-1)
  718. if scrollY < nMaxScroll then
  719. -- Move cursor down
  720. scrollY = scrollY + 1
  721. redrawText()
  722. end
  723.  
  724. end
  725. end
  726.  
  727. elseif sEvent == "term_resize" then
  728. w,h = term.getSize()
  729. setCursor( x, y )
  730. redrawMenu()
  731. redrawText()
  732.  
  733. end
  734. end
  735.  
  736. -- Cleanup
  737. term.clear()
  738. term.setCursorBlink( false )
  739. term.setCursorPos( 1, 1 )
Advertisement
Add Comment
Please, Sign In to add comment