diff options
-rw-r--r-- | server/src/core/completion.lua | 83 | ||||
-rw-r--r-- | server/src/core/definition.lua | 205 | ||||
-rw-r--r-- | server/src/core/diagnostics.lua | 27 | ||||
-rw-r--r-- | server/src/core/implementation.lua | 21 | ||||
-rw-r--r-- | server/src/emmy/class.lua | 11 | ||||
-rw-r--r-- | server/src/emmy/manager.lua | 26 | ||||
-rw-r--r-- | server/src/emmy/type.lua | 41 | ||||
-rw-r--r-- | server/src/method/textDocument/completion.lua | 54 | ||||
-rw-r--r-- | server/src/method/textDocument/publishDiagnostics.lua | 5 | ||||
-rw-r--r-- | server/src/vm/emmy.lua | 53 | ||||
-rw-r--r-- | server/src/vm/local.lua | 8 | ||||
-rw-r--r-- | server/src/vm/value.lua | 9 | ||||
-rw-r--r-- | server/src/vm/vm.lua | 43 | ||||
-rw-r--r-- | server/test/completion/init.lua | 122 | ||||
-rw-r--r-- | server/test/crossfile/completion.lua | 31 | ||||
-rw-r--r-- | server/test/definition/bug.lua | 2 | ||||
-rw-r--r-- | server/test/definition/emmy.lua | 31 | ||||
-rw-r--r-- | server/test/definition/init.lua | 1 | ||||
-rw-r--r-- | server/test/definition/method.lua | 62 | ||||
-rw-r--r-- | server/test/definition/table.lua | 32 | ||||
-rw-r--r-- | server/test/diagnostics/init.lua | 53 | ||||
-rw-r--r-- | server/test/hover/init.lua | 66 |
22 files changed, 566 insertions, 420 deletions
diff --git a/server/src/core/completion.lua b/server/src/core/completion.lua index 4a487441..d0da95cd 100644 --- a/server/src/core/completion.lua +++ b/server/src/core/completion.lua @@ -397,6 +397,14 @@ local function searchEmmyKeyword(vm, source, word, callback) end end +local function searchEmmyClass(vm, source, word, callback) + vm.emmyMgr:eachClass(function (class) + if matchKey(word, class:getName()) then + callback(class:getName(), class:getSource(), CompletionItemKind.Class) + end + end) +end + local function searchSource(vm, source, word, callback) if source.type == 'keyword' then searchAsKeyowrd(vm, source, word, callback) @@ -430,6 +438,9 @@ local function searchSource(vm, source, word, callback) searchEmmyKeyword(vm, source, word, callback) return end + if source:get 'target class' then + searchEmmyClass(vm, source, word, callback) + end end local function searchInRequire(vm, select, source, callback) @@ -650,11 +661,9 @@ local function makeList(source, pos, word) end, list end -local function searchToclose(text, word, callback, pos) - if #word > 0 then - pos = pos - 1 - end - if text:sub(pos, pos) ~= '*' then +local function searchToclose(text, source, word, callback) + local pos = source.start + if text:sub(pos-1, pos-1) ~= '*' then return false end if not matchKey(word, 'toclose') then @@ -685,7 +694,62 @@ local function keywordSource(vm, word, pos) } end -return function (vm, text, pos, word, oldText) +local function findStartPos(pos, buf) + local res = nil + for i = pos, 1, -1 do + local c = buf:sub(i, i) + if c:find '[%w_]' then + res = i + else + break + end + end + if not res then + for i = pos, 1, -1 do + local c = buf:sub(i, i) + if c == '.' or c == ':' or c == '|' then + res = i + break + elseif c == '#' or c == '@' then + res = i + 1 + break + elseif c:find '[%s%c]' then + else + break + end + end + end + if not res then + return pos + end + return res +end + +local function findWord(position, text) + local word = text + for i = position, 1, -1 do + local c = text:sub(i, i) + if not c:find '[%w_]' then + word = text:sub(i+1, position) + break + end + end + return word:match('^([%w_]*)') +end + +local function getSource(vm, pos, text, filter) + local word = findWord(pos, text) + local source = findSource(vm, pos, filter) + if source then + return source, pos, word + end + pos = findStartPos(pos, text) + source = findSource(vm, pos, filter) + or keywordSource(vm, word, pos) + return source, pos, word +end + +return function (vm, text, pos, oldText) local filter = { ['name'] = true, ['string'] = true, @@ -695,10 +759,7 @@ return function (vm, text, pos, word, oldText) ['emmyIncomplete'] = true, ['call'] = true, } - local source = findSource(vm, pos, filter) - or findSource(vm, pos-1, filter) - or findSource(vm, pos+1, filter) - or keywordSource(vm, word, pos) + local source, pos, word = getSource(vm, pos, text, filter) if not source then return nil end @@ -709,7 +770,7 @@ return function (vm, text, pos, word, oldText) end end local callback, list = makeList(source, pos, word) - if searchToclose(text, word, callback, pos) then + if searchToclose(text, source, word, callback) then return list end searchSpecial(vm, source, word, callback, pos) diff --git a/server/src/core/definition.lua b/server/src/core/definition.lua index a7296bfb..335d2185 100644 --- a/server/src/core/definition.lua +++ b/server/src/core/definition.lua @@ -1,9 +1,8 @@ -local function parseValueSimily(vm, source, lsp) +local function parseValueSimily(callback, vm, source, lsp) local key = source[1] if not key then return nil end - local positions = {} vm:eachSource(function (other) if other == source then goto CONTINUE @@ -14,140 +13,43 @@ local function parseValueSimily(vm, source, lsp) and other:action() == 'set' and source:bindValue() ~= other:bindValue() then - positions[#positions+1] = { - other.start, - other.finish, - } + callback(other) end :: CONTINUE :: end) - if #positions == 0 then - return nil - end - return positions end -local function parseValueCrossFile(vm, source, lsp) +local function parseValueCrossFile(callback, vm, source, lsp) local value = source:bindValue() - local positions = {} - value:eachInfo(function (info, src) - if info.type == 'local' and src.uri == value.uri then - positions[#positions+1] = { - src.start, - src.finish, - value.uri, - } - return true - end - end) - if #positions > 0 then - return positions - end - value:eachInfo(function (info, src) - if info.type == 'set' and src.uri == value.uri then - positions[#positions+1] = { - src.start, - src.finish, - value.uri, - } - end - end) - if #positions > 0 then - return positions - end - - value:eachInfo(function (info, src) - if info.type == 'return' and src.uri == value.uri then - positions[#positions+1] = { - src.start, - src.finish, - value.uri, - } + if src.uri == value.uri then + if info.type == 'local' or info.type == 'set' or info.type == 'return' then + callback(src) + end end end) - if #positions > 0 then - return positions - end - - local destVM = lsp:getVM(value.uri) - if not destVM then - positions[#positions+1] = { - 0, 0, value.uri, - } - return positions - end - - local result = parseValueSimily(destVM, source, lsp) - if result then - for _, position in ipairs(result) do - positions[#positions+1] = position - position[3] = value.uri - end - end - if #positions > 0 then - return positions - end - return nil end -local function parseLocal(vm, source, lsp) +local function parseLocal(callback, vm, source, lsp) local positions = {} local loc = source:bindLocal() local locSource = loc:getSource() - if locSource:get 'arg' then - positions[#positions+1] = { - locSource.start, - locSource.finish, - locSource:getUri(), - } - return positions - end + --if locSource:get 'arg' then + -- callback(locSource) + --end local value = source:bindValue() if value and value.uri ~= '' and value.uri ~= vm.uri then - local positions = parseValueCrossFile(vm, source, lsp) - if positions and #positions > 0 then - return positions - end + parseValueCrossFile(callback, vm, source, lsp) end - positions[#positions+1] = { - locSource.start, - locSource.finish, - locSource:getUri(), - } + callback(locSource) if #positions == 0 then return nil end return positions end -local function parseValue(vm, source, lsp) - local positions = {} - local mark = {} - - local function callback(src) - if source == src then - return - end - if mark[src] then - return - end - mark[src] = true - if src.start == 0 then - return - end - local uri = src.uri - if uri == '' then - uri = nil - end - positions[#positions+1] = { - src.start, - src.finish, - uri, - } - end - +local function parseValue(callback, vm, source, lsp) if source:bindValue() then source:bindValue():eachInfo(function (info, src) if info.type == 'set' or info.type == 'local' or info.type == 'return' then @@ -165,56 +67,79 @@ local function parseValue(vm, source, lsp) end end) end - if #positions == 0 then - return nil - end - return positions end -local function parseLabel(vm, label, lsp) - local positions = {} +local function parseLabel(callback, vm, label, lsp) label:eachInfo(function (info, src) if info.type == 'set' then - positions[#positions+1] = { - src.start, - src.finish, - } + callback(src) end end) - if #positions == 0 then - return nil - end - return positions end -local function jumpUri(vm, source, lsp) +local function jumpUri(callback, vm, source, lsp) local uri = source:get 'target uri' - local positions = {} - positions[#positions+1] = { - 0, 0, uri, + callback { + start = 0, + finish = 0, + uri = uri } - return positions +end + +local function parseClass(callback, vm, source) + local className = source:get 'target class' + vm.emmyMgr:eachClass(className, function (class) + local src = class:getSource() + callback(src) + end) +end + +local function makeList(source) + local list = {} + local mark = {} + return list, function (src) + if source == src then + return + end + if mark[src] then + return + end + mark[src] = true + local uri = src.uri + if uri == '' then + uri = nil + end + list[#list+1] = { + src.start, + src.finish, + src.uri + } + end end return function (vm, source, lsp) if not source then return nil end + local list, callback = makeList(source) if source:bindLocal() then - return parseLocal(vm, source, lsp) - end - if source:bindValue() then - return parseValue(vm, source, lsp) - or parseValueSimily(vm, source, lsp) + parseLocal(callback, vm, source, lsp) + elseif source:bindValue() then + parseValue(callback, vm, source, lsp) + --parseValueSimily(callback, vm, source, lsp) end if source:bindLabel() then - return parseLabel(vm, source:bindLabel(), lsp) + parseLabel(callback, vm, source:bindLabel(), lsp) end if source:get 'target uri' then - return jumpUri(vm, source, lsp) + jumpUri(callback, vm, source, lsp) end if source:get 'in index' then - return parseValue(vm, source, lsp) - or parseValueSimily(vm, source, lsp) + parseValue(callback, vm, source, lsp) + --parseValueSimily(callback, vm, source, lsp) + end + if source:get 'target class' then + parseClass(callback, vm, source) end + return list end diff --git a/server/src/core/diagnostics.lua b/server/src/core/diagnostics.lua index d49f8da2..0732b7e3 100644 --- a/server/src/core/diagnostics.lua +++ b/server/src/core/diagnostics.lua @@ -439,10 +439,6 @@ function mt:checkEmmyClass(source, callback) local related = {} local current = class for _ = 1, 10 do - if parent:getName() == class:getName() then - callback(source.start, source.finish, lang.script.DIAG_CYCLIC_EXTENDS, related) - break - end local extends = current.extends if not extends then break @@ -452,20 +448,37 @@ function mt:checkEmmyClass(source, callback) finish = current:getSource().finish, uri = current:getSource().uri, } - current = parent - parent = self.vm.emmyMgr:eachClass(extends, function (parent) + current = self.vm.emmyMgr:eachClass(extends, function (parent) return parent end) - if not parent then + if not current then + break + end + if current:getName() == class:getName() then + callback(source.start, source.finish, lang.script.DIAG_CYCLIC_EXTENDS, related) break end end end +function mt:checkEmmyType(source, callback) + for _, tpsource in ipairs(source) do + local name = tpsource[1] + local class = self.vm.emmyMgr:eachClass(name, function (class) + return class + end) + if not class then + callback(tpsource.start, tpsource.finish, lang.script.DIAG_UNDEFINED_CLASS) + end + end +end + function mt:searchEmmyLua(callback) self.vm:eachSource(function (source) if source.type == 'emmyClass' then self:checkEmmyClass(source, callback) + elseif source.type == 'emmyType' then + self:checkEmmyType(source, callback) end end) end diff --git a/server/src/core/implementation.lua b/server/src/core/implementation.lua index 1b8006b1..450b9a0c 100644 --- a/server/src/core/implementation.lua +++ b/server/src/core/implementation.lua @@ -166,6 +166,20 @@ local function jumpUri(vm, source, lsp) return positions end +local function parseClass(vm, source) + local className = source:get 'target class' + local positions = {} + vm.emmyMgr:eachClass(className, function (class) + local src = class:getSource() + positions[#positions+1] = { + src.start, + src.finish, + src.uri, + } + end) + return positions +end + return function (vm, source, lsp) if not source then return nil @@ -180,4 +194,11 @@ return function (vm, source, lsp) if source:get 'target uri' then return jumpUri(vm, source, lsp) end + if source:get 'in index' then + return parseValue(vm, source, lsp) + or parseValueSimily(vm, source, lsp) + end + if source:get 'target class' then + return parseClass(vm, source) + end end diff --git a/server/src/emmy/class.lua b/server/src/emmy/class.lua index f1101e91..5e87181d 100644 --- a/server/src/emmy/class.lua +++ b/server/src/emmy/class.lua @@ -16,11 +16,20 @@ function mt:getSource() return listMgr.get(self.source) end -return function (source) +function mt:setValue(value) + self.value = value +end + +function mt:getValue() + return self.value +end + +return function (manager, source) local self = setmetatable({ name = source[1][1], source = source.id, extends = source[2] and source[2][1], + _manager = manager, }, mt) return self end diff --git a/server/src/emmy/manager.lua b/server/src/emmy/manager.lua index 99b46420..a3de42df 100644 --- a/server/src/emmy/manager.lua +++ b/server/src/emmy/manager.lua @@ -1,5 +1,6 @@ local listMgr = require 'vm.list' local newClass = require 'emmy.class' +local newType = require 'emmy.type' local mt = {} mt.__index = mt @@ -26,7 +27,7 @@ function mt:flushClass(name) list.version = version end -function mt:eachClass(name, callback) +function mt:eachClassByName(name, callback) self:flushClass(name) local list = self._class[name] if not list then @@ -42,6 +43,22 @@ function mt:eachClass(name, callback) end end +function mt:eachClass(...) + local n = select('#', ...) + if n == 1 then + local callback = ... + for name in pairs(self._class) do + local res = self:eachClassByName(name, callback) + if res ~= nil then + return res + end + end + else + local name, callback = ... + return self:eachClassByName(name, callback) + end +end + function mt:addClass(source) local className = source[1][1] self:flushClass(className) @@ -53,14 +70,19 @@ function mt:addClass(source) } self._class[className] = list end - list[source.id] = newClass(source) + list[source.id] = newClass(self, source) return list[source.id] end +function mt:createType(source) + return newType(self, source) +end + function mt:remove() end return function () + ---@class emmyMgr local self = setmetatable({ _class = {}, }, mt) diff --git a/server/src/emmy/type.lua b/server/src/emmy/type.lua new file mode 100644 index 00000000..c2195810 --- /dev/null +++ b/server/src/emmy/type.lua @@ -0,0 +1,41 @@ +local listMgr = require 'vm.list' + +local function buildName(source) + local names = {} + for i, type in ipairs(source) do + names[i] = type[1] + end + return table.concat(names, '|') +end + +local mt = {} +mt.__index = mt +mt.type = 'emmy.type' + +function mt:getType() + return self.name +end + +function mt:getName() + return self.name +end + +function mt:getSource() + return listMgr.get(self.source) +end + +function mt:getClass() + local class = self._manager:eachClass(self.name, function (class) + return class + end) + return class +end + +return function (manager, source) + local self = setmetatable({ + name = buildName(source), + source = source.id, + _manager = manager, + }, mt) + return self +end diff --git a/server/src/method/textDocument/completion.lua b/server/src/method/textDocument/completion.lua index 7f60708b..1b9aa73f 100644 --- a/server/src/method/textDocument/completion.lua +++ b/server/src/method/textDocument/completion.lua @@ -16,70 +16,27 @@ local function posToRange(lines, start, finish) } end -local function findStartPos(pos, buf) - local res = nil - for i = pos, 1, -1 do - local c = buf:sub(i, i) - if c:find '[%w_]' then - res = i - else - break - end - end - if not res then - for i = pos, 1, -1 do - local c = buf:sub(i, i) - if c == '.' or c == ':' then - res = i - elseif c:find '[%s%c]' then - else - break - end - end - end - if not res then - return pos - end - return res -end - -local function findWord(position, text) - local word = text - for i = position, 1, -1 do - local c = text:sub(i, i) - if not c:find '[%w_]' then - word = text:sub(i+1, position) - break - end - end - return word:match('^([%w_]*)') -end - local function fastCompletion(lsp, params, lines) local uri = params.textDocument.uri local text, oldText = lsp:getText(uri) -- lua是从1开始的,因此都要+1 local position = lines:positionAsChar(params.position.line + 1, params.position.character) - local word = findWord(position, text) - local startPos = findStartPos(position, text) local vm = lsp:getVM(uri) - if not vm or not startPos then + if not vm then vm = lsp:loadVM(uri) if not vm then return nil end end - startPos = startPos or position - local items = core.completion(vm, text, startPos, word, oldText) + local items = core.completion(vm, text, position, oldText) if not items or #items == 0 then vm = lsp:loadVM(uri) if not vm then return nil end - startPos = startPos or position - items = core.completion(vm, text, startPos, word) + items = core.completion(vm, text, position) if not items or #items == 0 then return nil end @@ -93,16 +50,13 @@ local function finishCompletion(lsp, params, lines) local text = lsp:getText(uri) -- lua是从1开始的,因此都要+1 local position = lines:positionAsChar(params.position.line + 1, params.position.character) - local word = findWord(position, text) - local startPos = findStartPos(position, text) local vm = lsp:loadVM(uri) if not vm then return nil end - startPos = startPos or position - local items = core.completion(vm, text, startPos, word) + local items = core.completion(vm, text, position) if not items or #items == 0 then return nil end diff --git a/server/src/method/textDocument/publishDiagnostics.lua b/server/src/method/textDocument/publishDiagnostics.lua index fbe65bb3..3a4e4658 100644 --- a/server/src/method/textDocument/publishDiagnostics.lua +++ b/server/src/method/textDocument/publishDiagnostics.lua @@ -43,7 +43,7 @@ local function getRange(start, finish, lines) } end -local function createInfo(data, lines) +local function createInfo(lsp, data, lines) local diagnostic = { source = lang.script.DIAG_DIAGNOSTICS, range = getRange(data.start, data.finish, lines), @@ -54,6 +54,7 @@ local function createInfo(data, lines) if data.related then local related = {} for i, info in ipairs(data.related) do + local _, lines = lsp:getVM(info.uri) local message = info.message if not message then local start_line = lines:rowcol(info.start) @@ -144,7 +145,7 @@ return function (lsp, params) if vm then local datas = core.diagnostics(vm, lines, uri) for _, data in ipairs(datas) do - diagnostics[#diagnostics+1] = createInfo(data, lines) + diagnostics[#diagnostics+1] = createInfo(lsp, data, lines) end end if errs then diff --git a/server/src/vm/emmy.lua b/server/src/vm/emmy.lua index 6e5c2b13..22f72ae6 100644 --- a/server/src/vm/emmy.lua +++ b/server/src/vm/emmy.lua @@ -1,15 +1,66 @@ local mt = require 'vm.manager' +function mt:clearEmmy() + self._emmy = nil +end + +function mt:doEmmy(action) + local tp = action.type + if tp == 'emmyClass' then + self:doEmmyClass(action) + elseif tp == 'emmyType' then + self:doEmmyType(action) + elseif tp == 'emmyAlias' then + elseif tp == 'emmyParam' then + elseif tp == 'emmyReturn' then + elseif tp == 'emmyField' then + elseif tp == 'emmyGeneric' then + elseif tp == 'emmyVararg' then + elseif tp == 'emmyLanguage' then + elseif tp == 'emmyArrayType' then + elseif tp == 'emmyTableType' then + elseif tp == 'emmyFunctionType' then + elseif tp == 'emmySee' then + elseif tp == 'emmyIncomplete' then + self:doEmmyIncomplete(action) + end +end + +function mt:getEmmy() + local emmy = self._emmy + self._emmy = nil + return emmy +end + function mt:doEmmyClass(action) local emmyMgr = self.emmyMgr self:instantSource(action) local class = emmyMgr:addClass(action) - self.emmy = class + local extends = action[2] + if extends then + self:instantSource(extends) + extends:set('target class', extends[1]) + end + self._emmy = class action:set('emmy.class', class) + if self.lsp then + self.lsp.global:markSet(self:getUri()) + end end function mt:doEmmyType(action) local emmyMgr = self.emmyMgr + self:instantSource(action) + local type = emmyMgr:createType(action) + self._emmy = type + action:set('emmy.type', type) + for _, obj in ipairs(action) do + self:instantSource(obj) + obj:set('target class', obj[1]) + end + if self.lsp then + self.lsp.global:markGet(self:getUri()) + end end function mt:doEmmyIncomplete(action) diff --git a/server/src/vm/local.lua b/server/src/vm/local.lua index e75ed149..618214ff 100644 --- a/server/src/vm/local.lua +++ b/server/src/vm/local.lua @@ -111,6 +111,13 @@ function mt:shadow(old) end group[#group+1] = self self._shadow = group + + if not self:getSource() then + log.debug('not self:getSource()', table.dump(self)) + end + if not old.close then + log.debug('not old.close', table.dump(old)) + end old:close(self:getSource().start - 1) end @@ -136,7 +143,6 @@ function mt:setEmmy(emmy) if emmy.type ~= 'emmy.class' and emmy.type ~= 'emmy.type' then return end - self._emmy = emmy if self.value then self.value:setEmmy(emmy) end diff --git a/server/src/vm/value.lua b/server/src/vm/value.lua index 76b173a9..783bfc4e 100644 --- a/server/src/vm/value.lua +++ b/server/src/vm/value.lua @@ -528,7 +528,14 @@ function mt:setEmmy(emmy) if not emmy then return end - if emmy.type ~= 'emmy.class' and emmy.type ~= 'emmy.type' then + if emmy.type == 'emmy.class' then + emmy:setValue(self) + elseif emmy.type == 'emmy.type' then + local class = emmy:getClass() + if class then + self:mergeValue(class:getValue()) + end + else return end self._emmy = emmy diff --git a/server/src/vm/vm.lua b/server/src/vm/vm.lua index 57301ed5..7f5250eb 100644 --- a/server/src/vm/vm.lua +++ b/server/src/vm/vm.lua @@ -41,12 +41,14 @@ function mt:buildTable(source) end local n = 0 for index, obj in ipairs(source) do + local emmy = self:getEmmy() if obj.type == 'pair' then local value = self:getFirstInMulti(self:getExp(obj[2])) local key = obj[1] self:instantSource(obj) self:instantSource(key) key:bindValue(value, 'set') + value:setEmmy(emmy) if key.type == 'index' then local index = self:getIndex(key) key:set('parent', tbl) @@ -58,6 +60,8 @@ function mt:buildTable(source) tbl:setChild(key[1], value, key) end end + elseif obj.type:sub(1, 4) == 'emmy' then + self:doEmmy(obj) else local value = self:getExp(obj) if value.type == 'multi' then @@ -778,10 +782,11 @@ function mt:doGoTo(source) end end -function mt:setOne(var, value) +function mt:setOne(var, value, emmy) if not value then value = valueMgr.create('nil', self:getDefaultSource()) end + value:setEmmy(emmy) self:instantSource(var) if var.type == 'name' then self:setName(var[1], var, value) @@ -805,6 +810,7 @@ function mt:setOne(var, value) end function mt:doSet(action) + local emmy = self:getEmmy() if not action[2] then return end @@ -824,11 +830,12 @@ function mt:doSet(action) local i = 0 self:forList(vars, function (var) i = i + 1 - self:setOne(var, values[i]) + self:setOne(var, values[i], emmy) end) end function mt:doLocal(action) + local emmy = self:getEmmy() self:instantSource(action) local vars = action[1] local exps = action[2] @@ -851,9 +858,8 @@ function mt:doLocal(action) if values then value = values[i] end - self:createLocal(key[1], key, value) + self:createLocal(key[1], key, value, emmy) end) - self.emmy = nil end function mt:doIf(action) @@ -1010,6 +1016,10 @@ function mt:doAction(action) end end local tp = action.type + if tp:sub(1, 4) == 'emmy' then + self:doEmmy(action) + return + end if tp == 'do' then self:doDo(action) elseif tp == 'break' then @@ -1041,27 +1051,11 @@ function mt:doAction(action) self:doFunction(action) elseif tp == 'localfunction' then self:doLocalFunction(action) - elseif tp == 'emmyClass' then - --self:doEmmyClass(action) - elseif tp == 'emmyType' then - --self:doEmmyType(action) - elseif tp == 'emmyAlias' then - elseif tp == 'emmyParam' then - elseif tp == 'emmyReturn' then - elseif tp == 'emmyField' then - elseif tp == 'emmyGeneric' then - elseif tp == 'emmyVararg' then - elseif tp == 'emmyLanguage' then - elseif tp == 'emmyArrayType' then - elseif tp == 'emmyTableType' then - elseif tp == 'emmyFunctionType' then - elseif tp == 'emmySee' then - elseif tp == 'emmyIncomplete' then - self:doEmmyIncomplete(action) else self:getExp(action) action:set('as action', true) end + self:clearEmmy() end function mt:doActions(actions) @@ -1163,20 +1157,20 @@ function mt:bindLabel(source, label, action) end end -function mt:createLocal(key, source, value) +function mt:createLocal(key, source, value, emmy) local loc = self:bindLocal(source) if not value then value = self:createValue('nil', source) end if loc then loc:setValue(value) - loc:setEmmy(self.emmy) + loc:setEmmy(emmy) self:saveLocal(key, loc) return loc end loc = localMgr.create(key, source, value) - loc:setEmmy(self.emmy) + loc:setEmmy(emmy) self:saveLocal(key, loc) self:bindLocal(source, loc, 'local') value:addInfo('local', source) @@ -1283,6 +1277,7 @@ return function (ast, lsp, uri) main = nil, env = nil, emmy = nil, + ---@type emmyMgr emmyMgr = lsp and lsp.emmy or emmyMgr(), lsp = lsp, uri = uri or '', diff --git a/server/test/completion/init.lua b/server/test/completion/init.lua index 6dc998c7..560f6fa4 100644 --- a/server/test/completion/init.lua +++ b/server/test/completion/init.lua @@ -58,57 +58,16 @@ local function eq(a, b) return a == b end -local function findStartPos(pos, buf) - local res = nil - for i = pos, 1, -1 do - local c = buf:sub(i, i) - if c:find '[%w_]' then - res = i - else - break - end - end - if not res then - for i = pos, 1, -1 do - local c = buf:sub(i, i) - if c == '.' or c == ':' then - res = i - elseif c:find '[%s%c]' then - else - break - end - end - end - if not res then - return pos - end - return res -end - -local function findWord(position, text) - local word = text - for i = position, 1, -1 do - local c = text:sub(i, i) - if not c:find '[%w_]' then - word = text:sub(i+1, position) - break - end - end - return word:match('^([%w_]*)') -end - rawset(_G, 'TEST', true) function TEST(script) return function (expect) local pos = script:find('$', 1, true) - 1 - local new_script = script:gsub('%$', ' ') + local new_script = script:gsub('%$', '') local ast = parser:ast(new_script, 'lua', 'Lua 5.4') local vm = buildVM(ast) assert(vm) - local word = findWord(pos, new_script) - local startPos = findStartPos(pos, new_script) - local result = core.completion(vm, new_script, startPos, word) + local result = core.completion(vm, new_script, pos) if expect then assert(result) assert(eq(expect, result)) @@ -414,7 +373,7 @@ collectgarbage('$') documentation = EXISTS, textEdit = { start = 16, - finish = 18, + finish = 17, newText = '"collect"', }, }, @@ -424,7 +383,7 @@ collectgarbage('$') documentation = EXISTS, textEdit = { start = 16, - finish = 18, + finish = 17, newText = '"stop"', }, }, @@ -434,7 +393,7 @@ collectgarbage('$') documentation = EXISTS, textEdit = { start = 16, - finish = 18, + finish = 17, newText = '"restart"', }, }, @@ -444,7 +403,7 @@ collectgarbage('$') documentation = EXISTS, textEdit = { start = 16, - finish = 18, + finish = 17, newText = '"count"', }, }, @@ -454,7 +413,7 @@ collectgarbage('$') documentation = EXISTS, textEdit = { start = 16, - finish = 18, + finish = 17, newText = '"step"', }, }, @@ -464,7 +423,7 @@ collectgarbage('$') documentation = EXISTS, textEdit = { start = 16, - finish = 18, + finish = 17, newText = '"setpause"', }, }, @@ -474,7 +433,7 @@ collectgarbage('$') documentation = EXISTS, textEdit = { start = 16, - finish = 18, + finish = 17, newText = '"setstepmul"', }, }, @@ -484,7 +443,7 @@ collectgarbage('$') documentation = EXISTS, textEdit = { start = 16, - finish = 18, + finish = 17, newText = '"isrunning"', }, }, @@ -536,7 +495,7 @@ self.results.list[#$] kind = CompletionItemKind.Snippet, textEdit = { start = 20, - finish = 21, + finish = 20, newText = 'self.results.list+1] = ', }, }, @@ -551,7 +510,7 @@ self.results.list[#self.re$] kind = CompletionItemKind.Snippet, textEdit = { start = 20, - finish = 28, + finish = 27, newText = 'self.results.list+1] = ', }, }, @@ -570,7 +529,7 @@ fff[#ff$] kind = CompletionItemKind.Snippet, textEdit = { start = 6, - finish = 9, + finish = 8, newText = 'fff+1] = ', }, }, @@ -589,7 +548,7 @@ local _ = fff.kkk[#$] kind = CompletionItemKind.Snippet, textEdit = { start = 20, - finish = 21, + finish = 20, newText = 'fff.kkk]', }, }, @@ -736,25 +695,25 @@ end (nil) require 'config' .config.runtime.version = 'Lua 5.4' -TEST [[ -local *$ -]] -{ - { - label = 'toclose', - kind = CompletionItemKind.Keyword, - } -} - -TEST [[ -local *tocl$ -]] -{ - { - label = 'toclose', - kind = CompletionItemKind.Keyword, - } -} +--TEST [[ +--local *$ +--]] +--{ +-- { +-- label = 'toclose', +-- kind = CompletionItemKind.Keyword, +-- } +--} + +--TEST [[ +--local *tocl$ +--]] +--{ +-- { +-- label = 'toclose', +-- kind = CompletionItemKind.Keyword, +-- } +--} TEST [[ local mt = {} @@ -810,3 +769,18 @@ TEST [[ kind = CompletionItemKind.Keyword } } + +TEST [[ +---@class ABC +---@class BBC : $ +]] +{ + { + label = 'ABC', + kind = CompletionItemKind.Class, + }, + { + label = 'BBC', + kind = CompletionItemKind.Class, + }, +} diff --git a/server/test/crossfile/completion.lua b/server/test/crossfile/completion.lua index c982607b..cc31ed5d 100644 --- a/server/test/crossfile/completion.lua +++ b/server/test/crossfile/completion.lua @@ -61,31 +61,6 @@ local function eq(a, b) return a == b end -local function findStartPos(pos, buf) - local res = nil - for i = pos-1, 1, -1 do - local c = buf:sub(i, i) - if c:find '%a' then - res = i - else - break - end - end - return res -end - -local function findWord(position, text) - local word = text - for i = position-1, 1, -1 do - local c = text:sub(i, i) - if not c:find '[%w_]' then - word = text:sub(i+1, position) - break - end - end - return word:match('^([%w_]*)') -end - function TEST(data) local lsp = service() local ws = workspace(lsp, 'test') @@ -99,7 +74,7 @@ function TEST(data) local uri = ws:uriEncode(fs.path(info.path)) local script = info.content if info.main then - pos = script:find('$', 1, true) + pos = script:find('$', 1, true) - 1 script = script:gsub('%$', '') mainUri = uri mainBuf = script @@ -114,9 +89,7 @@ function TEST(data) local vm = lsp:loadVM(mainUri) assert(vm) - local word = findWord(pos, mainBuf) - local startPos = findStartPos(pos, mainBuf) or pos - local result = core.completion(vm, mainBuf, startPos, word) + local result = core.completion(vm, mainBuf, pos) local expect = data.completion if expect then assert(result) diff --git a/server/test/definition/bug.lua b/server/test/definition/bug.lua index 1d3ab02c..ee414ef6 100644 --- a/server/test/definition/bug.lua +++ b/server/test/definition/bug.lua @@ -86,5 +86,5 @@ return f(), <?b?> TEST [[ local a = os.clock() -local <?<!b!>?> = os.clock() +local <?b?> = os.clock() ]] diff --git a/server/test/definition/emmy.lua b/server/test/definition/emmy.lua new file mode 100644 index 00000000..a98f334f --- /dev/null +++ b/server/test/definition/emmy.lua @@ -0,0 +1,31 @@ +TEST [[ +---@class <!A!> +---@class B : <?A?> +]] + +TEST [[ +---@class <!A!> +---@type B|<?A?> +]] + +TEST [[ +---@class A +local mt = {} +function mt:<!cast!>() +end + +---@type A +local obj +obj:<?cast?>() +]] + +--TEST [[ +-----@class A +--local <!mt!> = {} +--function mt:cast() +--end +-- +-----@type A +--local obj +--<?obj?>:cast() +--]] diff --git a/server/test/definition/init.lua b/server/test/definition/init.lua index e095e474..d699744a 100644 --- a/server/test/definition/init.lua +++ b/server/test/definition/init.lua @@ -62,3 +62,4 @@ require 'definition.table' require 'definition.method' require 'definition.label' require 'definition.bug' +require 'definition.emmy' diff --git a/server/test/definition/method.lua b/server/test/definition/method.lua index 40c5f127..ad9fea08 100644 --- a/server/test/definition/method.lua +++ b/server/test/definition/method.lua @@ -69,37 +69,37 @@ setmetatable(api, { __index = mt }) api:<?method1?>() ]] -TEST [[ -local mt -function mt:x() - self.<?init?>() -end - -local obj = setmetatable({}, { __index = mt }) -obj.<!init!> = 1 -]] - -TEST [[ -local mt -function mt:x() - self.<?init?>() -end - -local obj = setmetatable({ <!init!> = 1 }, { __index = mt }) -]] - -TEST [[ -local mt -function mt:x() - self.a.<?out?>() -end - -local obj = setmetatable({ - a = { - <!out!> = 1, - } -}, { __index = mt }) -]] +--TEST [[ +--local mt +--function mt:x() +-- self.<?init?>() +--end +-- +--local obj = setmetatable({}, { __index = mt }) +--obj.<!init!> = 1 +--]] +-- +--TEST [[ +--local mt +--function mt:x() +-- self.<?init?>() +--end +-- +--local obj = setmetatable({ <!init!> = 1 }, { __index = mt }) +--]] +-- +--TEST [[ +--local mt +--function mt:x() +-- self.a.<?out?>() +--end +-- +--local obj = setmetatable({ +-- a = { +-- <!out!> = 1, +-- } +--}, { __index = mt }) +--]] TEST [[ local sm = setmetatable diff --git a/server/test/definition/table.lua b/server/test/definition/table.lua index 1b6d011e..90e7926f 100644 --- a/server/test/definition/table.lua +++ b/server/test/definition/table.lua @@ -96,19 +96,19 @@ local t = { t.<?insert?>() ]] -TEST[[ -local t = { - <!insert!> = 1, -} -y.<?insert?>() -]] - -TEST[[ -local t = { - <!insert!> = 1, -} -local y = { - insert = 1, -} -t.<?insert?>() -]] +--TEST[[ +--local t = { +-- <!insert!> = 1, +--} +--y.<?insert?>() +--]] + +--TEST[[ +--local t = { +-- <!insert!> = 1, +--} +--local y = { +-- insert = 1, +--} +--t.<?insert?>() +--]] diff --git a/server/test/diagnostics/init.lua b/server/test/diagnostics/init.lua index 7a092803..4b762122 100644 --- a/server/test/diagnostics/init.lua +++ b/server/test/diagnostics/init.lua @@ -334,25 +334,34 @@ local function x() end ]] ---TEST [[ ------@class <!Class!> ------@class <!Class!> ---]] --- ---TEST [[ ------@class A : <!B!> ---]] --- ---TEST [[ ------@class <!A : B!> ------@class <!B : C!> ------@class <!C : D!> ------@class <!D : A!> ---]] --- ---TEST [[ ------@class A : B ------@class B : C ------@class C : D ------@class D ---]] +TEST [[ +---@class <!Class!> +---@class <!Class!> +]] + +TEST [[ +---@class A : <!B!> +]] + +TEST [[ +---@class <!A : B!> +---@class <!B : C!> +---@class <!C : D!> +---@class <!D : A!> +]] + +TEST [[ +---@class A : B +---@class B : C +---@class C : D +---@class D +]] + +TEST [[ +---@type <!A!> +]] + +TEST [[ +---@class A +---@type A|<!B!>|<!C!> +]] diff --git a/server/test/hover/init.lua b/server/test/hover/init.lua index fbbbeb82..bdd26932 100644 --- a/server/test/hover/init.lua +++ b/server/test/hover/init.lua @@ -465,10 +465,62 @@ function n<next>(table: table [, index: any]) -> key: any, value: any ]] ---TEST[[ ------@class Class ---local <?x?> = class() ---]] ---[[ ---local x: *Class ---]] +TEST[[ +---@class Class +local <?x?> = class() +]] +[[ +local x: *Class +]] + +TEST[[ +---@class Class +<?x?> = class() +]] +[[ +global x: *Class +]] + +TEST[[ +local t = { + ---@class Class + <?x?> = class() +} +]] +[[ +field x: *Class +]] + +TEST[[ +---@type Class +local <?x?> = class() +]] +[[ +local x: *Class +]] + +TEST[[ +---@type Class +<?x?> = class() +]] +[[ +global x: *Class +]] + +TEST[[ +local t = { + ---@type Class + <?x?> = class() +} +]] +[[ +field x: *Class +]] + +TEST[[ +---@type A|B|C +local <?x?> = class() +]] +[[ +local x: *A|B|C +]] |