Advertisement
Guest User

Untitled

a guest
Oct 24th, 2019
106
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 59.75 KB | None | 0 0
  1. local filesystem = require("Filesystem")
  2. local screen = require("Screen")
  3. local event = require("Event")
  4. local keyboard = require("Keyboard")
  5. local GUI = require("GUI")
  6. local internet = require("Internet")
  7. local system = require("System")
  8. local paths = require("Paths")
  9. local text = require("Text")
  10. local number = require("Number")
  11.  
  12. ------------------------------------------------------------
  13.  
  14. local config = {
  15.     leftTreeViewWidth = 23,
  16.     syntaxColorScheme = GUI.LUA_SYNTAX_COLOR_SCHEME,
  17.     scrollSpeed = 8,
  18.     cursorColor = 0x00A8FF,
  19.     cursorSymbol = "┃",
  20.     cursorBlinkDelay = 0.5,
  21.     doubleClickDelay = 0.4,
  22.     enableAutoBrackets = true,
  23.     syntaxHighlight = true,
  24.     enableAutocompletion = true,
  25.     linesToShowOpenProgress = 150,
  26. }
  27.  
  28. local openBrackets = {
  29.     ["{"] = "}",
  30.     ["["] = "]",
  31.     ["("] = ")",
  32.     ["\""] = "\"",
  33.     ["\'"] = "\'"
  34. }
  35.  
  36. local closeBrackets = {
  37.     ["}"] = "{",
  38.     ["]"] = "[",
  39.     [")"] = "(",
  40.     ["\""] = "\"",
  41.     ["\'"] = "\'"
  42. }
  43.  
  44. local luaKeywords = {
  45.     ["do"] = true,
  46.     ["local"] = true,
  47.     ["return"] = true,
  48.     ["while"] = true,
  49.     ["repeat"] = true,
  50.     ["until"] = true,
  51.     ["for"] = true,
  52.     ["in"] = true,
  53.     ["if"] = true,
  54.     ["then"] = true,
  55.     ["else"] = true,
  56.     ["elseif"] = true,
  57.     ["end"] = true,
  58.     ["function"] = true,
  59.     ["true"] = true,
  60.     ["false"] = true,
  61.     ["nil"] = true,
  62.     ["not"] = true,
  63.     ["and"] = true,
  64.     ["or" ] = true,
  65. }
  66.  
  67. local lines = {""}
  68. local cursorPositionSymbol = 1
  69. local cursorPositionLine = 1
  70. local cursorBlinkState = false
  71.  
  72. local saveContextMenuItem
  73. local cursorUptime = computer.uptime()
  74. local scriptCoroutine
  75. local currentScriptDirectory = filesystem.path(system.getCurrentScript())
  76. local configPath = paths.user.applicationData .. "MineCode IDE/Config9.cfg"
  77. local localization = system.getLocalization(currentScriptDirectory .. "Localizations/")
  78. local findStartFrom
  79. local clipboard
  80. local breakpointLines
  81. local lastErrorLine
  82. local autocompleteDatabase
  83. local autoCompleteWordStart, autoCompleteWordEnd
  84. local continue, showBreakpointMessage, showTip
  85.  
  86. ------------------------------------------------------------
  87.  
  88. if filesystem.exists(configPath) then
  89.     config = filesystem.readTable(configPath)
  90. end
  91.  
  92. local workspace, window, menu = system.addWindow(GUI.window(1, 1, 120, 30))
  93. menu:removeChildren()
  94.  
  95. local codeView = window:addChild(GUI.codeView(1, 1, 1, 1, 1, 1, 1, {}, {}, GUI.LUA_SYNTAX_PATTERNS, config.syntaxColorScheme, config.syntaxHighlight, lines))
  96.  
  97. local function convertScreenCoordinatesToTextPosition(x, y)
  98.     return
  99.         x - codeView.codeAreaPosition + codeView.fromSymbol - 1,
  100.         y - codeView.y + codeView.fromLine
  101. end
  102.  
  103. local overrideCodeViewDraw = codeView.draw
  104. codeView.draw = function(...)
  105.     overrideCodeViewDraw(...)
  106.  
  107.     if cursorBlinkState then
  108.         local x, y = codeView.codeAreaPosition + cursorPositionSymbol - codeView.fromSymbol + 1, codeView.y + cursorPositionLine - codeView.fromLine
  109.         if
  110.             x >= codeView.codeAreaPosition + 1 and
  111.             y >= codeView.y and
  112.             x <= codeView.codeAreaPosition + codeView.codeAreaWidth - 2 and
  113.             y <= codeView.y + codeView.height - (codeView.horizontalScrollBar.hidden and 1 or 2)
  114.         then
  115.             screen.drawText(x, y, config.cursorColor, config.cursorSymbol)
  116.         end
  117.     end
  118. end
  119.  
  120. local function saveConfig()
  121.     filesystem.writeTable(configPath, config)
  122. end
  123.  
  124. local topToolBar = window:addChild(GUI.container(1, 1, 1, 3))
  125. local topToolBarPanel = topToolBar:addChild(GUI.panel(1, 1, 1, 3, 0xE1E1E1))
  126.  
  127. local topLayout = topToolBar:addChild(GUI.layout(1, 1, 1, 3, 1, 1))
  128. topLayout:setDirection(1, 1, GUI.DIRECTION_HORIZONTAL)
  129. topLayout:setSpacing(1, 1, 2)
  130. topLayout:setAlignment(1, 1, GUI.ALIGNMENT_HORIZONTAL_CENTER, GUI.ALIGNMENT_VERTICAL_TOP)
  131.  
  132. local autocomplete = window:addChild(GUI.autoComplete(1, 1, 36, 7, 0xE1E1E1, 0xA5A5A5, 0x3C3C3C, 0x3C3C3C, 0xA5A5A5, 0xE1E1E1, 0xC3C3C3, 0x4B4B4B))
  133.  
  134. local addBreakpointButton = topLayout:addChild(GUI.adaptiveButton(1, 1, 3, 1, 0x878787, 0xE1E1E1, 0xD2D2D2, 0x4B4B4B, "x"))
  135.  
  136. local syntaxHighlightingButton = topLayout:addChild(GUI.adaptiveButton(1, 1, 3, 1, 0xD2D2D2, 0x4B4B4B, 0x696969, 0xE1E1E1, "◈"))
  137. syntaxHighlightingButton.switchMode = true
  138. syntaxHighlightingButton.pressed = codeView.syntaxHighlight
  139.  
  140. local runButton = topLayout:addChild(GUI.adaptiveButton(1, 1, 3, 1, 0x4B4B4B, 0xE1E1E1, 0xD2D2D2, 0x4B4B4B, "▷"))
  141.  
  142. local title = topLayout:addChild(GUI.object(1, 1, 1, 3))
  143. local titleLines = {}
  144. local titleDebugMode = false
  145. title.eventHandler = nil
  146. title.draw = function()
  147.     local sides = titleDebugMode and 0xCC4940 or 0x5A5A5A
  148.     screen.drawRectangle(title.x, title.y, 1, title.height, sides, 0x0, " ")
  149.     screen.drawRectangle(title.x + title.width - 1, title.y, 1, title.height, sides, 0x0, " ")
  150.     screen.drawRectangle(title.x + 1, title.y, title.width - 2, 3, titleDebugMode and 0x880000 or 0x3C3C3C, 0x969696, " ")
  151.  
  152.     if titleDebugMode then
  153.         local text = lastErrorLine and localization.runtimeError or localization.debugging .. (_G.MineCodeIDEDebugInfo and _G.MineCodeIDEDebugInfo.line or "N/A")
  154.         screen.drawText(math.floor(title.x + title.width / 2 - unicode.len(text) / 2), title.y + 1, 0xE1E1E1, text)
  155.     else
  156.         for i = 1, #titleLines do
  157.             screen.drawText(math.floor(title.x + title.width / 2 - unicode.len(titleLines[i]) / 2), title.y + i - 1, 0x969696, titleLines[i])
  158.         end
  159.     end
  160. end
  161.  
  162. local toggleLeftToolBarButton = topLayout:addChild(GUI.adaptiveButton(1, 1, 3, 1, 0xD2D2D2, 0x4B4B4B, 0x4B4B4B, 0xE1E1E1, "⇦"))
  163. toggleLeftToolBarButton.switchMode, toggleLeftToolBarButton.pressed = true, true
  164.  
  165. local toggleBottomToolBarButton = topLayout:addChild(GUI.adaptiveButton(1, 1, 3, 1, 0xD2D2D2, 0x4B4B4B, 0x696969, 0xE1E1E1, "⇩"))
  166. toggleBottomToolBarButton.switchMode, toggleBottomToolBarButton.pressed = true, false
  167.  
  168. local toggleTopToolBarButton = topLayout:addChild(GUI.adaptiveButton(1, 1, 3, 1, 0xD2D2D2, 0x4B4B4B, 0x878787, 0xE1E1E1, "⇧"))
  169. toggleTopToolBarButton.switchMode, toggleTopToolBarButton.pressed = true, true
  170.  
  171. local actionButtons = window:addChild(GUI.actionButtons(2, 2, true))
  172. actionButtons.close.onTouch = function()
  173.     window:remove()
  174. end
  175. actionButtons.maximize.onTouch = function()
  176.     window:maximize()
  177. end
  178. actionButtons.minimize.onTouch = function()
  179.     window:minimize()
  180. end
  181.  
  182. local bottomToolBar = window:addChild(GUI.container(1, 1, 1, 3))
  183. bottomToolBar.hidden = true
  184.  
  185. local caseSensitiveButton = bottomToolBar:addChild(GUI.adaptiveButton(1, 1, 2, 1, 0x3C3C3C, 0xE1E1E1, 0xB4B4B4, 0x2D2D2D, "Aa"))
  186. caseSensitiveButton.switchMode = true
  187.  
  188. local searchInput = bottomToolBar:addChild(GUI.input(7, 1, 10, 3, 0xE1E1E1, 0x969696, 0x969696, 0xE1E1E1, 0x2D2D2D, "", localization.findSomeShit))
  189.  
  190. local searchButton = bottomToolBar:addChild(GUI.adaptiveButton(1, 1, 3, 1, 0x3C3C3C, 0xE1E1E1, 0xB4B4B4, 0x2D2D2D, localization.find))
  191.  
  192. local leftTreeView = window:addChild(GUI.filesystemTree(1, 1, config.leftTreeViewWidth, 1, 0xD2D2D2, 0x3C3C3C, 0x3C3C3C, 0x969696, 0x3C3C3C, 0xE1E1E1, 0xB4B4B4, 0xA5A5A5, 0xB4B4B4, 0x4B4B4B, GUI.IO_MODE_BOTH, GUI.IO_MODE_FILE))
  193.  
  194. local leftTreeViewResizer = window:addChild(GUI.resizer(1, 1, 3, 5, 0x696969, 0x0))
  195.  
  196. local function updateHighlights()
  197.     codeView.highlights = {}
  198.  
  199.     if breakpointLines then
  200.         for i = 1, #breakpointLines do
  201.             codeView.highlights[breakpointLines[i]] = 0x990000
  202.         end
  203.     end
  204.  
  205.     if lastErrorLine then
  206.         codeView.highlights[lastErrorLine] = 0xFF4940
  207.     end
  208. end
  209.  
  210. local function updateTitle()
  211.     if not topToolBar.hidden then
  212.         titleLines[1] = text.limit(leftTreeView.selectedItem or "...", title.width - 4, "left")
  213.         titleLines[2] = text.limit(localization.cursor .. math.floor(cursorPositionLine) .. localization.line .. math.floor(cursorPositionSymbol) .. localization.symbol, title.width - 4)
  214.        
  215.         if codeView.selections[1] then
  216.             local countOfSelectedLines, countOfSelectedSymbols = codeView.selections[1].to.line - codeView.selections[1].from.line + 1
  217.            
  218.             if codeView.selections[1].from.line == codeView.selections[1].to.line then
  219.                 countOfSelectedSymbols = unicode.len(unicode.sub(lines[codeView.selections[1].from.line], codeView.selections[1].from.symbol, codeView.selections[1].to.symbol))
  220.             else
  221.                 countOfSelectedSymbols = unicode.len(unicode.sub(lines[codeView.selections[1].from.line], codeView.selections[1].from.symbol, -1))
  222.                
  223.                 for line = codeView.selections[1].from.line + 1, codeView.selections[1].to.line - 1 do
  224.                     countOfSelectedSymbols = countOfSelectedSymbols + unicode.len(lines[line])
  225.                 end
  226.                
  227.                 countOfSelectedSymbols = countOfSelectedSymbols + unicode.len(unicode.sub(lines[codeView.selections[1].to.line], 1, codeView.selections[1].to.symbol))
  228.             end
  229.  
  230.             titleLines[3] = text.limit(localization.selection .. math.floor(countOfSelectedLines) .. localization.lines .. math.floor(countOfSelectedSymbols) .. localization.symbols, title.width - 4)
  231.         else
  232.             titleLines[3] = text.limit(localization.selection .. localization.none, title.width - 4)
  233.         end
  234.     end
  235. end
  236.  
  237. local function tick(state)
  238.     cursorBlinkState = state
  239.     updateTitle()
  240.     workspace:draw()
  241.  
  242.     cursorUptime = computer.uptime()
  243. end
  244.  
  245. local function clearAutocompleteDatabaseFromLine(line)
  246.     for word in lines[line]:gmatch("[%a%d%_]+") do
  247.         if not word:match("^%d+$") then
  248.             autocompleteDatabase[word] = (autocompleteDatabase[word] or 0) - 1
  249.             if autocompleteDatabase[word] < 1 then
  250.                 autocompleteDatabase[word] = nil
  251.             end
  252.         end
  253.     end
  254. end
  255.  
  256. local function updateAutocompleteDatabaseFromLine(line)
  257.     for word in lines[line]:gmatch("[%a%d%_]+") do
  258.         if not word:match("^%d+$") then
  259.             autocompleteDatabase[word] = (autocompleteDatabase[word] or 0) + 1
  260.         end
  261.     end
  262. end
  263.  
  264. local function updateAutocompleteDatabaseFromAllLines()
  265.     if config.enableAutocompletion then
  266.         autocompleteDatabase = {}
  267.         for line = 1, #lines do
  268.             updateAutocompleteDatabaseFromLine(line)
  269.         end
  270.     end
  271. end
  272.  
  273. local function getautoCompleteWordStartAndEnding(fromSymbol)
  274.     local shittySymbolsRegexp, from, to = "[%s%c%p]"
  275.  
  276.     for i = fromSymbol, 1, -1 do
  277.         if unicode.sub(lines[cursorPositionLine], i, i):match(shittySymbolsRegexp) then break end
  278.         from = i
  279.     end
  280.  
  281.     for i = fromSymbol, unicode.len(lines[cursorPositionLine]) do
  282.         if unicode.sub(lines[cursorPositionLine], i, i):match(shittySymbolsRegexp) then break end
  283.         to = i
  284.     end
  285.  
  286.     return from, to
  287. end
  288.  
  289. local function aplhabeticalSort(t)
  290.     table.sort(t, function(a, b) return a[1] < b[1] end)
  291. end
  292.  
  293. local function showAutocomplete()
  294.     if config.enableAutocompletion then
  295.         autoCompleteWordStart, autoCompleteWordEnd = getautoCompleteWordStartAndEnding(cursorPositionSymbol - 1)
  296.         if autoCompleteWordStart then
  297.             local word = unicode.sub(lines[cursorPositionLine], autoCompleteWordStart, autoCompleteWordEnd)
  298.             if not luaKeywords[word] then
  299.                 autocomplete:match(autocompleteDatabase, word, true)
  300.  
  301.                 if #autocomplete.items > 0 then
  302.                     autocomplete.fromItem, autocomplete.selectedItem = 1, 1
  303.                     autocomplete.localX = codeView.localX + codeView.lineNumbersWidth + autoCompleteWordStart - codeView.fromSymbol
  304.                     autocomplete.localY = codeView.localY + cursorPositionLine - codeView.fromLine + 1
  305.                     autocomplete.hidden = false
  306.                 end
  307.             end
  308.         end
  309.     end
  310. end
  311.  
  312. local function toggleEnableAutocompleteDatabase()
  313.     config.enableAutocompletion = not config.enableAutocompletion
  314.     autocompleteDatabase = {}
  315.     saveConfig()
  316. end
  317.  
  318. local function calculateSizes()
  319.     if leftTreeView.hidden then
  320.         codeView.localX, codeView.width = 1, window.width
  321.         bottomToolBar.localX, bottomToolBar.width = codeView.localX, codeView.width
  322.     else
  323.         codeView.localX, codeView.width = leftTreeView.width + 1, window.width - leftTreeView.width
  324.         bottomToolBar.localX, bottomToolBar.width = codeView.localX, codeView.width
  325.     end
  326.  
  327.     if topToolBar.hidden then
  328.         leftTreeView.localY, leftTreeView.height = 1, window.height
  329.         codeView.localY, codeView.height = 1, window.height
  330.     else
  331.         leftTreeView.localY, leftTreeView.height = 4, window.height - 3
  332.         codeView.localY, codeView.height = 4, window.height - 3
  333.     end
  334.  
  335.     if not bottomToolBar.hidden then
  336.         codeView.height = codeView.height - 3
  337.     end
  338.  
  339.     leftTreeViewResizer.localX = leftTreeView.width
  340.     leftTreeViewResizer.localY = math.floor(leftTreeView.localY + leftTreeView.height / 2 - leftTreeViewResizer.height / 2)
  341.  
  342.     bottomToolBar.localY = window.height - 2
  343.     searchButton.localX = bottomToolBar.width - searchButton.width + 1
  344.     searchInput.width = bottomToolBar.width - searchInput.localX - searchButton.width + 1
  345.  
  346.     topToolBar.width, topToolBarPanel.width, topLayout.width = window.width, window.width, window.width
  347.     title.width = math.floor(topToolBar.width * 0.32)
  348.  
  349.     -- topMenu.width = window.width
  350. end
  351.  
  352. local function gotoLine(line)
  353.     codeView.fromLine = math.ceil(line - codeView.height / 2)
  354.     if codeView.fromLine < 1 then
  355.         codeView.fromLine = 1
  356.     elseif codeView.fromLine > #lines then
  357.         codeView.fromLine = #lines
  358.     end
  359. end
  360.  
  361. local function clearSelection()
  362.     codeView.selections[1] = nil
  363. end
  364.  
  365. local function clearBreakpoints()
  366.     breakpointLines = nil
  367.     updateHighlights()
  368. end
  369.  
  370. local function addBreakpoint()
  371.     breakpointLines = breakpointLines or {}
  372.    
  373.     local lineExists
  374.     for i = 1, #breakpointLines do
  375.         if breakpointLines[i] == cursorPositionLine then
  376.             lineExists = i
  377.             break
  378.         end
  379.     end
  380.    
  381.     if lineExists then
  382.         table.remove(breakpointLines, lineExists)
  383.     else
  384.         table.insert(breakpointLines, cursorPositionLine)
  385.     end
  386.  
  387.     if #breakpointLines > 0 then
  388.         table.sort(breakpointLines, function(a, b) return a < b end)
  389.     else
  390.         breakpointLines = nil
  391.     end
  392.  
  393.     updateHighlights()
  394. end
  395.  
  396. local function fixFromLineByCursorPosition()
  397.     local offset = codeView.horizontalScrollBar.hidden and 1 or 2
  398.     if codeView.fromLine > cursorPositionLine then
  399.         codeView.fromLine = cursorPositionLine
  400.     elseif codeView.fromLine + codeView.height - offset < cursorPositionLine then
  401.         codeView.fromLine = cursorPositionLine - codeView.height + offset
  402.     end
  403. end
  404.  
  405. local function fixFromSymbolByCursorPosition()
  406.     if codeView.fromSymbol > cursorPositionSymbol then
  407.         codeView.fromSymbol = cursorPositionSymbol
  408.     elseif codeView.fromSymbol + codeView.codeAreaWidth - 3 < cursorPositionSymbol then
  409.         codeView.fromSymbol = cursorPositionSymbol - codeView.codeAreaWidth + 3
  410.     end
  411. end
  412.  
  413. local function fixCursorPosition(symbol, line)
  414.     if line < 1 then
  415.         line = 1
  416.     elseif line > #lines then
  417.         line = #lines
  418.     end
  419.  
  420.     local lineLength = unicode.len(lines[line])
  421.     if symbol < 1 or lineLength == 0 then
  422.         symbol = 1
  423.     elseif symbol > lineLength then
  424.         symbol = lineLength + 1
  425.     end
  426.  
  427.     return math.floor(symbol), math.floor(line)
  428. end
  429.  
  430. local function setCursorPosition(symbol, line)
  431.     cursorPositionSymbol, cursorPositionLine = fixCursorPosition(symbol, line)
  432.     fixFromLineByCursorPosition()
  433.     fixFromSymbolByCursorPosition()
  434.     autocomplete.hidden = true
  435. end
  436.  
  437. local function setCursorPositionAndClearSelection(symbol, line)
  438.     setCursorPosition(symbol, line)
  439.     clearSelection()
  440. end
  441.  
  442. local function moveCursor(symbolOffset, lineOffset, ignoreHidden)
  443.     if autocomplete.hidden or ignoreHidden then
  444.         if codeView.selections[1] then
  445.             if symbolOffset < 0 or lineOffset < 0 then
  446.                 setCursorPositionAndClearSelection(codeView.selections[1].from.symbol, codeView.selections[1].from.line)
  447.             else
  448.                 setCursorPositionAndClearSelection(codeView.selections[1].to.symbol, codeView.selections[1].to.line)
  449.             end
  450.         else
  451.             local newSymbol, newLine = cursorPositionSymbol + symbolOffset, cursorPositionLine + lineOffset
  452.            
  453.             if symbolOffset < 0 and newSymbol < 1 then
  454.                 newLine, newSymbol = newLine - 1, math.huge
  455.             elseif symbolOffset > 0 and newSymbol > unicode.len(lines[newLine] or "") + 1 then
  456.                 newLine, newSymbol = newLine + 1, 1
  457.             end
  458.  
  459.             setCursorPosition(newSymbol, newLine)
  460.         end
  461.     end
  462. end
  463.  
  464. local function setCursorPositionToHome()
  465.     setCursorPositionAndClearSelection(1, 1)
  466. end
  467.  
  468. local function setCursorPositionToEnd()
  469.     setCursorPositionAndClearSelection(unicode.len(lines[#lines]) + 1, #lines)
  470. end
  471.  
  472. local function scroll(direction, speed)
  473.     if direction == 1 then
  474.         if codeView.fromLine > speed then
  475.             codeView.fromLine = codeView.fromLine - speed
  476.         else
  477.             codeView.fromLine = 1
  478.         end
  479.     else
  480.         if codeView.fromLine < #lines - speed then
  481.             codeView.fromLine = codeView.fromLine + speed
  482.         else
  483.             codeView.fromLine = #lines
  484.         end
  485.     end
  486. end
  487.  
  488. local function pageUp()
  489.     scroll(1, codeView.height - 2)
  490. end
  491.  
  492. local function pageDown()
  493.     scroll(-1, codeView.height - 2)
  494. end
  495.  
  496. local function selectWord()
  497.     local from, to = getautoCompleteWordStartAndEnding(cursorPositionSymbol)
  498.     if from and to then
  499.         codeView.selections[1] = {
  500.             from = {symbol = from, line = cursorPositionLine},
  501.             to = {symbol = to, line = cursorPositionLine},
  502.         }
  503.         cursorPositionSymbol = to
  504.     end
  505. end
  506.  
  507. local function optimizeString(s)
  508.     return s:gsub("\t", string.rep(" ", codeView.indentationWidth)):gsub("\r\n", "\n")
  509. end
  510.  
  511. local function addBackgroundContainer(title)
  512.     return GUI.addBackgroundContainer(workspace, true, true, title)
  513. end
  514.  
  515. local function addInputFadeContainer(title, placeholder)
  516.     local container = addBackgroundContainer(title)
  517.     container.input = container.layout:addChild(GUI.input(1, 1, 36, 3, 0xC3C3C3, 0x787878, 0x787878, 0xC3C3C3, 0x2D2D2D, "", placeholder))
  518.  
  519.     return container
  520. end
  521.  
  522. local function newFile()
  523.     autocompleteDatabase = {}
  524.     lines = {""}
  525.     codeView.lines = lines
  526.     codeView.maximumLineLength = 1
  527.     leftTreeView.selectedItem = nil
  528.     setCursorPositionAndClearSelection(1, 1)
  529.     clearBreakpoints()
  530.     updateTitle()
  531. end
  532.  
  533. local function openFile(path)
  534.     local file, reason = filesystem.open(path, "r")
  535.     if file then
  536.         newFile()
  537.         leftTreeView.selectedItem = path
  538.         codeView.hidden = true
  539.  
  540.         local container = window:addChild(GUI.container(codeView.localX, codeView.localY, codeView.width, codeView.height))
  541.         container:addChild(GUI.panel(1, 1, container.width, container.height, 0x1E1E1E))
  542.        
  543.         local layout = container:addChild(GUI.layout(1, 1, container.width, container.height, 1, 1))
  544.        
  545.         layout:addChild(GUI.label(1, 1, layout.width, 1, 0xD2D2D2, localization.openingFile .. " " .. path):setAlignment(GUI.ALIGNMENT_HORIZONTAL_CENTER, GUI.ALIGNMENT_VERTICAL_TOP))
  546.         local progressBar = layout:addChild(GUI.progressBar(1, 1, 36, 0x969696, 0x2D2D2D, 0x787878, 0, true, true, "", "%"))
  547.  
  548.         local counter, currentSize, totalSize = 1, 0, filesystem.size(path)
  549.         for line in file:lines() do
  550.             line = optimizeString(line)
  551.             table.insert(lines, line)
  552.             codeView.maximumLineLength = math.max(codeView.maximumLineLength, unicode.len(line))
  553.            
  554.             counter, currentSize = counter + 1, currentSize + #line
  555.             if counter % config.linesToShowOpenProgress == 0 then
  556.                 progressBar.value = math.floor(currentSize / totalSize * 100)
  557.                 computer.pullSignal(0)
  558.                 workspace:draw()
  559.             end
  560.         end
  561.  
  562.         file:close()
  563.  
  564.         if #lines > 1 then
  565.             table.remove(lines, 1)
  566.         end
  567.  
  568.         if counter > config.linesToShowOpenProgress then
  569.             progressBar.value = 100
  570.             workspace:draw()
  571.         end
  572.  
  573.         codeView.hidden = false
  574.         container:remove()
  575.         updateAutocompleteDatabaseFromAllLines()
  576.         updateTitle()
  577.         saveContextMenuItem.disabled = false
  578.     else
  579.         GUI.alert(reason)
  580.     end
  581. end
  582.  
  583. local function saveFile(path)
  584.     filesystem.makeDirectory(filesystem.path(path))
  585.     local file, reason = filesystem.open(path, "w")
  586.     if file then
  587.         for line = 1, #lines do
  588.             file:write(lines[line], "\n")
  589.         end
  590.         file:close()
  591.  
  592.         saveContextMenuItem.disabled = false
  593.     else
  594.         GUI.alert("Failed to open file for writing: " .. tostring(reason))
  595.     end
  596. end
  597.  
  598. local function gotoLineWindow()
  599.     local container = addInputFadeContainer(localization.gotoLine, localization.lineNumber)
  600.  
  601.     container.input.onInputFinished = function()
  602.         if container.input.text:match("%d+") then
  603.             gotoLine(tonumber(container.input.text))
  604.             container:remove()
  605.             workspace:draw()
  606.         end
  607.     end
  608.  
  609.     workspace:draw()
  610. end
  611.  
  612. local function openFileWindow()
  613.     local filesystemDialog = GUI.addFilesystemDialog(workspace, true, 50, math.floor(window.height * 0.8), "Open", "Cancel", "File name", "/")
  614.     filesystemDialog:setMode(GUI.IO_MODE_OPEN, GUI.IO_MODE_FILE)
  615.     filesystemDialog.onSubmit = function(path)
  616.         openFile(path)
  617.         workspace:draw()
  618.     end
  619.     filesystemDialog:show()
  620. end
  621.  
  622. local function saveFileAsWindow()
  623.     local filesystemDialog = GUI.addFilesystemDialog(workspace, true, 50, math.floor(window.height * 0.8), "Save", "Cancel", "File name", "/")
  624.     filesystemDialog:setMode(GUI.IO_MODE_SAVE, GUI.IO_MODE_FILE)
  625.     filesystemDialog.onSubmit = function(path)
  626.         saveFile(path)
  627.         leftTreeView:updateFileList()
  628.         leftTreeView.selectedItem = (leftTreeView.workPath .. path):gsub("/+", "/")
  629.  
  630.         updateTitle()
  631.         workspace:draw()
  632.     end
  633.     filesystemDialog:show()
  634. end
  635.  
  636. local function saveFileWindow()
  637.     saveFile(leftTreeView.selectedItem)
  638.     leftTreeView:updateFileList()
  639. end
  640.  
  641. local function splitStringIntoLines(s)
  642.     s = optimizeString(s)
  643.  
  644.     local lines, index, maximumLineLength, starting = {s}, 1, 0
  645.     repeat
  646.         starting = lines[index]:find("\n")
  647.         if starting then
  648.             table.insert(lines, lines[index]:sub(starting + 1, -1))
  649.             lines[index] = lines[index]:sub(1, starting - 1)
  650.             maximumLineLength = math.max(maximumLineLength, unicode.len(lines[index]))
  651.  
  652.             index = index + 1
  653.         end
  654.     until not starting
  655.  
  656.     return lines, maximumLineLength
  657. end
  658.  
  659. local function downloadFileFromWeb()
  660.     local container = addInputFadeContainer(localization.getFromWeb, localization.url)
  661.    
  662.     container.input.onInputFinished = function()
  663.         if #container.input.text > 0 then
  664.             container.input:remove()
  665.             container.layout:addChild(GUI.text(1, 1, 0x969696, localization.downloading))
  666.             workspace:draw()
  667.  
  668.             local result, reason = internet.request(container.input.text)
  669.             if result then
  670.                 newFile()
  671.                 lines, codeView.maximumLineLength = splitStringIntoLines(result)
  672.                 codeView.lines = lines
  673.                 updateAutocompleteDatabaseFromAllLines()
  674.             else
  675.                 GUI.alert("Failed to connect to URL: " .. tostring(reason))
  676.             end
  677.         end
  678.  
  679.         container:remove()
  680.         workspace:draw()
  681.     end
  682.  
  683.     workspace:draw()
  684. end
  685.  
  686. local function getVariables(codePart)
  687.     local variables = {}
  688.     -- Сначала мы проверяем участок кода на наличие комментариев
  689.     if
  690.         not codePart:match("^%-%-") and
  691.         not codePart:match("^[\t%s]+%-%-")
  692.     then
  693.         -- Затем заменяем все строковые куски в участке кода на "ничего", чтобы наш "прекрасный" парсер не искал переменных в строках
  694.         codePart = codePart:gsub("\"[^\"]+\"", "")
  695.         -- Потом разбиваем код на отдельные буквенно-цифровые слова, не забыв точечку с двоеточием
  696.         for word in codePart:gmatch("[%a%d%.%:%_]+") do
  697.             -- Далее проверяем, не совпадает ли это слово с одним из луа-шаблонов, то бишь, не является ли оно частью синтаксиса
  698.             if
  699.                 not luaKeywords[word] and
  700.                 -- Также проверяем, не число ли это в чистом виде
  701.                 not word:match("^[%d%.]+$") and
  702.                 not word:match("^0x%x+$") and
  703.                 -- Или символ конкатенации, например
  704.                 not word:match("^%.+$")
  705.             then
  706.                 variables[word] = true
  707.             end
  708.         end
  709.     end
  710.  
  711.     return variables
  712. end
  713.  
  714. continue = function(...)
  715.     -- Готовим экран к запуску
  716.     local oldResolutionX, oldResolutionY = screen.getResolution()
  717.    
  718.     -- Запускаем
  719.     _G.MineCodeIDEDebugInfo = nil
  720.     local coroutineResumeSuccess, coroutineResumeReason = coroutine.resume(scriptCoroutine, ...)
  721.  
  722.     -- Анализируем результат запуска
  723.     if coroutineResumeSuccess then
  724.         if coroutine.status(scriptCoroutine) == "dead" then
  725.             screen.setResolution(oldResolutionX, oldResolutionY)
  726.             workspace:draw(true)
  727.         else
  728.             -- Тест на пидора, мало ли у чувака в проге тоже есть yield
  729.             if _G.MineCodeIDEDebugInfo then
  730.                 screen.setResolution(oldResolutionX, oldResolutionY)
  731.                 workspace:draw(true)
  732.                 gotoLine(_G.MineCodeIDEDebugInfo.line)
  733.                 showBreakpointMessage(_G.MineCodeIDEDebugInfo.variables)
  734.             end
  735.         end
  736.     else
  737.         screen.setResolution(oldResolutionX, oldResolutionY)
  738.         showTip(debug.traceback(scriptCoroutine, coroutineResumeReason), "%:(%d+)%: in main chunk", true, true)
  739.     end
  740. end
  741.  
  742. local function run(...)
  743.     -- Инсертим брейкпоинты
  744.     if breakpointLines then
  745.         local offset = 0
  746.         for i = 1, #breakpointLines do
  747.             local variables = getVariables(lines[breakpointLines[i] + offset])
  748.            
  749.             local breakpointMessage = "_G.MineCodeIDEDebugInfo = {variables = {"
  750.             for variable in pairs(variables) do
  751.                 breakpointMessage = breakpointMessage .. "[\"" .. variable .. "\"] = type(" .. variable .. ") == 'string' and '\"' .. " .. variable .. " .. '\"' or tostring(" .. variable .. "), "
  752.             end
  753.             breakpointMessage =  breakpointMessage .. "}, line = " .. breakpointLines[i] .. "}; coroutine.yield()"
  754.  
  755.             table.insert(lines, breakpointLines[i] + offset, breakpointMessage)
  756.             offset = offset + 1
  757.         end
  758.     end
  759.  
  760.     -- Лоадим кодыч
  761.     local loadSuccess, loadReason = load(table.concat(lines, "\n"), leftTreeView.selectedItem and ("=" .. leftTreeView.selectedItem))
  762.    
  763.     -- Чистим дерьмо вилочкой, чистим
  764.     if breakpointLines then
  765.         for i = 1, #breakpointLines do
  766.             table.remove(lines, breakpointLines[i])
  767.         end
  768.     end
  769.  
  770.     -- Запускаем кодыч
  771.     if loadSuccess then
  772.         scriptCoroutine = coroutine.create(loadSuccess)
  773.         continue(...)
  774.     else
  775.         showTip(loadReason, "%:(%d+)%:", true)
  776.     end
  777. end
  778.  
  779. local function zalupa()
  780.     local container = window:addChild(GUI.container(1, 1, window.width, window.height))
  781.  
  782.     container.close = function()
  783.         lastErrorLine = nil
  784.         titleDebugMode = false
  785.         updateHighlights()
  786.        
  787.         container:remove()
  788.         workspace:draw()
  789.     end
  790.  
  791.     container:addChild(GUI.object(1, 1, window.width, window.height)).eventHandler = function(workspace, object, e1)
  792.         if e1 == "touch" or e1 == "key_down" then
  793.             container.close()
  794.         end
  795.     end
  796.  
  797.     return container
  798. end
  799.  
  800. showTip = function(errorCode, matchCode, beep, force)
  801.     -- Извлекаем ошибочную строку текущего скрипта
  802.     lastErrorLine = tonumber(errorCode:match(matchCode))
  803.     if lastErrorLine then
  804.         -- Делаем поправку на количество брейкпоинтов в виде вставленных дебаг-строк
  805.         if breakpointLines then
  806.             local countOfBreakpointsBeforeLastErrorLine = 0
  807.             for i = 1, #breakpointLines do
  808.                 if breakpointLines[i] < lastErrorLine then
  809.                     countOfBreakpointsBeforeLastErrorLine = countOfBreakpointsBeforeLastErrorLine + 1
  810.                 else
  811.                     break
  812.                 end
  813.             end
  814.        
  815.             lastErrorLine = lastErrorLine - countOfBreakpointsBeforeLastErrorLine
  816.         end
  817.  
  818.         gotoLine(lastErrorLine)
  819.     end
  820.  
  821.     updateHighlights()
  822.  
  823.     local container = zalupa()
  824.     local tip, tipLines = container:addChild(GUI.object(1, 1, 40))
  825.  
  826.     tip.passScreenEvents = true
  827.     tip.draw = function()
  828.         screen.drawText(math.floor(tip.x + tip.width / 2 - 1), tip.y, 0xE1E1E1, "◢◣")
  829.         screen.drawRectangle(tip.x, tip.y + 1, tip.width, tip.height - 1, 0xE1E1E1, 0x2D2D2D, " ")
  830.         for i = 1, #tipLines do
  831.             screen.drawText(tip.x + 1, tip.y + i + 1, 0x2D2D2D, tipLines[i])
  832.         end
  833.     end
  834.  
  835.     tipLines = text.wrap(errorCode, tip.width - 2)
  836.     tip.height = #tipLines + 3
  837.  
  838.     local minX = codeView.localX + codeView.codeAreaPosition - codeView.x
  839.     local maxX = minX + codeView.width - tip.width - 5
  840.  
  841.     tip.localX = math.min(maxX, math.max(minX + 1, number.round(minX + unicode.len(lines[lastErrorLine]) / 2 - tip.width / 2)))
  842.     tip.localY = codeView.localY + lastErrorLine - codeView.fromLine + 1
  843.  
  844.     workspace:draw(force)
  845.  
  846.     if beep then
  847.         computer.beep(1500, 0.08)
  848.     end
  849. end
  850.  
  851. showBreakpointMessage = function(variables)
  852.     local lines = {}
  853.    
  854.     for variable, value in pairs(variables) do
  855.         table.insert(lines, variable .. " = " .. value)
  856.     end
  857.  
  858.     if #lines > 0 then
  859.         table.insert(lines, 1, {text = localization.variables, color = 0x0})
  860.         table.insert(lines, 2, " ")
  861.     else
  862.         table.insert(lines, 1, {text = localization.variablesNotAvailable, color = 0x0})
  863.     end
  864.  
  865.     local container = zalupa()
  866.     local errorContainer = container:addChild(GUI.container(title.localX, topToolBar.hidden and 1 or 4, title.width, #lines + 3))
  867.     local panel = errorContainer:addChild(GUI.panel(1, 1, errorContainer.width, errorContainer.height, 0xE1E1E1))
  868.     local textBox = errorContainer:addChild(GUI.textBox(3, 2, errorContainer.width - 4, #lines, nil, 0x4B4B4B, lines, 1))
  869.     textBox:setAlignment(GUI.ALIGNMENT_HORIZONTAL_CENTER, GUI.ALIGNMENT_VERTICAL_TOP)
  870.  
  871.     local exitButton = errorContainer:addChild(GUI.button(1, errorContainer.height, math.floor(errorContainer.width / 2), 1, 0x3C3C3C, 0xC3C3C3, 0x2D2D2D, 0x878787, localization.finishDebug))
  872.     exitButton.animated = false
  873.     exitButton.onTouch = function()
  874.         scriptCoroutine = nil
  875.         container.close()
  876.     end
  877.    
  878.     local continueButton = errorContainer:addChild(GUI.button(exitButton.width + 1, exitButton.localY, errorContainer.width - exitButton.width, 1, 0x4B4B4B, 0xC3C3C3, 0x2D2D2D, 0x878787, localization.continueDebug))
  879.     continueButton.animated = false
  880.     continueButton.onTouch = function()
  881.         container.close()
  882.         continue()
  883.     end
  884.    
  885.     titleDebugMode = true
  886.     workspace:draw()
  887.  
  888.     computer.beep(1500, 0.08)
  889. end
  890.  
  891. local function launchWithArgumentsWindow()
  892.     local container = addInputFadeContainer(localization.launchWithArguments, localization.arguments)
  893.  
  894.     container.input.onInputFinished = function()
  895.         local arguments = {}
  896.         container.input.text = container.input.text:gsub(",%s+", ",")
  897.         for argument in container.input.text:gmatch("[^,]+") do
  898.             table.insert(arguments, argument)
  899.         end
  900.  
  901.         container:remove()
  902.         workspace:draw()
  903.  
  904.         run(table.unpack(arguments))
  905.     end
  906.  
  907.     workspace:draw()
  908. end
  909.  
  910. local function deleteLine(line)
  911.     clearAutocompleteDatabaseFromLine(line)
  912.    
  913.     if #lines > 1 then
  914.         table.remove(lines, line)
  915.     else
  916.         lines[1] = ""
  917.     end
  918.  
  919.     setCursorPositionAndClearSelection(1, cursorPositionLine)
  920. end
  921.  
  922. local function deleteSpecifiedData(fromSymbol, fromLine, toSymbol, toLine) 
  923.     clearAutocompleteDatabaseFromLine(fromLine)
  924.  
  925.     lines[fromLine] = unicode.sub(lines[fromLine], 1, fromSymbol - 1) .. unicode.sub(lines[toLine], toSymbol + 1, -1)
  926.     for line = fromLine + 1, toLine do
  927.         clearAutocompleteDatabaseFromLine(fromLine + 1)
  928.        
  929.         table.remove(lines, fromLine + 1)
  930.     end
  931.    
  932.     setCursorPositionAndClearSelection(fromSymbol, fromLine)
  933.     updateAutocompleteDatabaseFromLine(fromLine)
  934. end
  935.  
  936. local function deleteSelectedData()
  937.     if codeView.selections[1] then
  938.         deleteSpecifiedData(
  939.             codeView.selections[1].from.symbol,
  940.             codeView.selections[1].from.line,
  941.             codeView.selections[1].to.symbol,
  942.             codeView.selections[1].to.line
  943.         )
  944.  
  945.         clearSelection()
  946.     end
  947. end
  948.  
  949. local function copy()
  950.     if codeView.selections[1] then
  951.         if codeView.selections[1].to.line == codeView.selections[1].from.line then
  952.             clipboard = { unicode.sub(lines[codeView.selections[1].from.line], codeView.selections[1].from.symbol, codeView.selections[1].to.symbol) }
  953.         else
  954.             clipboard = { unicode.sub(lines[codeView.selections[1].from.line], codeView.selections[1].from.symbol, -1) }
  955.             for line = codeView.selections[1].from.line + 1, codeView.selections[1].to.line - 1 do
  956.                 table.insert(clipboard, lines[line])
  957.             end
  958.             table.insert(clipboard, unicode.sub(lines[codeView.selections[1].to.line], 1, codeView.selections[1].to.symbol))
  959.         end
  960.     end
  961. end
  962.  
  963. local function cut()
  964.     if codeView.selections[1] then
  965.         copy()
  966.         deleteSelectedData()
  967.     end
  968. end
  969.  
  970. local function paste(data, notTable)
  971.     if codeView.selections[1] then
  972.         deleteSelectedData()
  973.     end
  974.  
  975.     local firstPart = unicode.sub(lines[cursorPositionLine], 1, cursorPositionSymbol - 1)
  976.     local secondPart = unicode.sub(lines[cursorPositionLine], cursorPositionSymbol, -1)
  977.  
  978.     if notTable then
  979.         clearAutocompleteDatabaseFromLine(cursorPositionLine)
  980.  
  981.         lines[cursorPositionLine] = firstPart .. data .. secondPart
  982.         setCursorPositionAndClearSelection(cursorPositionSymbol + unicode.len(data), cursorPositionLine)
  983.  
  984.         updateAutocompleteDatabaseFromLine(cursorPositionLine)
  985.     else
  986.         if #data == 1 then
  987.             clearAutocompleteDatabaseFromLine(cursorPositionLine)
  988.  
  989.             lines[cursorPositionLine] = firstPart .. data[1] .. secondPart
  990.             setCursorPositionAndClearSelection(unicode.len(firstPart .. data[1]) + 1, cursorPositionLine)
  991.  
  992.             updateAutocompleteDatabaseFromLine(cursorPositionLine)
  993.         else
  994.             clearAutocompleteDatabaseFromLine(cursorPositionLine)
  995.  
  996.             lines[cursorPositionLine] = firstPart .. data[1]
  997.             updateAutocompleteDatabaseFromLine(cursorPositionLine)
  998.  
  999.             if #data > 2 then
  1000.                 for pasteLine = #data - 1, 2, -1 do
  1001.                     table.insert(lines, cursorPositionLine + 1, data[pasteLine])
  1002.                    
  1003.                     updateAutocompleteDatabaseFromLine(cursorPositionLine + 1)
  1004.                 end
  1005.             end
  1006.             table.insert(lines, cursorPositionLine + #data - 1, data[#data] .. secondPart)
  1007.             updateAutocompleteDatabaseFromLine(cursorPositionLine + #data - 1)
  1008.  
  1009.             setCursorPositionAndClearSelection(unicode.len(data[#data]) + 1, cursorPositionLine + #data - 1)
  1010.         end
  1011.     end
  1012. end
  1013.  
  1014. local function selectAndPasteColor()
  1015.     local startColor = 0xFF0000
  1016.     if codeView.selections[1] and codeView.selections[1].from.line == codeView.selections[1].to.line then
  1017.         startColor = tonumber(unicode.sub(lines[codeView.selections[1].from.line], codeView.selections[1].from.symbol, codeView.selections[1].to.symbol)) or startColor
  1018.     end
  1019.  
  1020.     local palette = window:addChild(GUI.palette(1, 1, startColor))
  1021.     palette.localX, palette.localY = math.floor(window.width / 2 - palette.width / 2), math.floor(window.height / 2 - palette.height / 2)
  1022.  
  1023.     palette.cancelButton.onTouch = function()
  1024.         palette:remove()
  1025.         workspace:draw()
  1026.     end
  1027.  
  1028.     palette.submitButton.onTouch = function()
  1029.         paste(string.format("0x%06X", palette.color.integer), true)
  1030.         palette.cancelButton.onTouch()
  1031.     end
  1032. end
  1033.  
  1034. local function convertCase(method)
  1035.     if codeView.selections[1] then
  1036.         local from, to = codeView.selections[1].from, codeView.selections[1].to
  1037.         if from.line == to.line then
  1038.             lines[from.line] = unicode.sub(lines[from.line], 1, from.symbol - 1) .. unicode[method](unicode.sub(lines[from.line], from.symbol, to.symbol)) .. unicode.sub(lines[from.line], to.symbol + 1, -1)
  1039.         else
  1040.             lines[from.line] = unicode.sub(lines[from.line], 1, from.symbol - 1) .. unicode[method](unicode.sub(lines[from.line], from.symbol, -1))
  1041.             lines[to.line] = unicode[method](unicode.sub(lines[to.line], 1, to.symbol)) .. unicode.sub(lines[to.line], to.symbol + 1, -1)
  1042.             for line = from.line + 1, to.line - 1 do
  1043.                 lines[line] = unicode[method](lines[line])
  1044.             end
  1045.         end
  1046.     end
  1047. end
  1048.  
  1049. local function pasteRegularChar(unicodeByte, char)
  1050.     if not keyboard.isControl(unicodeByte) then
  1051.         paste(char, true)
  1052.         -- if char == " " then
  1053.             -- updateAutocompleteDatabaseFromAllLines()
  1054.         -- end
  1055.         showAutocomplete()
  1056.     end
  1057. end
  1058.  
  1059. local function pasteAutoBrackets(unicodeByte)
  1060.     local char = unicode.char(unicodeByte)
  1061.     local currentSymbol = unicode.sub(lines[cursorPositionLine], cursorPositionSymbol, cursorPositionSymbol)
  1062.  
  1063.     -- Если у нас вообще врублен режим автоскобок, то чекаем их
  1064.     if config.enableAutoBrackets then
  1065.         -- Ситуация, когда курсор находится на закрывающей скобке, и нехуй ее еще раз вставлять
  1066.         if closeBrackets[char] and currentSymbol == char then
  1067.             deleteSelectedData()
  1068.             setCursorPosition(cursorPositionSymbol + 1, cursorPositionLine)
  1069.         -- Если нажата открывающая скобка
  1070.         elseif openBrackets[char] then
  1071.             -- А вот тут мы берем в скобочки уже выделенный текст
  1072.             if codeView.selections[1] then
  1073.                 local firstPart = unicode.sub(lines[codeView.selections[1].from.line], 1, codeView.selections[1].from.symbol - 1)
  1074.                 local secondPart = unicode.sub(lines[codeView.selections[1].from.line], codeView.selections[1].from.symbol, -1)
  1075.                 lines[codeView.selections[1].from.line] = firstPart .. char .. secondPart
  1076.                 codeView.selections[1].from.symbol = codeView.selections[1].from.symbol + 1
  1077.  
  1078.                 if codeView.selections[1].to.line == codeView.selections[1].from.line then
  1079.                     codeView.selections[1].to.symbol = codeView.selections[1].to.symbol + 1
  1080.                 end
  1081.  
  1082.                 firstPart = unicode.sub(lines[codeView.selections[1].to.line], 1, codeView.selections[1].to.symbol)
  1083.                 secondPart = unicode.sub(lines[codeView.selections[1].to.line], codeView.selections[1].to.symbol + 1, -1)
  1084.                 lines[codeView.selections[1].to.line] = firstPart .. openBrackets[char] .. secondPart
  1085.                 cursorPositionSymbol = cursorPositionSymbol + 2
  1086.             -- А тут мы делаем двойную автоскобку, если можем
  1087.             elseif openBrackets[char] and not currentSymbol:match("[%a%d%_]") then
  1088.                 paste(char .. openBrackets[char], true)
  1089.                 setCursorPosition(cursorPositionSymbol - 1, cursorPositionLine)
  1090.                 cursorBlinkState = false
  1091.             -- Ну, и если нет ни выделений, ни можем ебануть автоскобочку по регулярке
  1092.             else
  1093.                 pasteRegularChar(unicodeByte, char)
  1094.             end
  1095.         -- Если мы вообще на скобку не нажимали
  1096.         else
  1097.             pasteRegularChar(unicodeByte, char)
  1098.         end
  1099.     -- Если оффнуты афтоскобки
  1100.     else
  1101.         pasteRegularChar(unicodeByte, char)
  1102.     end
  1103. end
  1104.  
  1105. local function delete()
  1106.     if codeView.selections[1] then
  1107.         deleteSelectedData()
  1108.     else
  1109.         if cursorPositionSymbol < unicode.len(lines[cursorPositionLine]) + 1 then
  1110.             deleteSpecifiedData(cursorPositionSymbol, cursorPositionLine, cursorPositionSymbol, cursorPositionLine)
  1111.         else
  1112.             if cursorPositionLine > 1 and lines[cursorPositionLine + 1] then
  1113.                 deleteSpecifiedData(unicode.len(lines[cursorPositionLine]) + 1, cursorPositionLine, 0, cursorPositionLine + 1)
  1114.             end
  1115.         end
  1116.  
  1117.         showAutocomplete()
  1118.     end
  1119. end
  1120.  
  1121. local function selectAll()
  1122.     codeView.selections[1] = {
  1123.         from = {
  1124.             symbol = 1, line = 1
  1125.         },
  1126.         to = {
  1127.             symbol = unicode.len(lines[#lines]), line = #lines
  1128.         }
  1129.     }
  1130. end
  1131.  
  1132. local function isLineCommented(line)
  1133.     if lines[line] == "" or lines[line]:match("%-%-%s?") then return true end
  1134. end
  1135.  
  1136. local function commentLine(line)
  1137.     lines[line] = "-- " .. lines[line]
  1138. end
  1139.  
  1140. local function uncommentLine(line)
  1141.     local countOfReplaces
  1142.     lines[line], countOfReplaces = lines[line]:gsub("%-%-%s?", "", 1)
  1143.     return countOfReplaces
  1144. end
  1145.  
  1146. local function toggleComment()
  1147.     if codeView.selections[1] then
  1148.         local allLinesAreCommented = true
  1149.        
  1150.         for line = codeView.selections[1].from.line, codeView.selections[1].to.line do
  1151.             if not isLineCommented(line) then
  1152.                 allLinesAreCommented = false
  1153.                 break
  1154.             end
  1155.         end
  1156.        
  1157.         for line = codeView.selections[1].from.line, codeView.selections[1].to.line do
  1158.             if allLinesAreCommented then
  1159.                 uncommentLine(line)
  1160.             else
  1161.                 commentLine(line)
  1162.             end
  1163.         end
  1164.  
  1165.         local modifyer = 3
  1166.         if allLinesAreCommented then modifyer = -modifyer end
  1167.         setCursorPosition(cursorPositionSymbol + modifyer, cursorPositionLine)
  1168.         codeView.selections[1].from.symbol, codeView.selections[1].to.symbol = codeView.selections[1].from.symbol + modifyer, codeView.selections[1].to.symbol + modifyer
  1169.     else
  1170.         if isLineCommented(cursorPositionLine) then
  1171.             if uncommentLine(cursorPositionLine) > 0 then
  1172.                 setCursorPositionAndClearSelection(cursorPositionSymbol - 3, cursorPositionLine)
  1173.             end
  1174.         else
  1175.             commentLine(cursorPositionLine)
  1176.             setCursorPositionAndClearSelection(cursorPositionSymbol + 3, cursorPositionLine)
  1177.         end
  1178.     end
  1179. end
  1180.  
  1181. local function indentLine(line)
  1182.     lines[line] = string.rep(" ", codeView.indentationWidth) .. lines[line]
  1183. end
  1184.  
  1185. local function unindentLine(line)
  1186.     lines[line], countOfReplaces = string.gsub(lines[line], "^" .. string.rep("%s", codeView.indentationWidth), "")
  1187.     return countOfReplaces
  1188. end
  1189.  
  1190. local function indentOrUnindent(isIndent)
  1191.     if codeView.selections[1] then
  1192.         local countOfReplacesInFirstLine, countOfReplacesInLastLine
  1193.        
  1194.         for line = codeView.selections[1].from.line, codeView.selections[1].to.line do
  1195.             if isIndent then
  1196.                 indentLine(line)
  1197.             else
  1198.                 local countOfReplaces = unindentLine(line)
  1199.                 if line == codeView.selections[1].from.line then
  1200.                     countOfReplacesInFirstLine = countOfReplaces
  1201.                 elseif line == codeView.selections[1].to.line then
  1202.                     countOfReplacesInLastLine = countOfReplaces
  1203.                 end
  1204.             end
  1205.         end    
  1206.  
  1207.         if isIndent then
  1208.             setCursorPosition(cursorPositionSymbol + codeView.indentationWidth, cursorPositionLine)
  1209.             codeView.selections[1].from.symbol, codeView.selections[1].to.symbol = codeView.selections[1].from.symbol + codeView.indentationWidth, codeView.selections[1].to.symbol + codeView.indentationWidth
  1210.         else
  1211.             if countOfReplacesInFirstLine > 0 then
  1212.                 codeView.selections[1].from.symbol = codeView.selections[1].from.symbol - codeView.indentationWidth
  1213.                 if cursorPositionLine == codeView.selections[1].from.line then
  1214.                     setCursorPosition(cursorPositionSymbol - codeView.indentationWidth, cursorPositionLine)
  1215.                 end
  1216.             end
  1217.  
  1218.             if countOfReplacesInLastLine > 0 then
  1219.                 codeView.selections[1].to.symbol = codeView.selections[1].to.symbol - codeView.indentationWidth
  1220.                 if cursorPositionLine == codeView.selections[1].to.line then
  1221.                     setCursorPosition(cursorPositionSymbol - codeView.indentationWidth, cursorPositionLine)
  1222.                 end
  1223.             end
  1224.         end
  1225.     else
  1226.         if isIndent then
  1227.             paste(string.rep(" ", codeView.indentationWidth), true)
  1228.         else
  1229.             if unindentLine(cursorPositionLine) > 0 then
  1230.                 setCursorPositionAndClearSelection(cursorPositionSymbol - codeView.indentationWidth, cursorPositionLine)
  1231.             end
  1232.         end
  1233.     end
  1234. end
  1235.  
  1236. local function find()
  1237.     if not bottomToolBar.hidden and searchInput.text ~= "" then
  1238.         findStartFrom = findStartFrom + 1
  1239.    
  1240.         for line = findStartFrom, #lines do
  1241.             local whereToFind, whatToFind = lines[line], searchInput.text
  1242.             if not caseSensitiveButton.pressed then
  1243.                 whereToFind, whatToFind = unicode.lower(whereToFind), unicode.lower(whatToFind)
  1244.             end
  1245.  
  1246.             local success, starting, ending = pcall(text.unicodeFind, whereToFind, whatToFind)
  1247.             if success then
  1248.                 if starting then
  1249.                     codeView.selections[1] = {
  1250.                         from = {symbol = starting, line = line},
  1251.                         to = {symbol = ending, line = line},
  1252.                         color = 0xCC9200
  1253.                     }
  1254.                     findStartFrom = line
  1255.                     gotoLine(line)
  1256.                     return
  1257.                 end
  1258.             else
  1259.                 GUI.alert("Wrong searching regex")
  1260.             end
  1261.         end
  1262.  
  1263.         findStartFrom = 0
  1264.     end
  1265. end
  1266.  
  1267. local function findFromFirstDisplayedLine()
  1268.     findStartFrom = codeView.fromLine
  1269.     find()
  1270. end
  1271.  
  1272. local function toggleBottomToolBar()
  1273.     bottomToolBar.hidden = not bottomToolBar.hidden
  1274.     toggleBottomToolBarButton.pressed = not bottomToolBar.hidden
  1275.     calculateSizes()
  1276.        
  1277.     if not bottomToolBar.hidden then
  1278.         workspace:draw()
  1279.         findFromFirstDisplayedLine()
  1280.     end
  1281. end
  1282.  
  1283. local function toggleTopToolBar()
  1284.     topToolBar.hidden = not topToolBar.hidden
  1285.     toggleTopToolBarButton.pressed = not topToolBar.hidden
  1286.     calculateSizes()
  1287. end
  1288.  
  1289. local function createEditOrRightClickMenu(menu)
  1290.     menu:addItem(localization.cut, not codeView.selections[1], "^X").onTouch = function()
  1291.         cut()
  1292.     end
  1293.  
  1294.     menu:addItem(localization.copy, not codeView.selections[1], "^C").onTouch = function()
  1295.         copy()
  1296.     end
  1297.  
  1298.     menu:addItem(localization.paste, not clipboard, "^V").onTouch = function()
  1299.         paste(clipboard)
  1300.     end
  1301.  
  1302.     menu:addSeparator()
  1303.  
  1304.     menu:addItem(localization.selectWord).onTouch = function()
  1305.         selectWord()
  1306.     end
  1307.  
  1308.     menu:addItem(localization.selectAll, false, "^A").onTouch = function()
  1309.         selectAll()
  1310.     end
  1311.  
  1312.     menu:addSeparator()
  1313.  
  1314.     menu:addItem(localization.comment, false, "^/").onTouch = function()
  1315.         toggleComment()
  1316.     end
  1317.  
  1318.     menu:addItem(localization.indent, false, "Tab").onTouch = function()
  1319.         indentOrUnindent(true)
  1320.     end
  1321.  
  1322.     menu:addItem(localization.unindent, false, "⇧Tab").onTouch = function()
  1323.         indentOrUnindent(false)
  1324.     end
  1325.  
  1326.     menu:addItem(localization.deleteLine, false, "^Del").onTouch = function()
  1327.         deleteLine(cursorPositionLine)
  1328.     end
  1329.  
  1330.     menu:addItem(localization.selectAndPasteColor, false, "^⇧C").onTouch = function()
  1331.         selectAndPasteColor()
  1332.     end
  1333.    
  1334.     local subMenu = menu:addSubMenuItem(localization.convertCase)
  1335.    
  1336.     subMenu:addItem(localization.toUpperCase, false, "^▲").onTouch = function()
  1337.         convertCase("upper")
  1338.     end
  1339.  
  1340.     subMenu:addItem(localization.toLowerCase, false, "^▼").onTouch = function()
  1341.         convertCase("lower")
  1342.     end
  1343.  
  1344.     menu:addSeparator()
  1345.  
  1346.     menu:addItem(localization.addBreakpoint, false, "F9").onTouch = function()
  1347.         addBreakpoint()
  1348.         workspace:draw()
  1349.     end
  1350.  
  1351.     menu:addItem(localization.clearBreakpoints, not breakpointLines, "^F9").onTouch = function()
  1352.         clearBreakpoints()
  1353.     end
  1354. end
  1355.  
  1356. local function checkScrollbar(y)
  1357.     return codeView.horizontalScrollBar.hidden or y < codeView.y + codeView.height - 1
  1358. end
  1359.  
  1360. local uptime = computer.uptime()
  1361. codeView.eventHandler = function(workspace, object, e1, e2, e3, e4, e5)
  1362.     if e1 == "touch" and checkScrollbar(e4) then
  1363.         if e5 == 1 then
  1364.             createEditOrRightClickMenu(GUI.addContextMenu(workspace, e3, e4))
  1365.         else
  1366.             setCursorPositionAndClearSelection(convertScreenCoordinatesToTextPosition(e3, e4))
  1367.         end
  1368.  
  1369.         tick(true)
  1370.     elseif e1 == "double_touch" then
  1371.         selectWord()
  1372.         tick(true)
  1373.     elseif e1 == "drag" and checkScrollbar(e4) then
  1374.         codeView.selections[1] = codeView.selections[1] or {from = {}, to = {}}
  1375.         codeView.selections[1].from.symbol, codeView.selections[1].from.line = cursorPositionSymbol, cursorPositionLine
  1376.         codeView.selections[1].to.symbol, codeView.selections[1].to.line = fixCursorPosition(convertScreenCoordinatesToTextPosition(e3, e4))
  1377.        
  1378.         if codeView.selections[1].from.line > codeView.selections[1].to.line then
  1379.             codeView.selections[1].from.line, codeView.selections[1].to.line = codeView.selections[1].to.line, codeView.selections[1].from.line
  1380.             codeView.selections[1].from.symbol, codeView.selections[1].to.symbol = codeView.selections[1].to.symbol, codeView.selections[1].from.symbol
  1381.         elseif codeView.selections[1].from.line == codeView.selections[1].to.line then
  1382.             if codeView.selections[1].from.symbol > codeView.selections[1].to.symbol then
  1383.                 codeView.selections[1].from.symbol, codeView.selections[1].to.symbol = codeView.selections[1].to.symbol, codeView.selections[1].from.symbol
  1384.             end
  1385.         end
  1386.  
  1387.         tick(true)
  1388.     elseif e1 == "key_down" then
  1389.         -- Ctrl or CMD
  1390.         if keyboard.isControlDown() or keyboard.isCommandDown() then
  1391.             -- Slash
  1392.             if e4 == 53 then
  1393.                 toggleComment()
  1394.             -- ]
  1395.             elseif e4 == 27 then
  1396.                 config.enableAutoBrackets = not config.enableAutoBrackets
  1397.                 saveConfig()
  1398.             -- I
  1399.             elseif e4 == 23 then
  1400.                 toggleEnableAutocompleteDatabase()
  1401.             -- A
  1402.             elseif e4 == 30 then
  1403.                 selectAll()
  1404.             -- C
  1405.             elseif e4 == 46 then
  1406.                 -- Shift
  1407.                 if keyboard.isKeyDown(42) then
  1408.                     selectAndPasteColor()
  1409.                 else
  1410.                     copy()
  1411.                 end
  1412.             -- V
  1413.             elseif e4 == 47 and clipboard then
  1414.                 paste(clipboard)
  1415.             -- X
  1416.             elseif e4 == 45 then
  1417.                 if codeView.selections[1] then
  1418.                     cut()
  1419.                 else
  1420.                     deleteLine(cursorPositionLine)
  1421.                 end
  1422.             -- N
  1423.             elseif e4 == 49 then
  1424.                 newFile()
  1425.             -- O
  1426.             elseif e4 == 24 then
  1427.                 openFileWindow()
  1428.             -- U
  1429.             elseif e4 == 22 and component.isAvailable("internet") then
  1430.                 downloadFileFromWeb()
  1431.             -- Arrow UP
  1432.             elseif e4 == 200 then
  1433.                 convertCase("upper")
  1434.             -- Arrow DOWN
  1435.             elseif e4 == 208 then
  1436.                 convertCase("lower")
  1437.             -- S
  1438.             elseif e4 == 31 then
  1439.                 -- Shift
  1440.                 if leftTreeView.selectedItem and not keyboard.isKeyDown(42) then
  1441.                     saveFileWindow()
  1442.                 else
  1443.                     saveFileAsWindow()
  1444.                 end
  1445.             -- F
  1446.             elseif e4 == 33 then
  1447.                 toggleBottomToolBar()
  1448.             -- G
  1449.             elseif e4 == 34 then
  1450.                 find()
  1451.             -- L
  1452.             elseif e4 == 38 then
  1453.                 gotoLineWindow()
  1454.             -- Backspace
  1455.             elseif e4 == 14 then
  1456.                 deleteLine(cursorPositionLine)
  1457.             -- Delete
  1458.             elseif e4 == 211 then
  1459.                 deleteLine(cursorPositionLine)
  1460.             -- F5
  1461.             elseif e4 == 63 then
  1462.                 launchWithArgumentsWindow()
  1463.             end
  1464.         -- Arrows up, down, left, right
  1465.         elseif e4 == 200 then
  1466.             moveCursor(0, -1)
  1467.         elseif e4 == 208 then
  1468.             moveCursor(0, 1)
  1469.         elseif e4 == 203 then
  1470.             moveCursor(-1, 0, true)
  1471.         elseif e4 == 205 then
  1472.             moveCursor(1, 0, true)
  1473.         -- Tab
  1474.         elseif e4 == 15 then
  1475.             if keyboard.isKeyDown(42) then
  1476.                 indentOrUnindent(false)
  1477.             else
  1478.                 indentOrUnindent(true)
  1479.             end
  1480.         -- Backspace
  1481.         elseif e4 == 14 then
  1482.             if codeView.selections[1] then
  1483.                 deleteSelectedData()
  1484.             else
  1485.                 if cursorPositionSymbol > 1 then
  1486.                     -- Удаляем автоскобочки))0
  1487.                     if config.enableAutoBrackets and unicode.sub(lines[cursorPositionLine], cursorPositionSymbol, cursorPositionSymbol) == openBrackets[unicode.sub(lines[cursorPositionLine], cursorPositionSymbol - 1, cursorPositionSymbol - 1)] then
  1488.                         deleteSpecifiedData(cursorPositionSymbol - 1, cursorPositionLine, cursorPositionSymbol, cursorPositionLine)
  1489.                     else
  1490.                         -- Удаляем индентацию
  1491.                         local match = unicode.sub(lines[cursorPositionLine], 1, cursorPositionSymbol - 1):match("^(%s+)$")
  1492.                         if match and #match % codeView.indentationWidth == 0 then
  1493.                             deleteSpecifiedData(cursorPositionSymbol - codeView.indentationWidth, cursorPositionLine, cursorPositionSymbol - 1, cursorPositionLine)
  1494.                         -- Удаляем обычные символы
  1495.                         else
  1496.                             deleteSpecifiedData(cursorPositionSymbol - 1, cursorPositionLine, cursorPositionSymbol - 1, cursorPositionLine)
  1497.                         end
  1498.                     end
  1499.                 else
  1500.                     -- Удаление типа с обратным энтером
  1501.                     if cursorPositionLine > 1 then
  1502.                         deleteSpecifiedData(unicode.len(lines[cursorPositionLine - 1]) + 1, cursorPositionLine - 1, 0, cursorPositionLine)
  1503.                     end
  1504.                 end
  1505.  
  1506.                 showAutocomplete()
  1507.             end
  1508.         -- Enter
  1509.         elseif e4 == 28 then
  1510.             if autocomplete.hidden then
  1511.                 if codeView.selections[1] then
  1512.                     deleteSelectedData()
  1513.                 end
  1514.                
  1515.                 local secondPart = unicode.sub(lines[cursorPositionLine], cursorPositionSymbol, -1)
  1516.                
  1517.                 local match = lines[cursorPositionLine]:match("^(%s+)")
  1518.                 if match then
  1519.                     secondPart = match .. secondPart
  1520.                 end
  1521.                
  1522.                 lines[cursorPositionLine] = unicode.sub(lines[cursorPositionLine], 1, cursorPositionSymbol - 1)
  1523.                 table.insert(lines, cursorPositionLine + 1, secondPart)
  1524.                
  1525.                 setCursorPositionAndClearSelection(match and #match + 1 or 1, cursorPositionLine + 1)
  1526.             else
  1527.                 autocomplete.hidden = true
  1528.             end
  1529.         -- F5
  1530.         elseif e4 == 63 then
  1531.             run()
  1532.         -- F9
  1533.         elseif e4 == 67 then
  1534.             -- Shift
  1535.             if keyboard.isKeyDown(42) then
  1536.                 clearBreakpoints()
  1537.             else
  1538.                 addBreakpoint()
  1539.             end
  1540.         -- Home
  1541.         elseif e4 == 199 then
  1542.             setCursorPositionToHome()
  1543.         -- End
  1544.         elseif e4 == 207 then
  1545.             setCursorPositionToEnd()
  1546.         -- Page Up
  1547.         elseif e4 == 201 then
  1548.             pageUp()
  1549.         -- Page Down
  1550.         elseif e4 == 209 then
  1551.             pageDown()
  1552.         -- Delete
  1553.         elseif e4 == 211 then
  1554.             delete()
  1555.         else
  1556.             pasteAutoBrackets(e3)
  1557.         end
  1558.  
  1559.         tick(true)
  1560.     elseif e1 == "scroll" then
  1561.         scroll(e5, config.scrollSpeed)
  1562.         tick(cursorBlinkState)
  1563.     elseif e1 == "clipboard" then
  1564.         local lines = splitStringIntoLines(e3)
  1565.         paste(lines)
  1566.        
  1567.         tick(cursorBlinkState)
  1568.     elseif not e1 and cursorUptime + config.cursorBlinkDelay < computer.uptime() then
  1569.         tick(not cursorBlinkState)
  1570.     end
  1571. end
  1572.  
  1573. leftTreeView.onItemSelected = function(path)
  1574.     workspace:draw()
  1575.     openFile(path)
  1576.     workspace:draw()
  1577. end
  1578.  
  1579. local MineCodeContextMenu = menu:addContextMenuItem("MineCode", 0x0)
  1580. MineCodeContextMenu:addItem(localization.about).onTouch = function()
  1581.     local container = addBackgroundContainer(localization.about)
  1582.    
  1583.     local about = {
  1584.         "MineCode IDE",
  1585.         "Copyright © 2014-2018 ECS Inc.",
  1586.         " ",
  1587.         "Developers:",
  1588.         " ",
  1589.         "Timofeev Igor, vk.com/id7799889",
  1590.         "Trifonov Gleb, vk.com/id88323331",
  1591.         " ",
  1592.         "Testers:",
  1593.         " ",
  1594.         "Semyonov Semyon, vk.com/id92656626",
  1595.         "Prosin Mihail, vk.com/id75667079",
  1596.         "Shestakov Timofey, vk.com/id113499693",
  1597.         "Bogushevich Victoria, vk.com/id171497518",
  1598.         "Vitvitskaya Yana, vk.com/id183425349",
  1599.         "Golovanova Polina, vk.com/id226251826",
  1600.     }
  1601.  
  1602.     local textBox = container.layout:addChild(GUI.textBox(1, 1, 36, #about, nil, 0xB4B4B4, about, 1, 0, 0, true, false))
  1603.     textBox:setAlignment(GUI.ALIGNMENT_HORIZONTAL_CENTER, GUI.ALIGNMENT_VERTICAL_TOP)
  1604.     textBox.eventHandler = nil
  1605.  
  1606.     workspace:draw()
  1607. end
  1608.  
  1609. local fileContextMenu = menu:addContextMenuItem(localization.file)
  1610. fileContextMenu:addItem(localization.new, false, "^N").onTouch = function()
  1611.     newFile()
  1612.     workspace:draw()
  1613. end
  1614.  
  1615. fileContextMenu:addItem(localization.open, false, "^O").onTouch = function()
  1616.     openFileWindow()
  1617. end
  1618.  
  1619. fileContextMenu:addItem(localization.getFromWeb, not component.isAvailable("internet"), "^U").onTouch = function()
  1620.     downloadFileFromWeb()
  1621. end
  1622.  
  1623.  
  1624. fileContextMenu:addSeparator()
  1625.  
  1626. saveContextMenuItem = fileContextMenu:addItem(localization.save, not leftTreeView.selectedItem, "^S")
  1627. saveContextMenuItem.onTouch = function()
  1628.     saveFileWindow()
  1629. end
  1630.  
  1631. fileContextMenu:addItem(localization.saveAs, false, "^⇧S").onTouch = function()
  1632.     saveFileAsWindow()
  1633. end
  1634.  
  1635. fileContextMenu:addItem(localization.flashEEPROM, not component.isAvailable("eeprom")).onTouch = function()
  1636.     local container = addBackgroundContainer(localization.flashEEPROM)
  1637.     container.layout:addChild(GUI.label(1, 1, container.width, 1, 0x969696, localization.flashingEEPROM .. "...")):setAlignment(GUI.ALIGNMENT_HORIZONTAL_CENTER, GUI.ALIGNMENT_VERTICAL_TOP)
  1638.     workspace:draw()
  1639.  
  1640.     component.get("eeprom").set(table.concat(lines, "\n"))
  1641.    
  1642.     container:remove()
  1643.     workspace:draw()
  1644. end
  1645.  
  1646. fileContextMenu:addSeparator()
  1647.  
  1648. fileContextMenu:addItem(localization.launchWithArguments, false, "^F5").onTouch = function()
  1649.     launchWithArgumentsWindow()
  1650. end
  1651.  
  1652. local topMenuEdit = menu:addContextMenuItem(localization.edit)
  1653. createEditOrRightClickMenu(topMenuEdit)
  1654.  
  1655. local gotoContextMenu = menu:addContextMenuItem(localization.gotoCyka)
  1656. gotoContextMenu:addItem(localization.pageUp, false, "PgUp").onTouch = function()
  1657.     pageUp()
  1658. end
  1659.  
  1660. gotoContextMenu:addItem(localization.pageDown, false, "PgDn").onTouch = function()
  1661.     pageDown()
  1662. end
  1663.  
  1664. gotoContextMenu:addItem(localization.gotoStart, false, "Home").onTouch = function()
  1665.     setCursorPositionToHome()
  1666. end
  1667.  
  1668. gotoContextMenu:addItem(localization.gotoEnd, false, "End").onTouch = function()
  1669.     setCursorPositionToEnd()
  1670. end
  1671.  
  1672. gotoContextMenu:addSeparator()
  1673.  
  1674. gotoContextMenu:addItem(localization.gotoLine, false, "^L").onTouch = function()
  1675.     gotoLineWindow()
  1676. end
  1677.  
  1678. local propertiesContextMenu = menu:addContextMenuItem(localization.properties)
  1679. propertiesContextMenu:addItem(localization.colorScheme).onTouch = function()
  1680.     local container = GUI.addBackgroundContainer(workspace, true, false, localization.colorScheme)
  1681.                
  1682.     local colorSelectorsCount, colorSelectorCountX = 0, 4; for key in pairs(config.syntaxColorScheme) do colorSelectorsCount = colorSelectorsCount + 1 end
  1683.     local colorSelectorCountY = math.ceil(colorSelectorsCount / colorSelectorCountX)
  1684.     local colorSelectorWidth, colorSelectorHeight, colorSelectorSpaceX, colorSelectorSpaceY = math.floor(container.width / colorSelectorCountX * 0.8), 3, 2, 1
  1685.    
  1686.     local startX, y = math.floor(container.width / 2 - (colorSelectorCountX * (colorSelectorWidth + colorSelectorSpaceX) - colorSelectorSpaceX) / 2), math.floor(container.height / 2 - (colorSelectorCountY * (colorSelectorHeight + colorSelectorSpaceY) - colorSelectorSpaceY + 3) / 2)
  1687.     container:addChild(GUI.label(1, y, container.width, 1, 0xFFFFFF, localization.colorScheme)):setAlignment(GUI.ALIGNMENT_HORIZONTAL_CENTER, GUI.ALIGNMENT_VERTICAL_TOP); y = y + 3
  1688.     local x, counter = startX, 1
  1689.  
  1690.     local colors = {}
  1691.     for key in pairs(config.syntaxColorScheme) do
  1692.         table.insert(colors, {key})
  1693.     end
  1694.  
  1695.     aplhabeticalSort(colors)
  1696.  
  1697.     for i = 1, #colors do
  1698.         local colorSelector = container:addChild(GUI.colorSelector(x, y, colorSelectorWidth, colorSelectorHeight, config.syntaxColorScheme[colors[i][1]], colors[i][1]))
  1699.         colorSelector.onColorSelected = function()
  1700.             config.syntaxColorScheme[colors[i][1]] = colorSelector.color
  1701.             saveConfig()
  1702.         end
  1703.  
  1704.         x, counter = x + colorSelectorWidth + colorSelectorSpaceX, counter + 1
  1705.         if counter > colorSelectorCountX then
  1706.             x, y, counter = startX, y + colorSelectorHeight + colorSelectorSpaceY, 1
  1707.         end
  1708.     end
  1709.  
  1710.     workspace:draw()
  1711. end
  1712.  
  1713. propertiesContextMenu:addItem(localization.cursorProperties).onTouch = function()
  1714.     local container = addBackgroundContainer(localization.cursorProperties)
  1715.  
  1716.     local input = container.layout:addChild(GUI.input(1, 1, 36, 3, 0xC3C3C3, 0x787878, 0x787878, 0xC3C3C3, 0x2D2D2D, config.cursorSymbol, localization.cursorSymbol))
  1717.     input.onInputFinished = function()
  1718.         if #input.text == 1 then
  1719.             config.cursorSymbol = input.text
  1720.             saveConfig()
  1721.         end
  1722.     end
  1723.  
  1724.     local colorSelector = container.layout:addChild(GUI.colorSelector(1, 1, 36, 3, config.cursorColor, localization.cursorColor))
  1725.     colorSelector.onColorSelected = function()
  1726.         config.cursorColor = colorSelector.color
  1727.         saveConfig()
  1728.     end
  1729.  
  1730.     local slider = container.layout:addChild(GUI.slider(1, 1, 36, 0xFFDB80, 0x000000, 0xFFDB40, 0xDDDDDD, 1, 1000, config.cursorBlinkDelay * 1000, false, localization.cursorBlinkDelay .. ": ", " ms"))
  1731.     slider.onValueChanged = function()
  1732.         config.cursorBlinkDelay = slider.value / 1000
  1733.         saveConfig()
  1734.     end
  1735.  
  1736.     workspace:draw()
  1737. end
  1738.  
  1739. propertiesContextMenu:addItem(localization.toggleTopToolBar).onTouch = function()
  1740.     toggleTopToolBar()
  1741. end
  1742.  
  1743. propertiesContextMenu:addSeparator()
  1744.  
  1745. propertiesContextMenu:addItem(localization.toggleSyntaxHighlight).onTouch = function()
  1746.     syntaxHighlightingButton.pressed = not syntaxHighlightingButton.pressed
  1747.     syntaxHighlightingButton.onTouch()
  1748. end
  1749.  
  1750. propertiesContextMenu:addItem(localization.toggleAutoBrackets, false, "^]").onTouch = function()
  1751.     config.enableAutoBrackets = not config.enableAutoBrackets
  1752.     saveConfig()
  1753. end
  1754.  
  1755. propertiesContextMenu:addItem(localization.toggleAutocompletion, false, "^I").onTouch = function()
  1756.     toggleEnableAutocompleteDatabase()
  1757. end
  1758.  
  1759. leftTreeViewResizer.onResize = function(dragWidth, dragHeight)
  1760.     leftTreeView.width = leftTreeView.width + dragWidth
  1761.     calculateSizes()
  1762. end
  1763.  
  1764. leftTreeViewResizer.onResizeFinished = function()
  1765.     config.leftTreeViewWidth = leftTreeView.width
  1766.     saveConfig()
  1767. end
  1768.  
  1769. addBreakpointButton.onTouch = function()
  1770.     addBreakpoint()
  1771.     workspace:draw()
  1772. end
  1773.  
  1774. syntaxHighlightingButton.onTouch = function()
  1775.     config.syntaxHighlight = not config.syntaxHighlight
  1776.     codeView.syntaxHighlight = config.syntaxHighlight
  1777.     workspace:draw()
  1778.     saveConfig()
  1779. end
  1780.  
  1781. toggleLeftToolBarButton.onTouch = function()
  1782.     leftTreeView.hidden = not toggleLeftToolBarButton.pressed
  1783.     leftTreeViewResizer.hidden = leftTreeView.hidden
  1784.     calculateSizes()
  1785.     workspace:draw()
  1786. end
  1787.  
  1788. toggleBottomToolBarButton.onTouch = function()
  1789.     bottomToolBar.hidden = not toggleBottomToolBarButton.pressed
  1790.     calculateSizes()
  1791.     workspace:draw()
  1792. end
  1793.  
  1794. toggleTopToolBarButton.onTouch = function()
  1795.     topToolBar.hidden = not toggleTopToolBarButton.pressed
  1796.     calculateSizes()
  1797.     workspace:draw()
  1798. end
  1799.  
  1800. codeView.verticalScrollBar.onTouch = function()
  1801.     codeView.fromLine = math.ceil(codeView.verticalScrollBar.value)
  1802. end
  1803.  
  1804. codeView.horizontalScrollBar.onTouch = function()
  1805.     codeView.fromSymbol = math.ceil(codeView.horizontalScrollBar.value)
  1806. end
  1807.  
  1808. runButton.onTouch = function()
  1809.     run()
  1810. end
  1811.  
  1812. autocomplete.onItemSelected = function(workspace, object, e1)
  1813.     local firstPart = unicode.sub(lines[cursorPositionLine], 1, autoCompleteWordStart - 1)
  1814.     local secondPart = unicode.sub(lines[cursorPositionLine], autoCompleteWordEnd + 1, -1)
  1815.     local middle = firstPart .. autocomplete.items[autocomplete.selectedItem]
  1816.     lines[cursorPositionLine] = middle .. secondPart
  1817.  
  1818.     setCursorPositionAndClearSelection(unicode.len(middle) + 1, cursorPositionLine)
  1819.    
  1820.     if e1 == "key_down" then
  1821.         autocomplete.hidden = false
  1822.     end
  1823.  
  1824.     tick(true)
  1825. end
  1826.  
  1827. window.onResize = function(width, height)
  1828.     calculateSizes()
  1829.     workspace:draw()
  1830. end
  1831.  
  1832. searchInput.onInputFinished = findFromFirstDisplayedLine
  1833. caseSensitiveButton.onTouch = find
  1834. searchButton.onTouch = find
  1835.  
  1836. ------------------------------------------------------------
  1837.  
  1838. autocomplete:moveToFront()
  1839. leftTreeView:updateFileList()
  1840. calculateSizes()
  1841. workspace:draw()
  1842.  
  1843. local initialPath = select(1, ...)
  1844. if initialPath and filesystem.exists(initialPath) then
  1845.     openFile(initialPath)
  1846. else
  1847.     newFile()
  1848. end
  1849.  
  1850. workspace:draw()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement