mirror of https://github.com/teverse/teverse
Compare commits
No commits in common. "a2fbd3032d09c3d475bce41a5907529fb9800ee1" and "a9b9d0dec612cdd884045254e9743cb2d87285f1" have entirely different histories.
a2fbd3032d
...
a9b9d0dec6
|
@ -1,431 +0,0 @@
|
||||||
-- MIT License
|
|
||||||
--
|
|
||||||
-- Copyright (c) 2018 LoganDark
|
|
||||||
--
|
|
||||||
-- Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
-- of this software and associated documentation files (the "Software"), to deal
|
|
||||||
-- in the Software without restriction, including without limitation the rights
|
|
||||||
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
-- copies of the Software, and to permit persons to whom the Software is
|
|
||||||
-- furnished to do so, subject to the following conditions:
|
|
||||||
--
|
|
||||||
-- The above copyright notice and this permission notice shall be included in all
|
|
||||||
-- copies or substantial portions of the Software.
|
|
||||||
--
|
|
||||||
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
-- SOFTWARE.
|
|
||||||
|
|
||||||
function lookupify(src, list)
|
|
||||||
list = list or {}
|
|
||||||
|
|
||||||
if type(src) == 'string' then
|
|
||||||
for i = 1, src:len() do
|
|
||||||
list[src:sub(i, i)] = true
|
|
||||||
end
|
|
||||||
elseif type(src) == 'table' then
|
|
||||||
for i = 1, #src do
|
|
||||||
list[src[i]] = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return list
|
|
||||||
end
|
|
||||||
|
|
||||||
local base_ident = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_'
|
|
||||||
local base_digits = '0123456789'
|
|
||||||
local base_operators = '+-*/^%#'
|
|
||||||
|
|
||||||
local chars = {
|
|
||||||
whitespace = lookupify(' \n\t\r'),
|
|
||||||
validEscapes = lookupify('abfnrtv"\'\\'),
|
|
||||||
ident = lookupify(
|
|
||||||
base_ident .. base_digits,
|
|
||||||
{
|
|
||||||
start = lookupify(base_ident),
|
|
||||||
}
|
|
||||||
),
|
|
||||||
|
|
||||||
digits = lookupify(
|
|
||||||
base_digits,
|
|
||||||
{
|
|
||||||
hex = lookupify(base_digits .. 'abcdefABCDEF')
|
|
||||||
}
|
|
||||||
),
|
|
||||||
|
|
||||||
symbols = lookupify(
|
|
||||||
base_operators .. ',{}[]();.:', {
|
|
||||||
equality = lookupify('~=><'),
|
|
||||||
operators = lookupify(base_operators)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
local keywords = {
|
|
||||||
structure = lookupify({
|
|
||||||
'and', 'break', 'do', 'else', 'elseif', 'end', 'for', 'function',
|
|
||||||
'goto', 'if', 'in', 'local', 'not', 'or', 'repeat', 'return', 'then',
|
|
||||||
'until', 'while'
|
|
||||||
}),
|
|
||||||
|
|
||||||
values = lookupify({
|
|
||||||
'true', 'false', 'nil'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return function(text)
|
|
||||||
local pos = 1
|
|
||||||
local start = 1
|
|
||||||
local buffer = {}
|
|
||||||
local lines = {}
|
|
||||||
|
|
||||||
local function look(delta)
|
|
||||||
delta = pos + (delta or 0)
|
|
||||||
|
|
||||||
return text:sub(delta, delta)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function get()
|
|
||||||
pos = pos + 1
|
|
||||||
|
|
||||||
return look(-1)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function getDataLevel()
|
|
||||||
local num = 0
|
|
||||||
|
|
||||||
while look(num) == '=' do
|
|
||||||
num = num + 1
|
|
||||||
end
|
|
||||||
|
|
||||||
if look(num) == '[' then
|
|
||||||
pos = pos + num + 1
|
|
||||||
|
|
||||||
return num
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function getCurrentTokenText()
|
|
||||||
return text:sub(start, pos - 1)
|
|
||||||
end
|
|
||||||
|
|
||||||
local currentLineLength = 0
|
|
||||||
local lineoffset = 0
|
|
||||||
|
|
||||||
local function pushToken(type, text)
|
|
||||||
text = text or getCurrentTokenText()
|
|
||||||
|
|
||||||
local tk = buffer[#buffer]
|
|
||||||
|
|
||||||
if not tk or tk.type ~= type then
|
|
||||||
tk = {
|
|
||||||
type = type,
|
|
||||||
data = text,
|
|
||||||
posFirst = start - lineoffset,
|
|
||||||
posLast = pos - 1 - lineoffset
|
|
||||||
}
|
|
||||||
|
|
||||||
if tk.data ~= '' then
|
|
||||||
buffer[#buffer + 1] = tk
|
|
||||||
end
|
|
||||||
else
|
|
||||||
tk.data = tk.data .. text
|
|
||||||
tk.posLast = tk.posLast + text:len()
|
|
||||||
end
|
|
||||||
|
|
||||||
currentLineLength = currentLineLength + text:len()
|
|
||||||
start = pos
|
|
||||||
|
|
||||||
return tk
|
|
||||||
end
|
|
||||||
|
|
||||||
local function newline()
|
|
||||||
lines[#lines + 1] = buffer
|
|
||||||
buffer = {}
|
|
||||||
|
|
||||||
get()
|
|
||||||
pushToken('newline')
|
|
||||||
buffer[1] = nil
|
|
||||||
|
|
||||||
lineoffset = lineoffset + currentLineLength
|
|
||||||
currentLineLength = 0
|
|
||||||
end
|
|
||||||
|
|
||||||
local function getData(level, type)
|
|
||||||
while true do
|
|
||||||
local char = get()
|
|
||||||
|
|
||||||
if char == '' then
|
|
||||||
return
|
|
||||||
elseif char == '\n' then
|
|
||||||
pos = pos - 1
|
|
||||||
pushToken(type)
|
|
||||||
newline()
|
|
||||||
elseif char == ']' then
|
|
||||||
local valid = true
|
|
||||||
|
|
||||||
for i = 1, level do
|
|
||||||
if look() == '=' then
|
|
||||||
pos = pos + 1
|
|
||||||
else
|
|
||||||
valid = false
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if valid and look() == ']' then
|
|
||||||
pos = pos - level - 1
|
|
||||||
|
|
||||||
return
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function chompWhitespace()
|
|
||||||
while true do
|
|
||||||
local char = look()
|
|
||||||
|
|
||||||
if char == '\n' then
|
|
||||||
pushToken('whitespace')
|
|
||||||
newline()
|
|
||||||
elseif chars.whitespace[char] then
|
|
||||||
pos = pos + 1
|
|
||||||
else
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
pushToken('whitespace')
|
|
||||||
end
|
|
||||||
|
|
||||||
while true do
|
|
||||||
chompWhitespace()
|
|
||||||
|
|
||||||
local char = get()
|
|
||||||
|
|
||||||
if char == '' then
|
|
||||||
break
|
|
||||||
elseif char == '-' and look() == '-' then
|
|
||||||
pos = pos + 1
|
|
||||||
|
|
||||||
if look() == '[' then
|
|
||||||
pos = pos + 1
|
|
||||||
|
|
||||||
local level = getDataLevel()
|
|
||||||
|
|
||||||
if level then
|
|
||||||
getData(level, 'comment')
|
|
||||||
|
|
||||||
pos = pos + level + 2
|
|
||||||
pushToken('comment')
|
|
||||||
else
|
|
||||||
while true do
|
|
||||||
local char2 = get()
|
|
||||||
|
|
||||||
if char2 == '' or char2 == '\n' then
|
|
||||||
pos = pos - 1
|
|
||||||
pushToken('comment')
|
|
||||||
|
|
||||||
if char2 == '\n' then
|
|
||||||
newline()
|
|
||||||
end
|
|
||||||
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
while true do
|
|
||||||
local char2 = get()
|
|
||||||
|
|
||||||
if char2 == '' or char2 == '\n' then
|
|
||||||
pos = pos - 1
|
|
||||||
pushToken('comment')
|
|
||||||
|
|
||||||
if char2 == '\n' then
|
|
||||||
newline()
|
|
||||||
end
|
|
||||||
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
pushToken('comment')
|
|
||||||
elseif char == '\'' or char == '"' then
|
|
||||||
pushToken('string_start')
|
|
||||||
|
|
||||||
while true do
|
|
||||||
local char2 = get()
|
|
||||||
|
|
||||||
if char2 == '\\' then
|
|
||||||
pos = pos - 1
|
|
||||||
pushToken('string')
|
|
||||||
get()
|
|
||||||
|
|
||||||
local char3 = get()
|
|
||||||
|
|
||||||
if chars.digits[char3] then
|
|
||||||
for i = 1, 2 do
|
|
||||||
if chars.digits[look()] then
|
|
||||||
pos = pos + 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
elseif char3 == 'x' then
|
|
||||||
if chars.digits.hex[look()] and chars.digits.hex[look(1)] then
|
|
||||||
pos = pos + 2
|
|
||||||
else
|
|
||||||
pushToken('unidentified')
|
|
||||||
end
|
|
||||||
elseif char3 == '\n' then
|
|
||||||
pos = pos - 1
|
|
||||||
pushToken('escape')
|
|
||||||
newline()
|
|
||||||
elseif not chars.validEscapes[char3] then
|
|
||||||
pushToken('unidentified')
|
|
||||||
end
|
|
||||||
|
|
||||||
pushToken('escape')
|
|
||||||
elseif char2 == '\n' then
|
|
||||||
pos = pos - 1
|
|
||||||
pushToken('string')
|
|
||||||
newline()
|
|
||||||
|
|
||||||
break
|
|
||||||
elseif char2 == char or char2 == '' then
|
|
||||||
pos = pos - 1
|
|
||||||
pushToken('string')
|
|
||||||
get()
|
|
||||||
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
pushToken('string_end')
|
|
||||||
elseif chars.ident.start[char] then
|
|
||||||
while chars.ident[look()] do
|
|
||||||
pos = pos + 1
|
|
||||||
end
|
|
||||||
|
|
||||||
local word = getCurrentTokenText()
|
|
||||||
|
|
||||||
if keywords.structure[word] then
|
|
||||||
pushToken('keyword')
|
|
||||||
elseif keywords.values[word] then
|
|
||||||
pushToken('value')
|
|
||||||
else
|
|
||||||
pushToken('ident')
|
|
||||||
end
|
|
||||||
elseif chars.digits[char] or (char == '.' and chars.digits[look()]) then
|
|
||||||
if char == '0' and look() == 'x' then
|
|
||||||
pos = pos + 1
|
|
||||||
|
|
||||||
while chars.digits.hex[look()] do
|
|
||||||
pos = pos + 1
|
|
||||||
end
|
|
||||||
else
|
|
||||||
while chars.digits[look()] do
|
|
||||||
pos = pos + 1
|
|
||||||
end
|
|
||||||
|
|
||||||
if look() == '.' then
|
|
||||||
pos = pos + 1
|
|
||||||
|
|
||||||
while chars.digits[look()] do
|
|
||||||
pos = pos + 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if look():lower() == 'e' then
|
|
||||||
pos = pos + 1
|
|
||||||
|
|
||||||
if look() == '-' then
|
|
||||||
pos = pos + 1
|
|
||||||
end
|
|
||||||
|
|
||||||
while chars.digits[look()] do
|
|
||||||
pos = pos + 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
pushToken('number')
|
|
||||||
elseif char == '[' then
|
|
||||||
local level = getDataLevel()
|
|
||||||
|
|
||||||
if level then
|
|
||||||
pushToken('string_start')
|
|
||||||
|
|
||||||
getData(level, 'string')
|
|
||||||
pushToken('string')
|
|
||||||
|
|
||||||
pos = pos + level + 2
|
|
||||||
pushToken('string_end')
|
|
||||||
else
|
|
||||||
pushToken('symbol')
|
|
||||||
end
|
|
||||||
elseif char == '.' then
|
|
||||||
if look() == '.' then
|
|
||||||
pos = pos + 1
|
|
||||||
|
|
||||||
if look() == '.' then
|
|
||||||
pos = pos + 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if getCurrentTokenText():len() == 3 then
|
|
||||||
pushToken('vararg')
|
|
||||||
else
|
|
||||||
pushToken('symbol')
|
|
||||||
end
|
|
||||||
elseif char == ':' and look() == ':' then
|
|
||||||
get()
|
|
||||||
|
|
||||||
pushToken('label_start')
|
|
||||||
|
|
||||||
chompWhitespace()
|
|
||||||
|
|
||||||
if chars.ident.start[look()] then
|
|
||||||
get()
|
|
||||||
|
|
||||||
while chars.ident[look()] do
|
|
||||||
get()
|
|
||||||
end
|
|
||||||
|
|
||||||
pushToken('label')
|
|
||||||
|
|
||||||
chompWhitespace()
|
|
||||||
|
|
||||||
if look() == ':' and look(1) == ':' then
|
|
||||||
get()
|
|
||||||
get()
|
|
||||||
|
|
||||||
pushToken('label_end')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
elseif chars.symbols.equality[char] then
|
|
||||||
if look() == '=' then
|
|
||||||
pos = pos + 1
|
|
||||||
end
|
|
||||||
|
|
||||||
pushToken('operator')
|
|
||||||
elseif chars.symbols[char] then
|
|
||||||
if chars.symbols.operators[char] then
|
|
||||||
pushToken('operator')
|
|
||||||
else
|
|
||||||
pushToken('symbol')
|
|
||||||
end
|
|
||||||
else
|
|
||||||
pushToken('unidentified')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
lines[#lines + 1] = buffer
|
|
||||||
|
|
||||||
return lines
|
|
||||||
end
|
|
|
@ -1,51 +0,0 @@
|
||||||
local lex = require("tevgit:core/editor/lexer.lua")
|
|
||||||
local theme = require("tevgit:core/editor/theme/default.lua")
|
|
||||||
|
|
||||||
local editor = teverse.construct("guiRichTextBox", {
|
|
||||||
parent = teverse.interface,
|
|
||||||
size = guiCoord(1, 0, 1, -100),
|
|
||||||
position = guiCoord(0, 0, 0, 50),
|
|
||||||
text = "local test = 10 + 10\n\n",
|
|
||||||
textWrap = true,
|
|
||||||
textFont = "tevurl:fonts/firaCodeRegular.otf",
|
|
||||||
textEditable = true
|
|
||||||
})
|
|
||||||
|
|
||||||
local function doLex()
|
|
||||||
editor:clearColours()
|
|
||||||
editor.backgroundColour = theme.background
|
|
||||||
editor.textColour = theme.foreground
|
|
||||||
|
|
||||||
local lines = lex(editor.text)
|
|
||||||
local index = 0
|
|
||||||
local lastColour = nil
|
|
||||||
for lineNumber, line in pairs(lines) do
|
|
||||||
local lineCount = 0
|
|
||||||
for _, token in pairs(line) do
|
|
||||||
local c = theme[token.type]
|
|
||||||
if c and lastColour ~= c then
|
|
||||||
editor:setColour(index + token.posFirst, c)
|
|
||||||
lastColour = c
|
|
||||||
end
|
|
||||||
|
|
||||||
lineCount = token.posLast
|
|
||||||
end
|
|
||||||
index = index + lineCount
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Highlight any pre-entered text
|
|
||||||
doLex()
|
|
||||||
|
|
||||||
local lastStroke = nil
|
|
||||||
editor:on("keyUp", function()
|
|
||||||
if lastStroke then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Limit lexxer to once very 0.2 seconds (every keystroke is inefficient)
|
|
||||||
lastStroke = true
|
|
||||||
sleep(0.2)
|
|
||||||
doLex()
|
|
||||||
lastStroke = nil
|
|
||||||
end)
|
|
|
@ -1,44 +0,0 @@
|
||||||
-- This file uses colours from https://ethanschoonover.com/solarized/
|
|
||||||
|
|
||||||
local colours = {
|
|
||||||
Base0 = colour.rgb(131, 148, 150),
|
|
||||||
Base1 = colour.rgb(147, 161, 161),
|
|
||||||
Base2 = colour.rgb(238, 232, 213),
|
|
||||||
Base3 = colour.rgb(253, 246, 227),
|
|
||||||
|
|
||||||
Base00 = colour.rgb(101, 123, 131),
|
|
||||||
Base01 = colour.rgb(88, 110, 117),
|
|
||||||
Base02 = colour.rgb(7, 54, 66),
|
|
||||||
Base03 = colour.rgb(0, 43, 54),
|
|
||||||
|
|
||||||
Yellow = colour.rgb(181, 137, 0),
|
|
||||||
Orange = colour.rgb(203, 75, 22),
|
|
||||||
Red = colour.rgb(220, 50, 47),
|
|
||||||
Magenta = colour.rgb(211, 54, 130),
|
|
||||||
Violet = colour.rgb(108, 113, 196),
|
|
||||||
Blue = colour.rgb(38, 139, 210),
|
|
||||||
Cyan = colour.rgb(42, 161, 152),
|
|
||||||
Green = colour.rgb(133, 153, 0),
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
background = colours.Base03,
|
|
||||||
foreground = colours.Base0,
|
|
||||||
|
|
||||||
comment = colours.Base01,
|
|
||||||
string_start = colours.Cyan,
|
|
||||||
string_end = colours.Cyan,
|
|
||||||
string = colours.Cyan,
|
|
||||||
escape = colours.Blue,
|
|
||||||
keyword = colours.Green,
|
|
||||||
value = colours.Green,
|
|
||||||
ident = colours.Blue,
|
|
||||||
number = colours.Magenta,
|
|
||||||
symbol = colours.Base1,
|
|
||||||
vararg = colours.Red,
|
|
||||||
operator = colours.Green,
|
|
||||||
label_start = colours.Red,
|
|
||||||
label_end = colours.Red,
|
|
||||||
label = colours.Red,
|
|
||||||
unidentified = colours.Base01
|
|
||||||
}
|
|
Loading…
Reference in New Issue