CobraOs

textedit 2

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