This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
chuzuki's profile picture

Improved Edit

Started by chuzuki, 27 February 2012 - 11:14 PM
chuzuki #1
Posted 28 February 2012 - 12:14 AM
This is my direct replacement for the standard edit program.

Changes:
  • Autoindent. Currently just copies the previous line's indentation.
  • Added delete key.
  • Added "Save & Exit" to Ctrl menu.
  • Line numbering, vim style. Helps a ton with debugging.
  • Home/End/PageUp/PageDown added
Spoiler


local tArgs = { ... }
if #tArgs == 0 then
   print( "Usage: edit <path>" )
   return
end

local sPath = shell.resolve( tArgs[1] )
local bReadOnly = fs.isReadOnly( sPath )
if fs.exists( sPath ) and fs.isDir( sPath ) then
   print( "Cannot edit a directory" )
   return
end

local w,h = term.getSize()
local x,y = 1,1
local scrollX, scrollY = 0,0

local bMenu = false
local nMenuItem = 1

local sStatus = ""
local tLines = {}

local function load()
   tLines = {}
   if fs.exists( sPath ) then
      local file = io.open( sPath, "r" )
      local sLine = file:read()
      while sLine do
         table.insert( tLines, sLine )
         sLine = file:read()
      end
      file:close()
   else
      table.insert( tLines, "" )
   end
end

local function save()
   local file = io.open( sPath, "w" )
   if file then
      for n, sLine in ipairs( tLines ) do
         file:write( sLine .. "n" )
      end
   file:close()
   return true
   end
   return false
end

local function redrawText()
   for y=1,h-1 do
      term.setCursorPos( 1 - scrollX, y )
      term.clearLine()

      local sLine = tLines[ y + scrollY ]
      if sLine ~= nil then
         term.write( sLine )
      end
   end
   term.setCursorPos( x - scrollX, y - scrollY )
end

local function redrawLine()
   local sLine = tLines[y]
   term.setCursorPos( 1 - scrollX, y - scrollY )
   term.clearLine()
   term.write( sLine )
   term.setCursorPos( x - scrollX, y - scrollY )
end

local tMenuItems = { "Save &amp; Exit", "Save", "Exit" }

local function redrawMenu()
   term.setCursorPos( 1, h )
   term.clearLine()

   if not bMenu then
      term.write( sStatus )
   else
      for n,sItem in ipairs( tMenuItems ) do
         if n == nMenuItem then
            term.write( "["..sItem.."]" )
         else
            term.write( " "..sItem.." " )
         end
      end
   end

   term.setCursorPos( x - scrollX, y - scrollY )
end

local function setStatus( _sText )
   sStatus = _sText
   redrawMenu()
end

local function setCursor( x, y )
   local screenX = x - scrollX
   local screenY = y - scrollY

   local bRedraw = false
   if screenX < 1 then
      scrollX = x - 1
      screenX = 1
      bRedraw = true
   elseif screenX > w then
      scrollX = x - w
      screenX = w
      bRedraw = true
   end

   if screenY < 1 then
      scrollY = y - 1
      screenY = 1
      bRedraw = true
   elseif screenY > h-1 then
      scrollY = y - (h-1)
      screenY = h-1
      bRedraw = true
   end

   if bRedraw then
      redrawText()
   end
   term.setCursorPos( screenX, screenY )
   setStatus( string.format('Menu:Ctrl "%s" %uL %u,%u', tArgs[1], #tLines, y, x ) )
end

load()

term.clear()
term.setCursorPos(x,y)
term.setCursorBlink( true )

redrawText()
setStatus( string.format('Menu:Ctrl "%s" %uL %u,%u', tArgs[1], #tLines, y, x ) )

local bRunning = true
local tMenuFunctions = {
   ["Save &amp; Exit"] = function()
      if save() then
         setStatus( "Saved to "..sPath )
         bRunning = false
      else
         setStatus( "Access denied" )
      end
   end,
   ["Exit"] = function()
      bRunning = false
   end,
   ["Save"] = function()
      if save() then
         setStatus( "Saved to "..sPath )
      else
         setStatus( "Access denied" )
      end
   end,
}

local function doMenuItem( _n )
   local fnMenu = tMenuFunctions[ tMenuItems[_n] ]
   if fnMenu then
      fnMenu()
   end

   bMenu = false
   term.setCursorBlink( true )
   redrawMenu()
end

while bRunning do
   local sEvent, param = os.pullEvent()
   if sEvent == "key" then
      if param == 200 then
      -- Up
         if not bMenu then
         -- Move cursor up
            if y > 1 then
               y = y - 1
               x = math.min( x, string.len( tLines[y] ) + 1 )
               setCursor( x, y )
            end
         end

      elseif param == 208 then
      -- Down
         if not bMenu then
         -- Move cursor down
            if y < #tLines then
               y = y + 1
               x = math.min( x, string.len( tLines[y] ) + 1 )
               setCursor( x, y )
            end
         end

      elseif param == 203 then
      -- Left
         if not bMenu then
         -- Move cursor left
            if x > 1 then
               len = string.len( tLines[y] ) + 1
               if x > len then
                  x = len 
               else
                  x = x - 1
               end
               setCursor( x, y )
            end
         else
         -- Move menu left
            nMenuItem = nMenuItem - 1
            if nMenuItem < 1 then
               nMenuItem = #tMenuItems
            end
            redrawMenu()
         end

      elseif param == 205 then
      -- Right
         if not bMenu then
         -- Move cursor right
            if x >= string.len( tLines[y] ) + 1 then
               x = string.len( tLines[y] ) + 1
            else
               x = x + 1
            end
            setCursor( x, y )
         else
         -- Move menu right
            nMenuItem = nMenuItem + 1
            if nMenuItem > #tMenuItems then
               nMenuItem = 1
            end
            redrawMenu()
         end

      elseif param == 199 then
      -- Home
         if not bMenu then
            -- Move cursor to x=1
            x = 1
            setCursor( x, y )
         end

      elseif param == 207 then
      -- End
         if not bMenu then
            -- Move cursor to x=len
            x = string.len( tLines[y] ) + 1
            setCursor( x, y )
         end

      elseif param == 201 then
      -- Page Up
         if not bMenu then
         -- Move cursor up term.height
            w,h = term.getSize()
            y = y - h + 1
            if y < 1 then y = 1 end
            x = math.min( x, string.len( tLines[y] ) + 1 )
            setCursor( x, y )
         end

      elseif param == 209 then
      -- Page Down
         if not bMenu then
         -- Move cursor down term.height
            w,h = term.getSize()
            y = y + h - 1
            if y > #tLines then y = #tLines end
            x = math.min( x, string.len( tLines[y] ) + 1 )
            setCursor( x, y )
         end

      elseif param == 14 then
      -- Backspace
         if not bMenu then
            if x > 1 then
            -- Remove character
               local sLine = tLines[y]
               tLines[y] = string.sub(sLine,1,x-2) .. string.sub(sLine,x)
               redrawLine()

               x = x - 1
               setCursor( x, y )

            elseif y > 1 then
            -- Remove newline
               local sPrevLen = string.len( tLines[y-1] )
               tLines[y-1] = tLines[y-1] .. tLines[y]
               table.remove( tLines, y )
               redrawText()

               x = sPrevLen + 1
               y = y - 1
               setCursor( x, y )
            end
         end

      elseif param == 211 then
      -- Delete
         if not bMenu then
            if x <= string.len(tLines[y]) then
            -- Remove character
               local sLine = tLines[y]
               tLines[y] = string.sub(sLine,1,x-1) .. string.sub(sLine,x+1)
               redrawLine()

            elseif y < #tLines then
            -- Remove newline
               local sPrevLen = string.len( tLines[y] )
               tLines[y] = tLines[y] .. tLines[y+1]
               table.remove( tLines, y+1 )
               redrawText()

               x = sPrevLen + 1
               setCursor( x, y )
            end
         end

      elseif param == 28 then
      -- Enter
         if not bMenu then
         -- Newline
            local sLine = tLines[y]
            local sPrevTab = string.match( sLine, "%s+" )
            term.write(sPrevTab)
            tLines[y] = string.sub(sLine,1,x-1)
            if sPrevTab == nil then
               table.insert( tLines, y+1, string.sub(sLine,x) )
               x = 1
            else
               table.insert( tLines, y+1, sPrevTab .. string.sub(sLine,x) )
               x = #tLines[y+1]+1
            end
            redrawText()

            y = y + 1
            setCursor( x, y ) 

         else
         -- Menu selection
            doMenuItem( nMenuItem )
         end

      elseif param == 29 then
      -- Menu toggle
         bMenu = not bMenu
         if bMenu then
            term.setCursorBlink( false )
            nMenuItem = 1
         else
            term.setCursorBlink( true )
         end
         redrawMenu()
      end

  elseif sEvent == "char" then
      if not bMenu then
     -- Input text
         local sLine = tLines[y]
         tLines[y] = string.sub(sLine,1,x-1) .. param .. string.sub(sLine,x)
         redrawLine()

         x = x + string.len( param )
         setCursor( x, y )

      else
      -- Select menu items
         for n,sMenuItem in ipairs( tMenuItems ) do
            if string.lower(string.sub(sMenuItem,1,1)) == string.lower(param) then
               doMenuItem( n )
               break
            end
         end
      end
  end
end

term.clear()
term.setCursorBlink( false )
term.setCursorPos( 1, 1 )

Suggestions are welcome, and the ComputerCraft team can certainly steal this since it's 90% their code anyways.
Casper7526 #2
Posted 28 February 2012 - 12:19 AM
End/Home/Page-Up/Page-Down/Tab Key

Aha, I got ya thinking now huh?
FuzzyPurp #3
Posted 28 February 2012 - 12:42 AM
Sweet and i 2nd the home, end, pgUp and pgDn keys <_</>/>
chuzuki #4
Posted 28 February 2012 - 12:42 AM
Yeah I thought about end/home/pgup/pgdn, which wouldn't be hard to do. I'll go add it now.

Tab completion in edit is less important than in shell, which I'm also working on. Unless you had a different use for tab in mind?
Casper7526 #5
Posted 28 February 2012 - 12:43 AM
Not tab completion, but just literally tab (not sure if thats in normal edit as I don't use it)

Tab completion would be cool though and is possible
chuzuki #6
Posted 28 February 2012 - 01:11 AM
Oh, I use spaces, not tabs so it's never come up. I'll see what I can do with it.

Updated OP with Home/End/PageUp/PageDown.
FuzzyPurp #7
Posted 28 February 2012 - 03:43 AM
Sweet
Casper7526 #8
Posted 28 February 2012 - 03:44 AM
Heh all that is left that I could think of would be a auto-completion system and tab to prepend 5 spaces to the current x,y
Zer0t3ch #9
Posted 15 March 2012 - 03:50 AM
looks good. Ill install it on my server later!
petrus4 #10
Posted 15 March 2012 - 06:04 AM
If I was a genuine programmer I'd write us an ed port; but I'm not, unfortunately. :D/>/>
mrgreaper #11
Posted 15 March 2012 - 06:03 PM
ctrl+v <<<< this please please please please :D/>/>
Mads #12
Posted 04 April 2012 - 08:06 AM
ctrl+v <<<< this please please please please :)/>/>
We can't access the clipboard in Computercraft, so that is unfortunately not possible:(
Luanub #13
Posted 04 April 2012 - 08:16 AM
ctrl+v <<<< this please please please please :)/>/>
We can't access the clipboard in Computercraft, so that is unfortunately not possible:(

ctrl+v / paste will work with a little effort :D/>/>
Mads #14
Posted 04 April 2012 - 01:22 PM
ctrl+v <<<< this please please please please :D/>/>
We can't access the clipboard in Computercraft, so that is unfortunately not possible:(

ctrl+v / paste will work with a little effort ;)/>/>

No, it will definately NOT. There is ONE possiblity though. For someone to write a peripheral that lets you access the clipboard. But as of now, it CANNOT be done with CC's inbuilt functions :)/>/>
MysticT #15
Posted 04 April 2012 - 06:36 PM
Actually, you can paste into the computer, it's kinda buggy but you can.
Mads #16
Posted 04 April 2012 - 06:52 PM
Actually, you can paste into the computer, it's kinda buggy but you can.
Care to explain how?
MysticT #17
Posted 04 April 2012 - 07:10 PM
Ctrl + v
:)/>/>
It pastes the clipboard content (from the real computer).
ComputerCraftFan11 #18
Posted 05 April 2012 - 03:23 AM
Actually, you can paste into the computer, it's kinda buggy but you can.
Care to explain how?

Press Ctrl to open the menu
after that, press Ctrl+V

(Sadly, it only pastes 1 line.. 1!!!)