From 6da2b175e20ed3c03b0dfcfc9046de1e0e5d4444 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=80=E8=90=8C=E5=B0=8F=E6=B1=90?= Date: Sat, 23 Nov 2019 00:05:30 +0800 Subject: =?UTF-8?q?=E6=AD=A3=E8=B7=AF=E7=9B=AE=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- script/core/document_symbol.lua | 260 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 260 insertions(+) create mode 100644 script/core/document_symbol.lua (limited to 'script/core/document_symbol.lua') diff --git a/script/core/document_symbol.lua b/script/core/document_symbol.lua new file mode 100644 index 00000000..48e01332 --- /dev/null +++ b/script/core/document_symbol.lua @@ -0,0 +1,260 @@ +local hoverFunction = require 'core.hover.function' +local getName = require 'core.name' +local hover = require 'core.hover' + +local SymbolKind = { + File = 1, + Module = 2, + Namespace = 3, + Package = 4, + Class = 5, + Method = 6, + Property = 7, + Field = 8, + Constructor = 9, + Enum = 10, + Interface = 11, + Function = 12, + Variable = 13, + Constant = 14, + String = 15, + Number = 16, + Boolean = 17, + Array = 18, + Object = 19, + Key = 20, + Null = 21, + EnumMember = 22, + Struct = 23, + Event = 24, + Operator = 25, + TypeParameter = 26, +} + +local function buildLocal(vm, source, used, callback) + local vars = source[1] + local exps = source[2] + if vars.type ~= 'list' then + vars = {vars} + end + if not exps or exps.type ~= 'list' then + exps = {exps} + end + for i, var in ipairs(vars) do + local exp = exps[i] + local data = {} + local loc = var:bindLocal() + data.name = loc:getName() + data.range = { var.start, var.finish } + data.selectionRange = { var.start, var.finish } + if exp then + local hvr = hover(var) + if exp.type == 'function' then + data.kind = SymbolKind.Function + else + data.kind = SymbolKind.Variable + end + data.detail = hvr.label:gsub('[\r\n]', '') + data.valueRange = { exp.start, exp.finish } + used[exp] = true + else + data.kind = SymbolKind.Variable + data.detail = '' + data.valueRange = { var.start, var.finish } + end + callback(data) + end +end + +local function buildSet(vm, source, used, callback) + local vars = source[1] + local exps = source[2] + if vars.type ~= 'list' then + vars = {vars} + end + if not exps or exps.type ~= 'list' then + exps = {exps} + end + for i, var in ipairs(vars) do + if var:bindLocal() then + goto CONTINUE + end + local exp = exps[i] + local data = {} + data.name = getName(var) + data.range = { var.start, var.finish } + data.selectionRange = { var.start, var.finish } + if exp then + local hvr = hover(var) + if not hvr then + goto CONTINUE + end + if exp.type == 'function' then + data.kind = SymbolKind.Function + else + data.kind = SymbolKind.Property + end + data.detail = hvr.label:gsub('[\r\n]', '') + data.valueRange = { exp.start, exp.finish } + used[exp] = true + else + data.kind = SymbolKind.Property + data.detail = '' + data.valueRange = { var.start, var.finish } + end + callback(data) + :: CONTINUE :: + end +end + +local function buildPair(vm, source, used, callback) + local var = source[1] + local exp = source[2] + local data = {} + data.name = getName(var) + data.range = { var.start, var.finish } + data.selectionRange = { var.start, var.finish } + if exp then + local hvr = hover(var) + if not hvr then + return + end + if exp.type == 'function' then + data.kind = SymbolKind.Function + else + data.kind = SymbolKind.Class + end + data.detail = hvr.label:gsub('[\r\n]', '') + data.valueRange = { exp.start, exp.finish } + used[exp] = true + else + data.kind = SymbolKind.Class + data.detail = '' + data.valueRange = { var.start, var.finish } + end + callback(data) +end + +local function buildLocalFunction(vm, source, used, callback) + local value = source:bindFunction() + if not value then + return + end + local name = getName(source.name) + local hvr = hoverFunction(name, value:getFunction()) + if not hvr then + return + end + local kind = SymbolKind.Function + callback { + name = name, + detail = hvr.label:gsub('[\r\n]', ''), + kind = kind, + range = { source.start, source.finish }, + selectionRange = { source.name.start, source.name.finish }, + valueRange = { source.start, source.finish }, + } +end + + +local function buildFunction(vm, source, used, callback) + if used[source] then + return + end + local value = source:bindFunction() + if not value then + return + end + local name = getName(source.name) + local func = value:getFunction() + if not func then + return + end + local hvr = hoverFunction(name, func, func:getObject()) + if not hvr then + return + end + local data = {} + data.name = name + data.detail = hvr.label:gsub('[\r\n]', '') + data.range = { source.start, source.finish } + data.valueRange = { source.start, source.finish } + if source.name then + data.selectionRange = { source.name.start, source.name.finish } + else + data.selectionRange = { source.start, source.start } + end + if func:getObject() then + data.kind = SymbolKind.Field + else + data.kind = SymbolKind.Function + end + callback(data) +end + +local function buildSource(vm, source, used, callback) + if source.type == 'local' then + buildLocal(vm, source, used, callback) + return + end + if source.type == 'set' then + buildSet(vm, source, used, callback) + return + end + if source.type == 'pair' then + buildPair(vm, source, used, callback) + return + end + if source.type == 'localfunction' then + buildLocalFunction(vm, source, used, callback) + return + end + if source.type == 'function' then + buildFunction(vm, source, used, callback) + return + end +end + +local function packChild(symbols, finish, kind) + local t + while true do + local symbol = symbols[#symbols] + if not symbol then + break + end + if symbol.valueRange[1] > finish then + break + end + symbols[#symbols] = nil + symbol.children = packChild(symbols, symbol.valueRange[2], symbol.kind) + if not t then + t = {} + end + t[#t+1] = symbol + end + return t +end + +local function packSymbols(symbols) + -- 按照start位置反向排序 + table.sort(symbols, function (a, b) + return a.range[1] > b.range[1] + end) + -- 处理嵌套 + return packChild(symbols, math.maxinteger, SymbolKind.Function) +end + +return function (vm) + local symbols = {} + local used = {} + + vm:eachSource(function (source) + buildSource(vm, source, used, function (data) + symbols[#symbols+1] = data + end) + end) + + local packedSymbols = packSymbols(symbols) + + return packedSymbols +end -- cgit v1.2.3