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

Note-Taker (Text Editor)

Started by Grim Reaper, 24 December 2012 - 08:31 PM
Grim Reaper #1
Posted 24 December 2012 - 09:31 PM
I noticed a couple new text-editing programs that had come out on the forums and thought that I might give a crack at it.
This script isn't much compared to TACO or any other editors, but it's a little nicer than the native edit program.

* It is recommended that you disable syntax highlighting seeing as it causes a lot of flashing and lag when redrawing the screen in
large files.

Features:
- Custom cursor
- Custom text and background colors
- Line numbering
- Colorful user interface
- Current file path displayed on top of screen
- Current line highlighting
- Alert at top of the screen if changes have been made so you know to save the file.
- Added key support for Ctrl + S (Save) or Ctrl + E (Exit),
- Mouse support for moving the cursor to different positions in the file.
- Mouse scrolling.
- Syntax highlighting
- Syntax highlighting is configurable (you can select none <- RECOMMENDED).

Features pending
- Other line commands (cut, paste, copy, etc.)
- Mutli-session support (projects).

Currently the colors must be configured within the script, but their respective constants are named ideally so you shouldn't have to look for long (no more than a couple of seconds) to find them.

Although you can't see it in the screenshots, the cursor does blink when it's idling.

Screenshots:
Spoiler
The following images are from a previous update without syntax highlighting.

Following images were taken before a recent update, hence the lack of line coloring.





Code:
Spoiler



tArgs = { ... }

--[[
	Note Taker	  PaymentOption
					23 December 2012

	Simple text editor using colors and
	line numbers and a custom cursor.
]]--

-- This program can only be used on an advanced computer, so make sure
-- that the computer we're working on supports color.
if not term.isColor() then
	print("Color must be supported.")
	return
end

-- Make sure that we have the proper arguments to continue.
if #tArgs < 1 then
	print("Usage: " .. fs.getName(shell.getRunningProgram()) .. " <file_path>")
	return
elseif fs.isDir(tArgs[1]) then
	print("Cannot edit a directory.")
	return
elseif fs.isReadOnly(tArgs[1]) then
	print("Cannot edit a read only file.")
	return
end

-- Variables --
local running = true -- Whether or not the program should be running.

local TAB_SIZE = 3 -- The number of spaces inserted into the current line when the tab key is pressed.

local BACKGROUND_COLOR   = colors.blue
local CURRENT_LINE_COLOR = colors.cyan
local TEXT_COLOR		 = colors.white

local LINE_NUMBER_COLOR			= colors.white
local LINE_NUMBER_BACKGROUND_COLOR = colors.gray

local CURSOR_BLINK_TIME = 0.3
local CURSOR_COLOR	  = colors.lightGray
local shouldCursorBlink = false
local cursorBlinkTimer  = os.startTimer(CURSOR_BLINK_TIME)

local path  = tArgs[1] -- The path for the program to load files from or to create a new file at.
local lines = {} -- All of the lines that are contained within the  current file.
local hasBeenSavedSinceLastChar = true -- Whether or not the file has been saved since the last character modification was made.

local xPosOffset = 3
local yPosOffset = 3

local WIDTH, HEIGHT = term.getSize() -- The width and height dimensions of the terminal we're working on.
local scroll = {x = 0, y = 0} -- The amount of characters/lines that are to be scrolled when editing.
local pos	= {x = 3, y = 3} -- The position of the cursor in the file. Scrolling will be handled in another function.

local COLORS = {
	COMMENT_COLOR = colors.lime,
	STRING_COLOR  = colors.lightGray,
	KEYWORD_COLOR = colors.yellow
}

local keywords = { -- All keywords that are to be highlighted when drawing the screen. Also, the colors for each keyword are stored by their
				   -- string index.
	["function"] = true,
	["if"]	   = true,
	["then"]	 = true,
	["elseif"]   = true,
	["else"]	 = true,
	["end"]	  = true,
	["repeat"]   = true,
	["until"]	= true,
	["for"]	  = true,
	["in"]	   = true,
	["ipairs"]   = true,
	["pairs"]	= true,
	["and"]	  = true,
	["or"]	   = true,
	["not"]	  = true,
	["do"]	   = true,
	["true"]	 = true,
	["false"]	= true,
	["while"]	= true

}
-- Variables --

-- File functions --
-- Reads all of the lines in the file at 'path' into a table and returns aforementioned table.
-- In the case that the path provided doesn't exist, then a table with a single empty string will
-- be returned so that we can create an empty file for the user to save.
function loadLinesFromFile(path)
	-- If the file doesn't exist, then setup the lines table as a single empty line.
	-- The file will be created when the programs saves.
	if not fs.exists(path) then
		return {""}
	end

	-- In the case that the file exists, then load its contents into the lines table.
	local fileHandle = io.open(path, 'r')
	local line	   = fileHandle:read()
	local lines	  = {}

	-- Read a line from the file so long as the line read
	-- isn't nil. (When the line is nil it means that we have reached the end of the file.)
	while line do
		table.insert(lines, line)
		line = fileHandle:read()
	end
	fileHandle:close()

	-- Setup the proper xPosOffset for the number of lines loaded.
	if #lines >= 10 then
		-- Find out which power of ten the number of lines is divisible by.
		local power	= 1
		local quotient = #lines / (math.pow(10, power))

		-- Divide the number of lines in the file by a power of ten until
		-- the resulting decimal is less than 1.
		-- Once it is less than 1, then we have the greatest power of ten that can
		-- fit into the number of lines, allowing us to calculate the offset of the cursor.
		while quotient >= 1 do
			if #lines / (10^power) >= 1 then
				quotient = #lines / (10^power)
				power = power + 1
			else
				break
			end
		end

		-- Update the cursor offset and the cursor position.
		xPosOffset = power + 2
		pos.x	  = xPosOffset
	end

	return lines
end

-- Saves all of the lines in the lines table to the file at 'path'.
-- If the directory that is specified by 'path' doesn't exist, then
-- it will be created so that the file can be saved properly.
function saveLinesToFile(path)
	-- Make sure that the path to the file excluding the name exists.
	-- In the case that it doesn't, then we'll make the directory to
	-- put the file in.
	local pathWithoutName = path:sub(1, path:len() - fs.getName(path):len())
	if not fs.isDir(pathWithoutName) then
		fs.makeDir(pathWithoutName)
	end

	-- Save the lines in the lines table to the path provided by looping
	-- through the lines table and writing each entry using fs.writeLine().
	local fileHandle = fs.open(path, 'w')
	for lineNumber, line in ipairs(lines) do
		fileHandle.writeLine(line)
	end
	fileHandle.close()
end
-- File functions --

-- Drawing functions --
-- Writes the given text using the x position offset as the cut off for strings appearing on screen.
-- This should be used only for drawing the lines in the file and not for the drawing of the interface.
function writeLimited(text)
	local xPos, yPos = term.getCursorPos()
	local old_xPos   = xPos
	local old_text   = text

	if xPos < xPosOffset then
		text = text:sub((xPosOffset - xPos) + 1)
		xPos = xPosOffset
	end

	term.setCursorPos(xPos, yPos)
	term.write(text)

	term.setCursorPos(old_xPos + old_text:len(), yPos)
end

-- Code shamelessly stolen from dan200's edit program. ************
local function tryWrite( sLine, regex, colour )
local match = string.match( sLine, regex )
if match then
if type(colour) == "number" then
term.setTextColour( colour )
else
term.setTextColour( colour(match) )
end
writeLimited( match )
term.setTextColour( TEXT_COLOR )
return string.sub( sLine, string.len(match) + 1 )
end
return nil
end

local function writeHighlighted( sLine )
while string.len(sLine) > 0 do
sLine =
tryWrite( sLine, "^%-%-%[%[.-%]%]", COLORS.COMMENT_COLOR ) or
tryWrite( sLine, "^%-%-.*", COLORS.COMMENT_COLOR ) or
tryWrite( sLine, "^\".-[^\\]\"", COLORS.STRING_COLOR ) or
tryWrite( sLine, "^\'.-[^\\]\'", COLORS.STRING_COLOR ) or
tryWrite( sLine, "^%[%[.-%]%]", COLORS.STRING_COLOR ) or
tryWrite( sLine, "^[%w_]+", function( match )
if keywords[ match ] then
return COLORS.KEYWORD_COLOR
end
return TEXT_COLOR
end ) or
tryWrite( sLine, "^[^%w_]", TEXT_COLOR )
end
end
-- End shameless code stealing. All credit goes to dan200. *******

-- Draws the title bar for the program which includes the name of the program and whether or not it has
-- been saved since it was edited last.
function drawTitleBar()
	-- Get the file path to display that we are editing that file. If the file path is too long,
	-- then truncate it.
	local truncatedFilePath = ((path:len() > (WIDTH - 14)) and path:sub(1, (WIDTH - 14)) .. "..." or path) .. (hasBeenSavedSinceLastChar and '' or '*')
	-- Redraw the title bar at the top of the screen.
	term.setCursorPos(1, 1)
	term.setBackgroundColor(colors.lightBlue)
	term.setTextColor(colors.white)
	term.clearLine()
	term.setCursorPos(2, 1)
	term.write("Note-Taker - " .. truncatedFilePath)
	term.setCursorPos(WIDTH - 3, 1)
	term.write("_[]")
	term.setBackgroundColor(colors.red)
	term.write('X')
end

-- Draws the line numbers in the file.
-- Accounts for scrolling too.
-- NOTE: This clears the entire line. The line must be redrawn
--	   after the line number has been drawn.
function drawLineNumbers()
	drawTitleBar()

	-- Redraw the menu option.
	term.setCursorPos(1, 2)
	term.setBackgroundColor(colors.lightGray)
	term.clearLine()
	term.setBackgroundColor(colors.gray)
	term.setCursorPos(WIDTH - ("[ File ]"):len(), 2)
	term.write("[ File ]")

	for lineNumber = yPosOffset + scroll.y, HEIGHT + scroll.y do
		term.setCursorPos(1, lineNumber - scroll.y)

		if lineNumber == pos.y then
			term.setBackgroundColor(CURRENT_LINE_COLOR)
		else
			term.setBackgroundColor(BACKGROUND_COLOR)
		end

		term.setTextColor(TEXT_COLOR)
		term.clearLine()
		if lineNumber - yPosOffset + 1 <= #lines then
			term.setBackgroundColor(LINE_NUMBER_BACKGROUND_COLOR)
			term.setTextColor(LINE_NUMBER_COLOR)

			term.write(tostring(lineNumber - yPosOffset + 1) .. (string.rep(' ', tostring(#lines):len() - tostring(lineNumber - yPosOffset + 1):len())))
		else
			term.setBackgroundColor(LINE_NUMBER_BACKGROUND_COLOR)
			term.setTextColor(LINE_NUMBER_COLOR)
			term.write(string.rep(' ', xPosOffset - 2))
		end

		-- Reset the colors for the editor so that only the part
		-- where the line number is drawn has color.
		term.setBackgroundColor(BACKGROUND_COLOR)
		term.setTextColor(TEXT_COLOR)
	end
end

-- Draws the current line number.
function drawCurrentLineNumber()
	local lineNumber = pos.y
	term.setCursorPos(1, lineNumber - scroll.y)

	term.setBackgroundColor(CURRENT_LINE_COLOR)
	term.clearLine()

	term.setCursorPos(1, lineNumber - scroll.y)
	term.setBackgroundColor(LINE_NUMBER_BACKGROUND_COLOR)
	term.setTextColor(LINE_NUMBER_COLOR)
	term.write(tostring(lineNumber - yPosOffset + 1) .. (string.rep(' ', tostring(#lines):len() - tostring(lineNumber - yPosOffset + 1):len())))
end

-- Draws the current line.
function drawCurrentLine()
	drawTitleBar()
	drawCurrentLineNumber()
	local lineNumber = pos.y + scroll.y
	local line	   = lines[(pos.y - yPosOffset + 1)]
	term.setBackgroundColor(CURRENT_LINE_COLOR)
	term.setTextColor(TEXT_COLOR)

	term.setCursorPos(xPosOffset - scroll.x, pos.y - scroll.y)
	writeHighlighted(line)
	term.setBackgroundColor(BACKGROUND_COLOR)
end

-- Draws all of the lines in the file that can fit on the screen
-- depending on how the screen is scrolled. Sets the cursor position
-- in the proper place after redrawing.
function drawLines()
	-- Redraw the line numbers.
	drawLineNumbers()
	-- NOTE: The above function call will have cleared all of the lines on screen.

	for lineNumber = yPosOffset + scroll.y, HEIGHT + scroll.y do
		-- Offset the line to threee characters over the compensate
		-- for the line numbers.
		term.setCursorPos(xPosOffset - scroll.x, lineNumber - scroll.y)

		-- Get the line at the supposed line number. If the line we selected doesn't exist,
		-- then don't draw it.
		local line = lines[lineNumber - (yPosOffset - 1)]
		if line then
			-- Scroll the line drawn by getting a substring of it from the first
			-- character plus how many characters are to be scrolled until how many
			-- characters will fit on the screen plus how much is to be scrolled.
			if lineNumber == pos.y then
				term.setBackgroundColor(CURRENT_LINE_COLOR)
			end

			writeHighlighted(line)
			term.setBackgroundColor(BACKGROUND_COLOR)
		end
	end

	-- Reset the cursor position to the proper place so that the user may write.
	term.setCursorPos(pos.x - scroll.x, pos.y - scroll.y)
end

-- Draws the cursor using the constant 'CURSOR_COLOR'.
function drawAndSetCursor(x, y)
	term.setCursorPos(x, y)
	term.setBackgroundColor(CURSOR_COLOR)
	if shouldCursorBlink then
		local charAtCursor = lines[pos.y - (yPosOffset - 1)]:sub(pos.x - (xPosOffset - 1), pos.x - (xPosOffset - 1))
		if charAtCursor == "" then
			charAtCursor = ' '
		end

		term.write(charAtCursor)
	end
	term.setBackgroundColor(BACKGROUND_COLOR)

	term.setCursorPos(45, 1)
end
-- Drawing functions --

-- Menu functions --
-- Draws the main menu that contains the save, exit, and color config menu.
function drawMainMenu()
	local options = { -- The options in the main menu.
		"  Save  ",
		"  Exit  "
	}

	-- Since the length of all of the options as strings are all the same, calculate the x position
	-- where each option should be drawn in order for them to all be in the center of the screen.
	local width = (#options[1] + #options[2]) * 2
	local xPos  = WIDTH/2 - width/2
	local yPos  = HEIGHT/2 - 3
	local index = 1

	-- Draws the menu in the center of the screen.
	local function draw()
		term.setBackgroundColor(colors.lightBlue)
		term.setCursorPos(xPos, yPos)
		term.write(string.rep(' ', width))

		term.setTextColor(colors.white)
		term.setCursorPos(WIDTH/2 - ("Menu"):len()/2, yPos)
		term.write("Menu")
		term.setCursorPos(xPos + width - 4, yPos)
		term.write('_[]')
		term.setBackgroundColor(colors.red)
		term.write('X')

		term.setBackgroundColor(colors.lightGray)
		for line = yPos + 1, yPos + #options + 1 do
			term.setCursorPos(xPos, line)
			term.write(string.rep(' ', width))
		end
		term.setBackgroundColor(colors.gray)

		term.setCursorPos(xPos + 3, yPos + #options)
		term.write("[ " .. options[1] .. " ]")

		term.setBackgroundColor(colors.lightGray)
		term.write("  ")
		term.setBackgroundColor(colors.gray)
		term.write("[ " .. options[2] .. " ]")
	end

	-- Handles clicks an other interaction with the menu.
	-- After any click, the function will return.
	local function handleClicks(xPos, yPos)
		while true do
			local event, p1, p2, p3 = os.pullEvent()

			-- Handle clicks.
			if event == "mouse_click" then
				-- If the click was on the save option, then save the current file.
				if wasClickOnRange(p2, p3, xPos + 3, math.floor(yPos + #options), ("[ " .. options[1] .. " ]"):len()) then
					saveLinesToFile(path)
					hasBeenSavedSinceLastChar = true
					return
				-- If the click was on the exit option, then exit the program.
				elseif wasClickOnRange(p2, p3, xPos + 3 + ("[ " .. options[1] .. " ]"):len(), math.floor(yPos + #options), ("[ " .. options[2] .. " ]"):len()) then
					running = false
					return
				-- If the click was on the red 'X' at the top of the menu dialog, then close the dialog box and return to the editor.
				-- Close the dialog box if the user pressed either of the control keys.
				elseif wasClickOnRange(p2, p3, xPos + width - 2, math.floor(yPos), 1) then
					return
				end
			-- Handle key presses.
			elseif event == "key" then
				-- If the key pressed was one of the control keys, then exit the dialog box.
				if p1 == 29 or p1 == 157 then
					return
				-- If the key pressed was 's' then save the file and close the dialog box.
				elseif p1 == keys['s'] then
					-- Catch 's' character event thrown.
					os.pullEvent()
					saveLinesToFile(path)
					hasBeenSavedSinceLastChar = true
					return
				-- If the key pressed was 'e' then exit the program.
				elseif p1 == keys['e'] then
					-- Catch 'e' character event thrown.
					os.pullEvent()

					-- Cleanup.
					running = false
					return
				end
			end
		end
	end

	draw()
	handleClicks(xPos, yPos)
end
-- Menu functions --

-- Click functions --
-- Checks whether or not the given click was on the given range.
function wasClickOnRange(xClickPos, yClickPos, xPos, yPos, width)
	return xClickPos >= xPos and xClickPos <= xPos + width and yClickPos == yPos
end
-- Click functions --

-- Positioning functions --
-- Sets the cursor at the stored position and modifies the scroll values accordingly
-- so everything will be drawn and positioned correctly.
function updateCursorPos()
	local xPos = pos.x - scroll.x -- This is to be the position that the cursor will be placed at on the x-axis for scrolling to be proper.
	local yPos = pos.y - scroll.y -- This is to be the position that the cursor will be placed at on the y-axis for scrolling to be proper.

	local shouldRedrawLines = false
	-- In the case that the cursor goes before 3, then we need to scroll the cursor back one so that we don't
	-- overwrite the line number and or go off the screen.
	if xPos < xPosOffset then
		xPos = xPosOffset
		scroll.x = pos.x - xPosOffset

		shouldRedrawLines = true
	-- If the cursor attempts to go beyond the screen limit, then scroll the cursor over by 1.
	elseif xPos > WIDTH then
		xPos = WIDTH
		scroll.x = pos.x - WIDTH

		shouldRedrawLines = true
	end

	-- In the case that the cursor attempts to go above the screen limit, then scroll the screen up by 1.
	if yPos < yPosOffset then
		yPos = yPosOffset
		scroll.y = scroll.y - 1

		shouldRedrawLines = true
	-- If the cursor attempts to go below the screen limit, then scroll the screen down by 1.
	elseif yPos > HEIGHT then
		yPos = HEIGHT
		scroll.y = scroll.y + 1

		shouldRedrawLines = true
	end

	if shouldRedrawLines then
		drawLines()
	end

	-- Redraw the text and lines in the file; repsotion the cursor to its proper point.
	drawAndSetCursor(xPos, yPos)
end
-- Positioning functions --

-- Input handling functions --
-- Waits for an event to be thrown, then handles that event accordingly by adding text to the file,
-- moving the cursor, and other various things.
function handleInput()
	-- Resets the cursor and its blink timer so that the user may see during this update.
	local function resetCursor()
		-- Make sure that the user can see the timer by
		-- setting the blink flag to true and resetting the cursor blink timer.
		shouldCursorBlink = true
		cursorBlinkTimer = os.startTimer(CURSOR_BLINK_TIME)
	end

	-- Grab an event and its parameters to be handled later.
	local event, p1, p2, p3 = os.pullEvent()
	local xPos = pos.x - (xPosOffset - 1)
	local yPos = pos.y - (yPosOffset - 1)
	local line = lines[yPos]

	-- In the case that the event thrown was a character event, add the chracter to the current line.
	if event == "char" then
		-- Set the line to a substring of itself from the cursor xPos minus one plus the character typed plus the rest of the line from the
		-- position of the cursor onward.
		lines[yPos] = line:sub(1, xPos - 1) .. p1 .. line:sub(xPos)

		-- Update the cursor by moving it one over to the right.
		pos.x = pos.x + 1

		-- Since the event thrown was not the cursor blink timer, make sure that the user can see the timer by
		-- setting the blink flag to true and resetting the cursor blink timer.
		resetCursor()

		-- A change has been made to the state of the lines in the file, so set the proper flag to alert the user
		-- that it needs to be saved to keep the changes made.
		hasBeenSavedSinceLastChar = false
		drawCurrentLine()
	-- If the event was a key, then handle that key press appropriately.
	elseif event == "key" then
		-- If the key pressed was a backspace, then remove the character before the cursor in the current line.
		if p1 == keys["backspace"] then
			-- Make sure the length of the line is greater than 0 before trying to remove a character.
			if pos.x > xPosOffset then
				lines[yPos] = line:sub(1, xPos - 2) .. line:sub(xPos)
				-- Update the cursor position by moving it one backwards.
				pos.x = pos.x - 1
				drawCurrentLine()
			-- If the cursor is at the beginning of the line, then back up the cursor to the previous line (if possible) carrying the
			-- current line with it.
			elseif yPos > 1 then
				-- If the number of lines in the file increases by an exponent of 10, then move the offset of the x pos for the cursor up by 1.
				if #lines == math.pow(10, xPosOffset - 3) then
					xPosOffset = xPosOffset - 1
					pos.x	  = pos.x - 1
				end

				local previousLine = lines[yPos - 1]
				lines[yPos - 1]   = previousLine .. line

				-- Remove the current line entry and move the cursor to the previous line.
				table.remove(lines, yPos)

				pos.x = previousLine:len() + xPosOffset -- lines[pos.y - 1]:len() + xPosOffset
				pos.y = pos.y - 1
				drawLines()
			end

			-- A change has been made to the state of the lines in the file, so set the proper flag to alert the user
			-- that it needs to be saved to keep the changes made.
			hasBeenSavedSinceLastChar = false
		-- If the key pressed was the enter key, then create a new line.
		elseif p1 == keys["return"] then
			-- Get a substring of the line from the cursor onward on the current line, a substring of the
			-- current line from the cursor backwards.
			local lineFromCursor   = line:sub(xPos)
			local lineBeforeCursor = line:sub(1, xPos - 1)
			-- Compute the number of spaces before any text on the screen to determine the current line's indentation.
			local _, numSpaces = line:find("^[ ]+")
			if not numSpaces then
				numSpaces = 0
			end

			-- Set the current line to the substring from the cursor backwards.
			lines[yPos]	 = lineBeforeCursor
			-- Insert the line from the cursor onward into the line below all the while shifting the entire
			-- file down by one line.
			table.insert(lines, yPos + 1, string.rep(' ', numSpaces) .. lineFromCursor)

			-- If the number of lines in the file increases by an exponent of 10, then move the offset of the x pos for the cursor up by 1.
			if #lines == math.pow(10, xPosOffset - 2) then
				xPosOffset = xPosOffset + 1
			end

			-- Update the cursor by moving it down once.
			pos.x = xPosOffset + numSpaces
			pos.y = pos.y + 1

			-- A change has been made to the state of the lines in the file, so set the proper flag to alert the user
			-- that it needs to be saved to keep the changes made.
			hasBeenSavedSinceLastChar = false

			-- For some reason, the screen won't scroll after you press the enter key. Weird.
			updateCursorPos()
			drawLines()
		-- If the key pressed was a right arrow, then move the cursor one to the right if it can.
		elseif p1 == keys["right"] then
			-- Make sure the cursor can move one to the right before actually moving the cursor.
			if xPos < line:len() + 1 then
				pos.x = pos.x + 1
				drawCurrentLine()
			-- If the current line isn't the last line the file and we're at the end of the line, then move the cursor
			-- to the next line.
			elseif yPos < #lines then
				pos.x = xPosOffset
				pos.y = pos.y + 1
				drawLines()
			end
		-- If the key pressed wa a left arrow, then move the cursor one to the left if it can.
		elseif p1 == keys["left"] then
			-- Make sure the cursor can move one to the left before actually moving it.
			if xPos > 1 then
				pos.x = pos.x - 1
				drawCurrentLine()
			-- If the current line isn't the first line in the file and we're at the beginning of the line, then move
			-- the cursor to the previous line.
			elseif yPos > 1 then
				pos.x = math.max(lines[yPos - 1]:len(), 1) + xPosOffset
				pos.y = pos.y - 1
				drawLines()
			end
		-- If the key pressed was the down key, then move the cursor one down if it can.
		elseif p1 == keys["down"] and yPos < #lines then
			pos.x = math.min(xPos + xPosOffset - 1, lines[yPos + 1]:len() + xPosOffset)
			pos.y = pos.y + 1
			drawLines()
		-- If the key pressed was the up key, then move the cursor one up if it can.
		elseif p1 == keys["up"] and yPos > 1 then
			pos.x = math.min(xPos + xPosOffset - 1, lines[yPos - 1]:len() + xPosOffset)
			pos.y = pos.y - 1
			drawLines()
		-- If the key pressed was the end key, then move the cursor to the end of the current line.
		elseif p1 == keys["end"] then
			pos.x	= line:len() + xPosOffset
			drawCurrentLine()
		-- If the key pressed was the home key, then move they cursor to the beginning of the current line.
		elseif p1 == keys["home"] then
			pos.x	= xPosOffset
			drawCurrentLine()
		-- If the key pressed was the delete key, then delete the character in front of the cursor if possible.
		elseif p1 == keys["delete"] then
			-- If the cursor isn't at the end of the line, then remove the character in front of the cursor.
			if xPos < line:len() + 1 then
				lines[yPos] = line:sub(1, xPos - 1) .. line:sub(xPos + 1)
				drawCurrentLine()
			-- If the cursor is at the end of the current line, then add the next line to the current one.
			elseif yPos < #lines then
				-- If the number of lines in the file increases by an exponent of 10, then move the offset of the x pos for the cursor up by 1.
				if #lines == math.pow(10, xPosOffset - 3) then
					xPosOffset = xPosOffset - 1
					pos.x	  = pos.x - 1
				end

				lines[yPos] = line .. lines[yPos + 1]
				table.remove(lines, yPos + 1)
				drawLines()
			end

			-- A change has been made to the state of the lines in the file, so set the proper flag to alert the user
			-- that it needs to be saved to keep the changes made.
			hasBeenSavedSinceLastChar = false
		-- If the key pressed was the tab key, then insert the proper number of spaces into the current line.
		elseif p1 == keys["tab"] then
			lines[yPos] = line:sub(1, xPos - 1) .. string.rep(' ', TAB_SIZE) .. line:sub(xPos)
			-- Update and reset the curs; redraw the current line.
			hasBeenSavedSinceLastChar = false
			pos.x = pos.x + TAB_SIZE
			resetCursor()
			drawCurrentLine()
		-- If the user pressed either of the control keys, then open the file menu.
		elseif p1 == 29 or p1 == 157 then
			drawMainMenu()
			resetCursor()
			drawLines()
		end

		-- Since the event thrown was not the cursor blink timer, make sure that the user can see the timer by
		-- setting the blink flag to true and resetting the cursor blink timer.
		resetCursor()
	-- If the event thrown was a timer event and the timer was the cursor blink timer, set the flag for the cursor
	-- to blink to true and reset the timer.
	elseif event == "timer" and p1 == cursorBlinkTimer then
		shouldCursorBlink = not shouldCursorBlink
		cursorBlinkTimer = os.startTimer(CURSOR_BLINK_TIME)
		drawCurrentLine()
	-- If the event was a click on the menu option at the top of the screen, then open the menu.
	elseif event == "mouse_click" and wasClickOnRange(p2, p3, WIDTH - ("[ File ]"):len(), 2, ("[ File ]"):len()) then
		drawMainMenu()
		resetCursor()
		drawLines()
	-- Handle mouse clicks.
	elseif event == "mouse_click" then
		-- If the event was a click on the 'X' at the top of the screen, then close the program.
		if p2 == WIDTH and p3 == 1 then
			running = false
		-- Handle a click if it was on some line in the code so we may move the cursor to the place of the click.
		elseif p2 >= xPosOffset and p3 >= yPosOffset then
			pos.y = math.min(p3 + scroll.y, #lines + scroll.y + yPosOffset - 1)
			pos.x = math.min(p2 + scroll.x, lines[pos.y - (yPosOffset - 1)]:len() + xPosOffset)

			drawLines()
		end
	end
end
-- Input handling functions --



-- Initialization --
-- Set the colors for the editor.
term.setBackgroundColor(BACKGROUND_COLOR)
term.setTextColor(TEXT_COLOR)

-- Clear the screen before writing anything.
term.clear()
-- Load the file passed as an argument into the lines table.
lines = loadLinesFromFile(path)
drawLines()
-- Initialization --


-- Main entry point.
while running do
	updateCursorPos()
	handleInput()
end

-- Cleanup.
term.setBackgroundColor(colors.black)
term.setTextColor(colors.white)

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

Pastebin
remiX #2
Posted 25 December 2012 - 02:02 AM
Much better than the default edit program (because of the colours :D/>) I like the numbers on the left xD

I would guess that you took the code from the edit program, or am I wrong?
Add mouse support to clicking to different places in the code :P/> and tabs
Grim Reaper #3
Posted 25 December 2012 - 05:12 AM
Much better than the default edit program (because of the colours :D/>) I like the numbers on the left xD

I would guess that you took the code from the edit program, or am I wrong?
Add mouse support to clicking to different places in the code :P/> and tabs

Thank you.

I did study the edit program to make sure that my scrolling would be similar to its, but I didn't take the code.
AndreWalia #4
Posted 25 December 2012 - 05:43 AM
This is Beautiful! mind if I; One, Put this in my OS. Two, Mind if i change the name ti not taker to editor? note taker will make people think its a word document program. Thanks
rhyleymaster #5
Posted 25 December 2012 - 08:38 AM
Its very good.
Grim Reaper #6
Posted 27 December 2012 - 01:39 PM
Syntax highlighting added. *Bump, hehehe….