summaryrefslogtreecommitdiff
path: root/server-beta
diff options
context:
space:
mode:
author最萌小汐 <sumneko@hotmail.com>2019-11-16 03:02:01 +0800
committer最萌小汐 <sumneko@hotmail.com>2019-11-16 03:02:01 +0800
commit81fb889cbf994be47f162dbfda446f80e51c6fab (patch)
tree3bf11ab96b180000e3228ea16188d1d888475df8 /server-beta
parentf2c235601da54117b803e084d94bbf88ba53b891 (diff)
downloadlua-language-server-81fb889cbf994be47f162dbfda446f80e51c6fab.zip
支持高亮
Diffstat (limited to 'server-beta')
-rw-r--r--server-beta/src/core/highlight.lua94
-rw-r--r--server-beta/src/parser/ast.lua127
-rw-r--r--server-beta/src/parser/grammar.lua59
-rw-r--r--server-beta/src/parser/guide.lua2
-rw-r--r--server-beta/test/highlight/init.lua99
5 files changed, 288 insertions, 93 deletions
diff --git a/server-beta/src/core/highlight.lua b/server-beta/src/core/highlight.lua
index 16c82a16..8c609485 100644
--- a/server-beta/src/core/highlight.lua
+++ b/server-beta/src/core/highlight.lua
@@ -13,7 +13,6 @@ local function ofLocal(source, callback)
end
local function ofField(source, uri, callback)
- callback(source)
local parent = source.parent
if not parent or not parent.node then
return
@@ -55,23 +54,96 @@ local function find(source, uri, callback)
elseif source.type == 'field'
or source.type == 'method' then
ofField(source, uri, callback)
- elseif source.type == 'string' then
- ofIndex(source, uri, callback)
- callback(source)
- elseif source.type == 'boolean'
+ elseif source.type == 'string'
+ or source.type == 'boolean'
or source.type == 'number' then
ofIndex(source, uri, callback)
+ callback(source)
+ elseif source.type == 'nil' then
+ callback(source)
elseif source.type == 'goto'
or source.type == 'label' then
ofLabel(source, callback)
end
end
+local function checkInIf(source, text, offset)
+ -- 检查 end
+ local endA = source.finish - #'end' + 1
+ local endB = source.finish
+ if offset >= endA
+ and offset <= endB
+ and text:sub(endA, endB) == 'end' then
+ return true
+ end
+ -- 检查每个子模块
+ for _, block in ipairs(source) do
+ for i = 1, #block.keyword, 2 do
+ local start = block.keyword[i]
+ local finish = block.keyword[i+1]
+ if offset >= start and offset <= finish then
+ return true
+ end
+ end
+ end
+ return false
+end
+
+local function makeIf(source, text, callback)
+ -- end
+ local endA = source.finish - #'end' + 1
+ local endB = source.finish
+ if text:sub(endA, endB) == 'end' then
+ callback(endA, endB)
+ end
+ -- 每个子模块
+ for _, block in ipairs(source) do
+ for i = 1, #block.keyword, 2 do
+ local start = block.keyword[i]
+ local finish = block.keyword[i+1]
+ callback(start, finish)
+ end
+ end
+ return false
+end
+
+local function findKeyword(source, text, offset, callback)
+ if source.type == 'do'
+ or source.type == 'function'
+ or source.type == 'loop'
+ or source.type == 'in'
+ or source.type == 'while'
+ or source.type == 'repeat' then
+ local ok
+ for i = 1, #source.keyword, 2 do
+ local start = source.keyword[i]
+ local finish = source.keyword[i+1]
+ if offset >= start and offset <= finish then
+ ok = true
+ break
+ end
+ end
+ if ok then
+ for i = 1, #source.keyword, 2 do
+ local start = source.keyword[i]
+ local finish = source.keyword[i+1]
+ callback(start, finish)
+ end
+ end
+ elseif source.type == 'if' then
+ local ok = checkInIf(source, text, offset)
+ if ok then
+ makeIf(source, text, callback)
+ end
+ end
+end
+
return function (uri, offset)
local ast = files.getAst(uri)
if not ast then
return nil
end
+ local text = files.getText(uri)
local results = {}
local mark = {}
guide.eachSourceContain(ast.ast, offset, function (source)
@@ -106,7 +178,10 @@ return function (uri, offset)
or target.type == 'setglobal'
or target.type == 'label' then
kind = define.DocumentHighlightKind.Write
- elseif target.type == 'string' then
+ elseif target.type == 'string'
+ or target.type == 'boolean'
+ or target.type == 'number'
+ or target.type == 'nil' then
kind = define.DocumentHighlightKind.Text
else
log.warn('Unknow target.type:', target.type)
@@ -122,6 +197,13 @@ return function (uri, offset)
kind = kind,
}
end)
+ findKeyword(source, text, offset, function (start, finish)
+ results[#results+1] = {
+ start = start,
+ finish = finish,
+ kind = define.DocumentHighlightKind.Write
+ }
+ end)
end)
if #results == 0 then
return nil
diff --git a/server-beta/src/parser/ast.lua b/server-beta/src/parser/ast.lua
index ded42891..ff5a6ae1 100644
--- a/server-beta/src/parser/ast.lua
+++ b/server-beta/src/parser/ast.lua
@@ -662,6 +662,9 @@ local Defs = {
return e
end,
Binary = function (first, op, second, ...)
+ if not first then
+ return second
+ end
if not op then
return first
end
@@ -836,20 +839,28 @@ local Defs = {
finish = start,
}
end,
- Function = function (start, args, actions, finish)
+ Function = function (functionStart, functionFinish, args, actions, endStart, endFinish)
actions.type = 'function'
- actions.start = start
- actions.finish = finish - 1
+ actions.start = functionStart
+ actions.finish = endFinish - 1
actions.args = args
- checkMissEnd(start)
+ actions.keyword= {
+ functionStart, functionFinish - 1,
+ endStart, endFinish - 1,
+ }
+ checkMissEnd(functionStart)
return actions
end,
- NamedFunction = function (start, name, args, actions, finish)
+ NamedFunction = function (functionStart, functionFinish, name, args, actions, endStart, endFinish)
actions.type = 'function'
- actions.start = start
- actions.finish = finish - 1
+ actions.start = functionStart
+ actions.finish = endFinish - 1
actions.args = args
- checkMissEnd(start)
+ actions.keyword= {
+ functionStart, functionFinish - 1,
+ endStart, endFinish - 1,
+ }
+ checkMissEnd(functionStart)
if not name then
return
end
@@ -864,13 +875,18 @@ local Defs = {
name.value = actions
end
name.range = actions.finish
+ name.vstart = functionStart
return name
end,
- LocalFunction = function (start, name, args, actions, finish)
+ LocalFunction = function (start, functionStart, functionFinish, name, args, actions, endStart, endFinish)
actions.type = 'function'
actions.start = start
- actions.finish = finish - 1
+ actions.finish = endFinish - 1
actions.args = args
+ actions.keyword= {
+ functionStart, functionFinish - 1,
+ endStart, endFinish - 1,
+ }
checkMissEnd(start)
if not name then
@@ -888,6 +904,7 @@ local Defs = {
local loc = createLocal(name, name.start, actions)
loc.localfunction = true
+ loc.vstart = functionStart
return loc
end,
@@ -1126,10 +1143,14 @@ local Defs = {
end
return tableUnpack(keys)
end,
- Do = function (start, actions, finish)
+ Do = function (start, actions, endA, endB)
actions.type = 'do'
actions.start = start
- actions.finish = finish - 1
+ actions.finish = endB - 1
+ actions.keyword= {
+ start, start + #'do' - 1,
+ endA , endB - 1,
+ }
checkMissEnd(start)
return actions
end,
@@ -1184,30 +1205,41 @@ local Defs = {
name.type = 'goto'
return name
end,
- IfBlock = function (start, exp, actions, finish)
+ IfBlock = function (ifStart, ifFinish, exp, thenStart, thenFinish, actions, finish)
actions.type = 'ifblock'
- actions.start = start
+ actions.start = ifStart
actions.finish = finish - 1
actions.filter = exp
+ actions.keyword= {
+ ifStart, ifFinish - 1,
+ thenStart, thenFinish - 1,
+ }
return actions
end,
- ElseIfBlock = function (start, exp, actions, finish)
+ ElseIfBlock = function (elseifStart, elseifFinish, exp, thenStart, thenFinish, actions, finish)
actions.type = 'elseifblock'
- actions.start = start
+ actions.start = elseifStart
actions.finish = finish - 1
actions.filter = exp
+ actions.keyword= {
+ elseifStart, elseifFinish - 1,
+ thenStart, thenFinish - 1,
+ }
return actions
end,
- ElseBlock = function (start, actions, finish)
+ ElseBlock = function (elseStart, elseFinish, actions, finish)
actions.type = 'elseblock'
- actions.start = start
+ actions.start = elseStart
actions.finish = finish - 1
+ actions.keyword= {
+ elseStart, elseFinish - 1,
+ }
return actions
end,
- If = function (start, blocks, finish)
+ If = function (start, blocks, endStart, endFinish)
blocks.type = 'if'
blocks.start = start
- blocks.finish = finish - 1
+ blocks.finish = endFinish - 1
local hasElse
for i = 1, #blocks do
local block = blocks[i]
@@ -1235,23 +1267,34 @@ local Defs = {
checkMissEnd(start)
return blocks
end,
- Loop = function (start, arg, steps, blockStart, block, finish)
+ Loop = function (forA, forB, arg, steps, doA, doB, blockStart, block, endA, endB)
local loc = createLocal(arg, blockStart, steps[1])
block.type = 'loop'
- block.start = start
- block.finish = finish - 1
+ block.start = forA
+ block.finish = endB - 1
block.loc = loc
block.max = steps[2]
block.step = steps[3]
- checkMissEnd(start)
+ block.keyword= {
+ forA, forB - 1,
+ doA , doB - 1,
+ endA, endB - 1,
+ }
+ checkMissEnd(forA)
return block
end,
- In = function (start, keys, exp, blockStart, block, finish)
+ In = function (forA, forB, keys, inA, inB, exp, doA, doB, blockStart, block, endA, endB)
local func = tableRemove(exp, 1)
block.type = 'in'
- block.start = start
- block.finish = finish - 1
+ block.start = forA
+ block.finish = endB - 1
block.keys = keys
+ block.keyword= {
+ forA, forB - 1,
+ inA , inB - 1,
+ doA , doB - 1,
+ endA, endB - 1,
+ }
local values
if func then
@@ -1270,22 +1313,31 @@ local Defs = {
createLocal(loc, blockStart)
end
end
- checkMissEnd(start)
+ checkMissEnd(forA)
return block
end,
- While = function (start, filter, block, finish)
+ While = function (whileA, whileB, filter, doA, doB, block, endA, endB)
block.type = 'while'
- block.start = start
- block.finish = finish - 1
+ block.start = whileA
+ block.finish = endB - 1
block.filter = filter
- checkMissEnd(start)
+ block.keyword= {
+ whileA, whileB - 1,
+ doA , doB - 1,
+ endA , endB - 1,
+ }
+ checkMissEnd(whileA)
return block
end,
- Repeat = function (start, block, filter, finish)
+ Repeat = function (repeatA, repeatB, block, untilA, untilB, filter, finish)
block.type = 'repeat'
- block.start = start
+ block.start = repeatA
block.finish = finish
block.filter = filter
+ block.keyword= {
+ repeatA, repeatB - 1,
+ untilA , untilB - 1,
+ }
return block
end,
Lua = function (start, actions, finish)
@@ -1491,6 +1543,7 @@ local Defs = {
symbol = 'end',
}
}
+ return pos, pos
end,
MissDo = function (pos)
PushError {
@@ -1501,6 +1554,7 @@ local Defs = {
symbol = 'do',
}
}
+ return pos, pos
end,
MissComma = function (pos)
PushError {
@@ -1521,6 +1575,7 @@ local Defs = {
symbol = 'in',
}
}
+ return pos, pos
end,
MissUntil = function (pos)
PushError {
@@ -1531,6 +1586,7 @@ local Defs = {
symbol = 'until',
}
}
+ return pos, pos
end,
MissThen = function (pos)
PushError {
@@ -1541,6 +1597,7 @@ local Defs = {
symbol = 'then',
}
}
+ return pos, pos
end,
MissName = function (pos)
PushError {
@@ -1639,6 +1696,7 @@ local Defs = {
}
}
}
+ return start, finish
end,
ErrDo = function (start, finish)
PushError {
@@ -1654,6 +1712,7 @@ local Defs = {
}
}
}
+ return start, finish
end,
}
diff --git a/server-beta/src/parser/grammar.lua b/server-beta/src/parser/grammar.lua
index 944f34ea..b64f6277 100644
--- a/server-beta/src/parser/grammar.lua
+++ b/server-beta/src/parser/grammar.lua
@@ -112,28 +112,30 @@ Rest <- (!%nl .)*
AND <- Sp {'and'} Cut
BREAK <- Sp 'break' Cut
-DO <- Sp 'do' Cut
- / Sp ({} 'then' Cut {}) -> ErrDo
-ELSE <- Sp 'else' Cut
-ELSEIF <- Sp 'elseif' Cut
-END <- Sp 'end' Cut
FALSE <- Sp 'false' Cut
-FOR <- Sp 'for' Cut
-FUNCTION <- Sp 'function' Cut
GOTO <- Sp 'goto' Cut
-IF <- Sp 'if' Cut
-IN <- Sp 'in' Cut
LOCAL <- Sp 'local' Cut
NIL <- Sp 'nil' Cut
NOT <- Sp 'not' Cut
OR <- Sp {'or'} Cut
-REPEAT <- Sp 'repeat' Cut
RETURN <- Sp 'return' Cut
-THEN <- Sp 'then' Cut
- / Sp ({} 'do' Cut {}) -> ErrThen
TRUE <- Sp 'true' Cut
-UNTIL <- Sp 'until' Cut
-WHILE <- Sp 'while' Cut
+
+DO <- Sp {} 'do' {} Cut
+ / Sp({} 'then' {} Cut) -> ErrDo
+IF <- Sp {} 'if' {} Cut
+ELSE <- Sp {} 'else' {} Cut
+ELSEIF <- Sp {} 'elseif' {} Cut
+END <- Sp {} 'end' {} Cut
+FOR <- Sp {} 'for' {} Cut
+FUNCTION <- Sp {} 'function' {} Cut
+IN <- Sp {} 'in' {} Cut
+REPEAT <- Sp {} 'repeat' {} Cut
+THEN <- Sp {} 'then' {} Cut
+ / Sp({} 'do' {} Cut) -> ErrThen
+UNTIL <- Sp {} 'until' {} Cut
+WHILE <- Sp {} 'while' {} Cut
+
Esc <- '\' -> ''
EChar
@@ -365,7 +367,7 @@ NewIndex <- Sp ({} Index NeedAssign DirtyExp {})
NewField <- Sp ({} MustName ASSIGN DirtyExp {})
-> NewField
-Function <- Sp ({} FunctionBody {})
+Function <- FunctionBody
-> Function
FuncArgs <- Sp ({} PL {| FuncArg+ |} DirtyPR {})
-> FuncArgs
@@ -415,8 +417,7 @@ SimpleList <- {| Simple (Sp ',' Simple)* |}
Do <- Sp ({}
'do' Cut
{| (!END Action)* |}
- NeedEnd
- {})
+ NeedEnd)
-> Do
Break <- Sp ({} BREAK {})
@@ -435,14 +436,14 @@ Label <- Sp ({} LABEL MustName DirtyLabel {})
GoTo <- Sp ({} GOTO MustName {})
-> GoTo
-If <- Sp ({} {| IfHead IfBody* |} NeedEnd {})
+If <- Sp ({} {| IfHead IfBody* |} NeedEnd)
-> If
-IfHead <- Sp ({} IfPart {}) -> IfBlock
- / Sp ({} ElseIfPart {}) -> ElseIfBlock
- / Sp ({} ElsePart {}) -> ElseBlock
-IfBody <- Sp ({} ElseIfPart {}) -> ElseIfBlock
- / Sp ({} ElsePart {}) -> ElseBlock
+IfHead <- Sp (IfPart {}) -> IfBlock
+ / Sp (ElseIfPart {}) -> ElseIfBlock
+ / Sp (ElsePart {}) -> ElseBlock
+IfBody <- Sp (ElseIfPart {}) -> ElseIfBlock
+ / Sp (ElsePart {}) -> ElseBlock
IfPart <- IF DirtyExp NeedThen
{| (!ELSEIF !ELSE !END Action)* |}
ElseIfPart <- ELSEIF DirtyExp NeedThen
@@ -452,7 +453,7 @@ ElsePart <- ELSE
For <- Loop / In
-Loop <- Sp ({} LoopBody {})
+Loop <- LoopBody
-> Loop
LoopBody <- FOR LoopArgs NeedDo
{} {| (!END Action)* |}
@@ -461,7 +462,7 @@ LoopArgs <- MustName AssignOrEQ
({} {| (COMMA / !DO !END Exp)* |} {})
-> PackLoopArgs
-In <- Sp ({} InBody {})
+In <- InBody
-> In
InBody <- FOR InNameList NeedIn InExpList NeedDo
{} {| (!END Action)* |}
@@ -471,13 +472,13 @@ InNameList <- ({} {| (COMMA / !IN !DO !END Name)* |} {})
InExpList <- ({} {| (COMMA / !DO !DO !END Exp)* |} {})
-> PackInExpList
-While <- Sp ({} WhileBody {})
+While <- WhileBody
-> While
WhileBody <- WHILE DirtyExp NeedDo
{| (!END Action)* |}
NeedEnd
-Repeat <- Sp ({} RepeatBody {})
+Repeat <- (RepeatBody {})
-> Repeat
RepeatBody <- REPEAT
{| (!UNTIL Action)* |}
@@ -499,11 +500,11 @@ Call <- Simple
-> SimpleCall
LocalFunction
- <- Sp ({} LOCAL FunctionNamedBody {})
+ <- Sp ({} LOCAL FunctionNamedBody)
-> LocalFunction
NamedFunction
- <- Sp ({} FunctionNamedBody {})
+ <- FunctionNamedBody
-> NamedFunction
FunctionNamedBody
<- FUNCTION FuncName FuncArgs
diff --git a/server-beta/src/parser/guide.lua b/server-beta/src/parser/guide.lua
index a5b8202e..4750fcaf 100644
--- a/server-beta/src/parser/guide.lua
+++ b/server-beta/src/parser/guide.lua
@@ -268,7 +268,7 @@ end
---
--- 主要针对赋值等语句时,key包含value
function m.isInRange(source, offset)
- return source.start <= offset and (source.range or source.finish) >= offset - 1
+ return (source.vstart or source.start) <= offset and (source.range or source.finish) >= offset - 1
end
--- 添加child
diff --git a/server-beta/test/highlight/init.lua b/server-beta/test/highlight/init.lua
index 6298fc2e..fbde194b 100644
--- a/server-beta/test/highlight/init.lua
+++ b/server-beta/test/highlight/init.lua
@@ -35,58 +35,111 @@ local function founded(targets, results)
end
function TEST(script)
- files.removeAll()
local target = catch_target(script)
- local start = script:find('<?', 1, true)
- local finish = script:find('?>', 1, true)
- local pos = (start + finish) // 2 + 1
- local new_script = script:gsub('<[!?]', ' '):gsub('[!?]>', ' ')
- files.setText('', new_script)
-
- local positions = core('', pos)
- if positions then
- assert(founded(target, positions))
- else
- assert(#target == 0)
+ for _, enter in ipairs(target) do
+ local start, finish = enter.start, enter.finish
+ files.removeAll()
+ local pos = (start + finish) // 2 + 1
+ local new_script = script:gsub('<[!?~]', ' '):gsub('[!?~]>', ' ')
+ files.setText('', new_script)
+
+ local positions = core('', pos)
+ if positions then
+ assert(founded(target, positions))
+ else
+ assert(#target == 0)
+ end
end
end
TEST [[
-local <?a?> = 1
+local <!a!> = 1
]]
TEST [[
-local <?a?> = 1
+local <!a!> = 1
<!a!> = 2
<!a!> = <!a!>
]]
TEST [[
-t.<?a?> = 1
+t.<!a!> = 1
a = t.<!a!>
]]
TEST [[
t[<!'a'!>] = 1
-a = t.<?a?>
-]]
-
-TEST [[
-t[<?'a'?>] = 1
a = t.<!a!>
]]
TEST [[
-:: <?a?> ::
+:: <!a!> ::
goto <!a!>
]]
TEST [[
local function f(<!a!>)
- return <?a?>
+ return <!a!>
end
]]
TEST [[
-local s = <?'asd/gadasd.fad.zxczg'?>
+local s = <!'asd/gadasd.fad.zxczg'!>
+]]
+
+TEST [[
+local b = <!true!>
+]]
+
+TEST [[
+local n = <!nil!>
+]]
+
+TEST [[
+local n = <!1.2354!>
+]]
+
+TEST [[
+local <!function!> f () <!end!>
+]]
+
+TEST [[
+<!function!> f () <!end!>
+]]
+
+TEST [[
+return <!function!> () <!end!>
+]]
+
+TEST [[
+<!if!> true <!then!>
+<!elseif!> true <!then!>
+<!elseif!> true <!then!>
+<!else!>
+<!end!>
+]]
+
+TEST [[
+<!for!> _ <!in!> _ <!do!>
+<!end!>
+]]
+
+TEST [[
+<!for!> i = 1, 10 <!do!>
+<!end!>
+]]
+
+TEST [[
+<!while!> true <!do!>
+<!end!>
+]]
+
+TEST [[
+<!repeat!>
+<!until!> true
+]]
+
+TEST [[
+<!do!>
+<!end!>
]]