MineOS/lib/syntax.lua

321 lines
15 KiB
Lua
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

if not _G.buffer then _G.buffer = require("doubleBuffering") end
if not _G.unicode then _G.unicode = require("unicode") end
local syntax = {}
----------------------------------------------------------------------------------------------------------------------------------------
syntax.colorSchemes = {
midnight = {
background = 0x1b1b1b,
text = 0xffffff,
strings = 0xff2024,
loops = 0xffff98,
comments = 0xa2ffb7,
boolean = 0xffcc66,
logic = 0xffcc66,
numbers = 0x24c0ff,
functions = 0xffcc66,
compares = 0xffff98,
lineNumbers = 0x262626,
lineNumbersText = 0xDDDDDD,
scrollBar = 0x444444,
scrollBarPipe = 0x24c0ff,
selection = 0x99B2F2,
}
}
local currentColorScheme, patterns
----------------------------------------------------------------------------------------------------------------------------------------
--Пересчитать цвета шаблонов
--Приоритет поиска шаблонов снижается сверху вниз
local function definePatterns()
patterns = {
--Комментарии
{ pattern = "%-%-.+", color = currentColorScheme.comments, cutFromLeft = 0, cutFromRight = 0 },
--Строки
{ pattern = "\"[^\"\"]+\"", color = currentColorScheme.strings, cutFromLeft = 0, cutFromRight = 0 },
--Циклы, условия, объявления
{ pattern = "while ", color = currentColorScheme.loops, cutFromLeft = 0, cutFromRight = 1 },
{ pattern = "do$", color = currentColorScheme.loops, cutFromLeft = 0, cutFromRight = 0 },
{ pattern = "do ", color = currentColorScheme.loops, cutFromLeft = 0, cutFromRight = 1 },
{ pattern = "end$", color = currentColorScheme.loops, cutFromLeft = 0, cutFromRight = 0 },
{ pattern = "end ", color = currentColorScheme.loops, cutFromLeft = 0, cutFromRight = 1 },
{ pattern = "for ", color = currentColorScheme.loops, cutFromLeft = 0, cutFromRight = 1 },
{ pattern = " in ", color = currentColorScheme.loops, cutFromLeft = 0, cutFromRight = 1 },
{ pattern = "repeat ", color = currentColorScheme.loops, cutFromLeft = 0, cutFromRight = 1 },
{ pattern = "if ", color = currentColorScheme.loops, cutFromLeft = 0, cutFromRight = 1 },
{ pattern = "then", color = currentColorScheme.loops, cutFromLeft = 0, cutFromRight = 0 },
{ pattern = "until ", color = currentColorScheme.loops, cutFromLeft = 0, cutFromRight = 1 },
{ pattern = "return", color = currentColorScheme.loops, cutFromLeft = 0, cutFromRight = 0 },
{ pattern = "local ", color = currentColorScheme.loops, cutFromLeft = 0, cutFromRight = 1 },
{ pattern = "function ", color = currentColorScheme.loops, cutFromLeft = 0, cutFromRight = 1 },
{ pattern = "else$", color = currentColorScheme.loops, cutFromLeft = 0, cutFromRight = 0 },
{ pattern = "else ", color = currentColorScheme.loops, cutFromLeft = 0, cutFromRight = 1 },
{ pattern = "elseif ", color = currentColorScheme.loops, cutFromLeft = 0, cutFromRight = 1 },
--Состояния переменной
{ pattern = "true", color = currentColorScheme.boolean, cutFromLeft = 0, cutFromRight = 0 },
{ pattern = "false", color = currentColorScheme.boolean, cutFromLeft = 0, cutFromRight = 0 },
{ pattern = "nil", color = currentColorScheme.boolean, cutFromLeft = 0, cutFromRight = 0 },
--Функции
{ pattern = "[%s%=][%a%d%_%-%.]+%(", color = currentColorScheme.functions, cutFromLeft = 0, cutFromRight = 1 },
{ pattern = "^[%a%d%_%-%.%=]+%(", color = currentColorScheme.functions, cutFromLeft = 0, cutFromRight = 1 },
--Логические выражения
{ pattern = " and ", color = currentColorScheme.logic, cutFromLeft = 0, cutFromRight = 1 },
{ pattern = " or ", color = currentColorScheme.logic, cutFromLeft = 0, cutFromRight = 1 },
{ pattern = " not ", color = currentColorScheme.logic, cutFromLeft = 0, cutFromRight = 1 },
{ pattern = " break$", color = currentColorScheme.logic, cutFromLeft = 0, cutFromRight = 0 },
{ pattern = "^break", color = currentColorScheme.logic, cutFromLeft = 0, cutFromRight = 0 },
{ pattern = " break ", color = currentColorScheme.logic, cutFromLeft = 0, cutFromRight = 0 },
--Сравнения и мат. операции
{ pattern = "<=", color = currentColorScheme.compares, cutFromLeft = 0, cutFromRight = 0 },
{ pattern = ">=", color = currentColorScheme.compares, cutFromLeft = 0, cutFromRight = 0 },
{ pattern = "<", color = currentColorScheme.compares, cutFromLeft = 0, cutFromRight = 0 },
{ pattern = ">", color = currentColorScheme.compares, cutFromLeft = 0, cutFromRight = 0 },
{ pattern = "==", color = currentColorScheme.compares, cutFromLeft = 0, cutFromRight = 0 },
{ pattern = "~=", color = currentColorScheme.compares, cutFromLeft = 0, cutFromRight = 0 },
{ pattern = "=", color = currentColorScheme.compares, cutFromLeft = 0, cutFromRight = 0 },
{ pattern = "%+", color = currentColorScheme.compares, cutFromLeft = 0, cutFromRight = 0 },
{ pattern = "%-", color = currentColorScheme.compares, cutFromLeft = 0, cutFromRight = 0 },
{ pattern = "%*", color = currentColorScheme.compares, cutFromLeft = 0, cutFromRight = 0 },
{ pattern = "%/", color = currentColorScheme.compares, cutFromLeft = 0, cutFromRight = 0 },
{ pattern = "%.+", color = currentColorScheme.compares, cutFromLeft = 0, cutFromRight = 0 },
{ pattern = "%#", color = currentColorScheme.compares, cutFromLeft = 0, cutFromRight = 0 },
{ pattern = "#^", color = currentColorScheme.compares, cutFromLeft = 0, cutFromRight = 0 },
{ pattern = "%%", color = currentColorScheme.compares, cutFromLeft = 0, cutFromRight = 0 },
--Числа
{ pattern = "[%s%(%,]0x%w+", color = currentColorScheme.numbers, cutFromLeft = 1, cutFromRight = 0 },
{ pattern = "[%s%(%,][%d%.]+", color = currentColorScheme.numbers, cutFromLeft = 1, cutFromRight = 0 },
}
end
local function convertFileToStrings(path)
local array = {}
local maximumStringWidth = 0
local file = io.open(path, "r")
for line in file:lines() do
line = string.gsub(line, " ", string.rep(" ", 4))
maximumStringWidth = math.max(maximumStringWidth, unicode.len(line))
table.insert(array, line)
end
file:close()
return array, maximumStringWidth
end
--Костыльная замена обычному string.find()
--Работает медленнее, но хотя бы поддерживает юникод
function unicode.find(str, pattern, init, plain)
if init then
if init < 0 then
init = -#unicode.sub(str,init)
elseif init > 0 then
init = #unicode.sub(str, 1, init - 1) + 1
end
end
a, b = string.find(str, pattern, init, plain)
if a then
local ap, bp = str:sub(1, a - 1), str:sub(a,b)
a = unicode.len(ap) + 1
b = a + unicode.len(bp) - 1
return a, b
else
return a
end
end
--Объявить новую цветовую схему
function syntax.setColorScheme(colorScheme)
currentColorScheme = colorScheme
definePatterns()
end
----------------------------------------------------------------------------------------------------------------------------------------
--Нарисовать и подсветить строку
function syntax.highlightString(x, y, text, fromSymbol, limit)
--Кароч вооот, хыыы
local searchFrom, starting, ending
--Загоняем в буфер всю строку базового цвета
buffer.text(x - fromSymbol + 1, y, currentColorScheme.text, text)
--Перебираем шаблоны
for i = #patterns, 1, -1 do
searchFrom = 1
--Перебираем весь текст, а то мало ли шаблон дохуя раз встречается
while true do
starting, ending = unicode.find(text, patterns[i].pattern, searchFrom)
if starting and ending then
buffer.text(x + starting - fromSymbol + patterns[i].cutFromLeft, y, patterns[i].color, unicode.sub(text, starting + patterns[i].cutFromLeft, ending - patterns[i].cutFromRight))
if ending > limit then break end
searchFrom = ending + 1
else
break
end
end
end
end
-- Открыть окно-просмотрщик кода
--x, y, width, height, strings, maximumStringWidth, fromSymbol, fromString, highlightLuaSyntax, selection, highlightedStrings
function syntax.viewCode(args)
--Рассчитываем максимальное количество строк, которое мы будем отображать
local countOfStringsOnDisplay, maximumNumberOfAvailableStrings
if args.strings[args.fromString + args.height - 1] then
countOfStringsOnDisplay = args.scrollbars.horizontal and args.height - 1 or args.height
maximumNumberOfAvailableStrings = args.fromString + args.height - 1
else
countOfStringsOnDisplay = #args.strings
maximumNumberOfAvailableStrings = #args.strings
end
--Рассчитываем ширину полоски с номерами строк
local lineNumbersWidth = unicode.len(args.fromStringOnLineNumbers + countOfStringsOnDisplay) + 2
--Рассчитываем стратовую позицию текстового поля
local textFieldPosition = args.x + lineNumbersWidth
local widthOfText = args.width - lineNumbersWidth - 3
local xEnd, yEnd = args.x + args.width - 1, args.y + args.height - 1
--Рисуем подложку под текст
buffer.square(args.x, args.y, args.width, args.height, currentColorScheme.background, 0xFFFFFF, " ")
--Рисуем подложку под номера строк
buffer.square(args.x, args.y, lineNumbersWidth, args.height, currentColorScheme.lineNumbers, 0xFFFFFF, " ")
--Подсвечиваем некоторые строки, если указано
if args.highlightedStrings then
for stringNumber, color in pairs(args.highlightedStrings) do
if stringNumber >= args.fromStringOnLineNumbers and stringNumber < args.fromStringOnLineNumbers + countOfStringsOnDisplay then
buffer.square(args.x, args.y + stringNumber - args.fromStringOnLineNumbers, args.width - 1, 1, color, 0xFFFFFF, " ")
buffer.square(args.x, args.y + stringNumber - args.fromStringOnLineNumbers, lineNumbersWidth, 1, currentColorScheme.lineNumbers, 0xFFFFFF, " ", 60)
end
end
end
--Рисуем номера строк
local yPos = args.y
for i = args.fromStringOnLineNumbers, args.fromStringOnLineNumbers + countOfStringsOnDisplay - 1 do
buffer.text(args.x + lineNumbersWidth - unicode.len(i) - 1, yPos, currentColorScheme.text, tostring(i))
yPos = yPos + 1
end
--Рисуем выделение, если оно имеется
if args.selection then
--Считаем высоту выделения
local heightOfSelection = args.selection.to.y - args.selection.from.y + 1
--Если высота выделения > 1
if heightOfSelection > 1 then
--Верхнее выделение
if args.selection.from.x < args.fromSymbol + widthOfText and args.selection.from.y >= args.fromString and args.selection.from.y < args.fromString + args.height then
local cyka = textFieldPosition + args.selection.from.x - args.fromSymbol
if cyka < textFieldPosition then
cyka = textFieldPosition
end
buffer.square(cyka, args.y + args.selection.from.y - args.fromString, widthOfText - cyka + lineNumbersWidth + 2 + args.x, 1, currentColorScheme.selection, 0xFFFFFF, " ")
end
--Средние выделения
if heightOfSelection > 2 then
for i = 1, heightOfSelection - 2 do
if args.selection.from.y + i >= args.fromString and args.selection.from.y + i < args.fromString + args.height then
buffer.square(textFieldPosition, args.y + args.selection.from.y + i - args.fromString, widthOfText + 2, 1, currentColorScheme.selection, 0xFFFFFF, " ")
end
end
end
--Нижнее выделение
if args.selection.to.x >= args.fromSymbol and args.selection.to.y >= args.fromString and args.selection.to.y < args.fromString + args.height then
buffer.square(textFieldPosition, args.y + args.selection.to.y - args.fromString, args.selection.to.x - args.fromSymbol + 1, 1, currentColorScheme.selection, 0xFFFFFF, " ")
end
elseif heightOfSelection == 1 then
local cyka = args.selection.to.x
if cyka > args.fromSymbol + widthOfText - 1 then cyka = args.fromSymbol + widthOfText - 1 end
buffer.square(textFieldPosition + args.selection.from.x, args.selection.from.y, cyka - args.selection.from.x, 1, currentColorScheme.selection, 0xFFFFFF, " ")
end
end
--Выставляем ограничение прорисовки буфера
textFieldPosition = textFieldPosition + 1
buffer.setDrawLimit(textFieldPosition, args.y, widthOfText, args.height)
--Рисуем текст
yPos = args.y
for i = args.fromString, maximumNumberOfAvailableStrings do
--Учитываем опциональную подсветку ситнаксиса
if args.highlightLuaSyntax then
syntax.highlightString(textFieldPosition, yPos, args.strings[i], args.fromSymbol, widthOfText)
else
buffer.text(textFieldPosition, yPos, currentColorScheme.text, unicode.sub(args.strings[i], args.fromSymbol, widthOfText))
end
yPos = yPos + 1
end
--Убираем ограничение отрисовки
buffer.resetDrawLimit()
--Рисуем вертикальный скроллбар
if args.scrollbars.vertical then buffer.scrollBar(xEnd, args.y, 1, args.height, #args.strings, args.fromString, currentColorScheme.scrollBar, currentColorScheme.scrollBarPipe) end
--Рисуем горизонтальный скроллбар
if args.scrollbars.horizontal then buffer.horizontalScrollBar(args.x + lineNumbersWidth, yEnd, args.width - lineNumbersWidth - 1, args.maximumStringWidth, args.fromSymbol, currentColorScheme.scrollBar, currentColorScheme.scrollBarPipe) end
--Для всяких майнкодов, чтоб курсор можно было ставит и ТОПЕ
return textFieldPosition
end
----------------------------------------------------------------------------------------------------------------
-- Стартовое объявление цветовой схемы при загрузке библиотеки
syntax.setColorScheme(syntax.colorSchemes.midnight)
----------------------------------------------------------------------------------------------------------------
-- buffer.start()
-- buffer.clear(0xFF8888)
-- local strings, maximumStringWidth = convertFileToStrings("/OS.lua")
-- local args = {
-- x = 1,
-- y = 1,
-- width = 100,
-- height = 40,
-- strings = strings,
-- fromString = 1,
-- fromSymbol = 1,
-- fromStringOnLineNumbers = 6,
-- maximumStringWidth = maximumStringWidth,
-- highlightLuaSyntax = true,
-- selection = {
-- from = {x = 8, y = 6},
-- to = {x = 16, y = 12}
-- },
-- highlightedStrings = {
-- [31] = 0xFF4444,
-- [33] = 0x55FF55,
-- },
-- scrollbars = {
-- vertical = true,
-- horizontal = true,
-- }
-- }
-- syntax.viewCode(args)
-- buffer.draw()
----------------------------------------------------------------------------------------------------------------
return syntax