This commit is contained in:
Igor Timofeev
2017-01-14 06:09:29 +03:00
parent 2029a78a3a
commit cb965a83cd

View File

@@ -0,0 +1,504 @@
---------------------------------------------------- Libraries ----------------------------------------------------
-- package.loaded.syntax = nil
-- package.loaded.GUI = nil
-- package.loaded.windows = nil
-- package.loaded.MineOSCore = nil
require("advancedLua")
local fs = require("filesystem")
local buffer = require("doubleBuffering")
local GUI = require("GUI")
local windows = require("windows")
local MineOSCore = require("MineOSCore")
local event = require("event")
local syntax = require("syntax")
local unicode = require("unicode")
local keyboard = require("keyboard")
---------------------------------------------------- Constants ----------------------------------------------------
-- "/MineOS/Desktop/MineCode IDE.app/MineCode IDE.lua"
local clipboard
local cursor = {
position = {
symbol = 20,
line = 8
},
color = 0x00A8FF,
symbol = "",
blinkDelay = 0.4,
blinkState = false,
}
local mainWindow = {}
local config = {
indentaionWidth = 2,
colorScheme = {
topToolBar = 0xBBBBBB,
topMenu = {
backgroundColor = 0xEEEEEE,
textColor = 0x444444,
backgroundPressedColor = 0x3366CC,
textPressedColor = 0xFFFFFF,
},
},
scrollSpeed = 8,
}
---------------------------------------------------- File processing methods ----------------------------------------------------
local function loadFile(path)
mainWindow.codeView.fromLine, mainWindow.codeView.fromSymbol, mainWindow.codeView.lines, mainWindow.codeView.maximumLineLength = 1, 1, {}, 0
local file = io.open(path, "r")
for line in file:lines() do
line = line:gsub("\t", string.rep(" ", config.indentaionWidth))
table.insert(mainWindow.codeView.lines, line)
mainWindow.codeView.maximumLineLength = math.max(mainWindow.codeView.maximumLineLength, unicode.len(line))
end
file:close()
mainWindow.titleTextBox.lines = {
"File: " .. path,
"Cursor position: 1x1",
"Zalupa, penis"
}
end
---------------------------------------------------- Cursor methods ----------------------------------------------------
local function fixFromLineByCursorPosition()
if mainWindow.codeView.fromLine > cursor.position.line then
mainWindow.codeView.fromLine = cursor.position.line
elseif mainWindow.codeView.fromLine + mainWindow.codeView.height - 2 < cursor.position.line then
mainWindow.codeView.fromLine = cursor.position.line - mainWindow.codeView.height + 2
end
end
local function fixFromSymbolByCursorPosition()
if mainWindow.codeView.fromSymbol > cursor.position.symbol then
mainWindow.codeView.fromSymbol = cursor.position.symbol
elseif mainWindow.codeView.fromSymbol + mainWindow.codeView.codeAreaWidth - 3 < cursor.position.symbol then
mainWindow.codeView.fromSymbol = cursor.position.symbol - mainWindow.codeView.codeAreaWidth + 3
end
end
local function fixCursorPosition(symbol, line)
if line < 1 then
line = 1
elseif line > #mainWindow.codeView.lines then
line = #mainWindow.codeView.lines
end
local lineLength = unicode.len(mainWindow.codeView.lines[line])
if symbol < 1 or lineLength == 0 then
symbol = 1
elseif symbol > lineLength then
symbol = lineLength + 1
end
return symbol, line
end
local function setCursorPosition(symbol, line)
cursor.position.symbol, cursor.position.line = fixCursorPosition(symbol, line)
fixFromLineByCursorPosition()
fixFromSymbolByCursorPosition()
end
local function convertScreenCoordinatesToCursorPosition(x, y)
return x - mainWindow.codeView.codeAreaPosition + mainWindow.codeView.fromSymbol - 1, y - mainWindow.codeView.y + mainWindow.codeView.fromLine
end
local function clearSelection()
mainWindow.codeView.selections[1] = nil
end
local function moveCursor(symbolOffset, lineOffset)
local newSymbol, newLine = cursor.position.symbol + symbolOffset, cursor.position.line + lineOffset
if newSymbol < 1 then
newLine, newSymbol = newLine - 1, math.huge
elseif newSymbol > unicode.len(mainWindow.codeView.lines[newLine] or "") + 1 then
newLine, newSymbol = newLine + 1, 1
end
setCursorPosition(newSymbol, newLine)
end
---------------------------------------------------- Text processing methods ----------------------------------------------------
local function deleteLine(line)
if #lines > 0 then
table.remove(mainWindow.codeView.lines, line)
setCursorPosition(1, cursor.position.line)
end
end
local function deleteSpecifiedData(fromSymbol, fromLine, toSymbol, toLine)
local upperLine = unicode.sub(mainWindow.codeView.lines[fromLine], 1, fromSymbol - 1)
local lowerLine = unicode.sub(mainWindow.codeView.lines[toLine], toSymbol + 1, -1)
for i = fromLine + 1, toLine do
table.remove(mainWindow.codeView.lines, fromLine + 1)
end
mainWindow.codeView.lines[fromLine] = upperLine .. lowerLine
setCursorPosition(fromSymbol, fromLine)
end
local function deleteSelectedData()
if mainWindow.codeView.selections[1] then
deleteSpecifiedData(
mainWindow.codeView.selections[1].from.symbol,
mainWindow.codeView.selections[1].from.line,
mainWindow.codeView.selections[1].to.symbol,
mainWindow.codeView.selections[1].to.line
)
clearSelection()
end
end
local function copy()
if mainWindow.codeView.selections[1] then
if mainWindow.codeView.selections[1].to.line == mainWindow.codeView.selections[1].from.line then
clipboard = { unicode.sub(mainWindow.codeView.lines[mainWindow.codeView.selections[1].from.line], mainWindow.codeView.selections[1].from.symbol, mainWindow.codeView.selections[1].to.symbol) }
else
clipboard = { unicode.sub(mainWindow.codeView.lines[mainWindow.codeView.selections[1].from.line], mainWindow.codeView.selections[1].from.symbol, -1) }
for line = mainWindow.codeView.selections[1].from.line + 1, mainWindow.codeView.selections[1].to.line - 1 do
table.insert(clipboard, mainWindow.codeView.lines[line])
end
table.insert(clipboard, unicode.sub(mainWindow.codeView.lines[mainWindow.codeView.selections[1].to.line], 1, mainWindow.codeView.selections[1].to.symbol))
end
end
end
local function cut()
if mainWindow.codeView.selections[1] then
copy()
deleteSelectedData()
end
end
local function paste(pasteLines)
local firstPart = unicode.sub(mainWindow.codeView.lines[cursor.position.line], 1, cursor.position.symbol - 1)
local secondPart = unicode.sub(mainWindow.codeView.lines[cursor.position.line], cursor.position.symbol, -1)
if #pasteLines == 1 then
mainWindow.codeView.lines[cursor.position.line] = firstPart .. pasteLines[1] .. secondPart
setCursorPosition(cursor.position.symbol + unicode.len(pasteLines[1]), cursor.position.line)
else
local line = cursor.position.line
mainWindow.codeView.lines[line] = firstPart .. pasteLines[1]
line = line + 1
for i = #pasteLines - 1, 2, -1 do
table.insert(mainWindow.codeView.lines, line, pasteLines[i])
line = line + 1
end
mainWindow.codeView.lines[line] = pasteLines[#pasteLines] .. secondPart
setCursorPosition(unicode.len(pasteLines[#pasteLines]) + 1, cursor.position.line + #pasteLines - 1)
end
end
local function backspace()
if mainWindow.codeView.selections[1] then
deleteSelectedData()
else
if cursor.position.symbol > 1 then
deleteSpecifiedData(cursor.position.symbol - 1, cursor.position.line, cursor.position.symbol - 1, cursor.position.line)
else
deleteSpecifiedData(unicode.len(mainWindow.codeView.lines[cursor.position.line - 1]) + 1, cursor.position.line - 1, 0, cursor.position.line)
end
end
end
local function enter()
local firstPart = unicode.sub(mainWindow.codeView.lines[cursor.position.line], 1, cursor.position.symbol - 1)
local secondPart = unicode.sub(mainWindow.codeView.lines[cursor.position.line], cursor.position.symbol, -1)
mainWindow.codeView.lines[cursor.position.line] = firstPart
table.insert(mainWindow.codeView.lines, cursor.position.line + 1, secondPart)
setCursorPosition(1, cursor.position.line + 1)
end
---------------------------------------------------- Text comments-related methods ----------------------------------------------------
local function isLineCommented(line)
return mainWindow.codeView.lines[line]:match("%-%-[^%-]")
end
local function commentLine(line)
mainWindow.codeView.lines[line] = "-- " .. mainWindow.codeView.lines[line]
end
local function uncommentLine(line)
mainWindow.codeView.lines[line], countOfReplaces = mainWindow.codeView.lines[line]:gsub("%-%-%s", "", 1)
return countOfReplaces
end
local function toggleComment()
if mainWindow.codeView.selections[1] then
local allLinesAreCommented = true
for line = mainWindow.codeView.selections[1].from.line, mainWindow.codeView.selections[1].to.line do
if not isLineCommented(line) then
allLinesAreCommented = false
end
end
for line = mainWindow.codeView.selections[1].from.line, mainWindow.codeView.selections[1].to.line do
if allLinesAreCommented then
uncommentLine(line)
else
commentLine(line)
end
end
local modifyer = 3
if allLinesAreCommented then
modifyer = -3
end
setCursorPosition(cursor.position.symbol + modifyer, cursor.position.line)
mainWindow.codeView.selections[1].from.symbol, mainWindow.codeView.selections[1].to.symbol = mainWindow.codeView.selections[1].from.symbol + modifyer, mainWindow.codeView.selections[1].to.symbol + modifyer
else
if isLineCommented(cursor.position.line) then
if uncommentLine(cursor.position.line) > 0 then
setCursorPosition(cursor.position.symbol - 3, cursor.position.line)
end
else
commentLine(cursor.position.line)
setCursorPosition(cursor.position.symbol + 3, cursor.position.line)
end
end
end
---------------------------------------------------- Text indentation-related methods ----------------------------------------------------
local function indentLine(line)
mainWindow.codeView.lines[line] = string.rep(" ", config.indentaionWidth) .. mainWindow.codeView.lines[line]
end
local function unindentLine(line)
mainWindow.codeView.lines[line], countOfReplaces = string.gsub(mainWindow.codeView.lines[line], "^" .. string.rep("%s", config.indentaionWidth), "")
return countOfReplaces
end
local function indentOrUnindent(isIndent)
if mainWindow.codeView.selections[1] then
local countOfReplacesInFirstLine, countOfReplacesInLastLine
for line = mainWindow.codeView.selections[1].from.line, mainWindow.codeView.selections[1].to.line do
if isIndent then
indentLine(line)
else
local countOfReplaces = unindentLine(line)
if line == mainWindow.codeView.selections[1].from.line then
countOfReplacesInFirstLine = countOfReplaces
elseif line == mainWindow.codeView.selections[1].to.line then
countOfReplacesInLastLine = countOfReplaces
end
end
end
if isIndent then
setCursorPosition(cursor.position.symbol + config.indentaionWidth, cursor.position.line)
mainWindow.codeView.selections[1].from.symbol, mainWindow.codeView.selections[1].to.symbol = mainWindow.codeView.selections[1].from.symbol + config.indentaionWidth, mainWindow.codeView.selections[1].to.symbol + config.indentaionWidth
else
if countOfReplacesInFirstLine > 0 then
mainWindow.codeView.selections[1].from.symbol = mainWindow.codeView.selections[1].from.symbol - config.indentaionWidth
if cursor.position.line == mainWindow.codeView.selections[1].from.line then
setCursorPosition(cursor.position.symbol - config.indentaionWidth, cursor.position.line)
end
end
if countOfReplacesInLastLine > 0 then
mainWindow.codeView.selections[1].to.symbol = mainWindow.codeView.selections[1].to.symbol - config.indentaionWidth
if cursor.position.line == mainWindow.codeView.selections[1].to.line then
setCursorPosition(cursor.position.symbol - config.indentaionWidth, cursor.position.line)
end
end
end
else
if isIndent then
indentLine(cursor.position.line)
setCursorPosition(cursor.position.symbol + config.indentaionWidth, cursor.position.line)
else
if unindentLine(cursor.position.line) > 0 then
setCursorPosition(cursor.position.symbol - config.indentaionWidth, cursor.position.line)
end
end
end
end
---------------------------------------------------- Main window related methods ----------------------------------------------------
local function calculateSizes()
if mainWindow.topToolBar.isHidden then
mainWindow.codeView.localPosition.y = 2
else
mainWindow.codeView.localPosition.y = 5
mainWindow.topToolBar.width = mainWindow.width
mainWindow.topToolBar.backgroundPanel.width = mainWindow.width
mainWindow.titleTextBox.width = mainWindow.topToolBar.width * 0.25
mainWindow.titleTextBox.localPosition.x = math.floor(mainWindow.topToolBar.width / 2 - mainWindow.titleTextBox.width / 2)
end
mainWindow.topMenu.width = mainWindow.width
mainWindow.codeView.width, mainWindow.codeView.height = mainWindow.width, mainWindow.height - 4
end
local function createWindow()
mainWindow = windows.fullScreen()
mainWindow.codeView = mainWindow:addCodeView(1, 1, 1, 1, {}, 1, 1, 1, {}, {}, true)
mainWindow.topMenu = mainWindow:addMenu(1, 1, 1, config.colorScheme.topMenu.backgroundColor, config.colorScheme.topMenu.textColor, config.colorScheme.topMenu.backgroundPressedColor, config.colorScheme.topMenu.textPressedColor)
mainWindow.topMenu:addItem("MineCode", 0x0)
mainWindow.topMenu:addItem("File")
mainWindow.topMenu:addItem("View")
mainWindow.topMenu:addItem("Properties")
mainWindow.topToolBar = mainWindow:addContainer(1, 2, 1, 3)
mainWindow.topToolBar.backgroundPanel = mainWindow.topToolBar:addPanel(1, 1, 1, 3, config.colorScheme.topToolBar)
mainWindow.titleTextBox = mainWindow.topToolBar:addTextBox(1, 1, 1, 3, 0xDDDDDD, 0x444444, {}, 1):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top)
mainWindow.runButton = mainWindow.topToolBar:addAdaptiveButton(1, 1, 2, 1, 0x444444, 0xFFFFFF, 0xFFFFFF, 0x444444, "Run")
mainWindow.runButton.onTouch = function()
GUI.error("RUN ВАСЯ РАН")
end
mainWindow.toggleSyntaxHighlightingButton = mainWindow.topToolBar:addAdaptiveButton(8, 1, 2, 1, 0xDDDDDD, 0x262626, 0x262626, 0xDDDDDD, "Syntax")
mainWindow.toggleSyntaxHighlightingButton.onTouch = function()
mainWindow.codeView.highlightLuaSyntax = not mainWindow.codeView.highlightLuaSyntax
end
mainWindow.onAnyEvent = function(eventData)
cursor.blinkState = not cursor.blinkState
local oldCursorState = cursor.blinkState
cursor.blinkState = true
if eventData[1] == "touch" and mainWindow.codeView:isClicked(eventData[3], eventData[4]) then
if eventData[5] == 1 then
local menu = GUI.contextMenu(eventData[3], eventData[4])
menu:addItem("Copy", false, "^C")
menu:addItem("Paste", false, "^V")
menu:addItem("Delete")
menu:addSeparator()
menu:addItem("Select all", false, "^A")
menu:show()
else
clearSelection()
setCursorPosition(convertScreenCoordinatesToCursorPosition(eventData[3], eventData[4]))
end
elseif eventData[1] == "drag" then
if eventData[5] ~= 1 then
mainWindow.codeView.selections[1] = mainWindow.codeView.selections[1] or {from = {}, to = {}}
mainWindow.codeView.selections[1].from.symbol, mainWindow.codeView.selections[1].from.line = cursor.position.symbol, cursor.position.line
mainWindow.codeView.selections[1].to.symbol, mainWindow.codeView.selections[1].to.line = fixCursorPosition(convertScreenCoordinatesToCursorPosition(eventData[3], eventData[4]))
if mainWindow.codeView.selections[1].from.line > mainWindow.codeView.selections[1].to.line then
mainWindow.codeView.selections[1].from.line, mainWindow.codeView.selections[1].to.line = swap(mainWindow.codeView.selections[1].from.line, mainWindow.codeView.selections[1].to.line)
mainWindow.codeView.selections[1].from.symbol, mainWindow.codeView.selections[1].to.symbol = swap(mainWindow.codeView.selections[1].from.symbol, mainWindow.codeView.selections[1].to.symbol)
end
end
elseif eventData[1] == "key_down" then
-- Ctrl or CMD
if keyboard.isKeyDown(29) or keyboard.isKeyDown(219) then
-- Slash
if eventData[4] == 53 then
toggleComment()
-- A
elseif eventData[4] == 30 then
mainWindow.codeView.selections[1] = {from = {}, to = {}}
mainWindow.codeView.selections[1].from.symbol, mainWindow.codeView.selections[1].from.line = 1, 1
mainWindow.codeView.selections[1].to.symbol, mainWindow.codeView.selections[1].to.line = unicode.len(mainWindow.codeView.lines[#mainWindow.codeView.lines]), #mainWindow.codeView.lines
-- C
elseif eventData[4] == 46 then
copy()
-- V
elseif eventData[4] == 47 then
paste(clipboard)
-- X
elseif eventData[4] == 45 then
cut()
-- W
elseif eventData[4] == 17 then
end
-- Arrows up, down, left, right
elseif eventData[4] == 200 then
moveCursor(0, -1)
elseif eventData[4] == 208 then
moveCursor(0, 1)
elseif eventData[4] == 203 then
moveCursor(-1, 0)
elseif eventData[4] == 205 then
moveCursor(1, 0)
-- Backspace
elseif eventData[4] == 14 then
backspace()
-- Tab
elseif eventData[4] == 15 then
if keyboard.isKeyDown(42) then
indentOrUnindent(false)
else
indentOrUnindent(true)
end
-- Enter
elseif eventData[4] == 28 then
enter()
else
if not keyboard.isControl(eventData[3]) then
deleteSelectedData()
paste({unicode.char(eventData[3])})
end
end
elseif eventData[1] == "clipboard" then
paste({eventData[3]})
elseif eventData[1] == "scroll" then
if mainWindow.codeView:isClicked(eventData[3], eventData[4]) then
if eventData[5] == 1 then
if mainWindow.codeView.fromLine > config.scrollSpeed then
mainWindow.codeView.fromLine = mainWindow.codeView.fromLine - config.scrollSpeed
else
mainWindow.codeView.fromLine = 1
end
else
if mainWindow.codeView.fromLine < #mainWindow.codeView.lines - config.scrollSpeed then
mainWindow.codeView.fromLine = mainWindow.codeView.fromLine + config.scrollSpeed
else
mainWindow.codeView.fromLine = #mainWindow.codeView.lines
end
end
end
elseif not eventData[1] then
cursor.blinkState = oldCursorState
end
mainWindow:draw()
if cursor.blinkState then
local x, y = mainWindow.codeView.codeAreaPosition + cursor.position.symbol - mainWindow.codeView.fromSymbol + 1, mainWindow.codeView.y + cursor.position.line - mainWindow.codeView.fromLine
if
x >= mainWindow.codeView.codeAreaPosition + 1 and
x <= mainWindow.codeView.codeAreaPosition + mainWindow.codeView.codeAreaWidth - 2 and
y >= mainWindow.codeView.y and
y <= mainWindow.codeView.y + mainWindow.codeView.height - 2
then
buffer.text(x, y, cursor.color, cursor.symbol)
end
end
buffer.draw()
end
end
-----------------------------------------------------------------------------------------------------------------------------
buffer.start()
createWindow()
calculateSizes()
loadFile("/OS.lua")
mainWindow.drawShadow = true
mainWindow:draw()
buffer.draw()
mainWindow.drawShadow = false
setCursorPosition(1, 1)
mainWindow:handleEvents(cursor.blinkDelay)