Skip to content

Commit be5b77b

Browse files
committed
supports ---@enum (key)
1 parent b53c18f commit be5b77b

File tree

11 files changed

+271
-38
lines changed

11 files changed

+271
-38
lines changed

changelog.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,24 @@
44
* `NEW` support `---@type` and `--[[@as]]` for return statement
55
* `NEW` commandline parameter `--force-accept-workspace`: allowing the use of the root directory or home directory as the workspace
66
* `NEW` diagnostic: `inject-field`
7+
* `NEW` `---@enum` supports attribute `key`
8+
```lua
9+
---@enum (key) AnimalType
10+
local enum = {
11+
Cat = 1,
12+
Dog = 2,
13+
}
14+
15+
---@param animal userdata
16+
---@param atp AnimalType
17+
---@return boolean
18+
local function isAnimalType(animal, atp)
19+
return API.isAnimalType(animal, enum[atp])
20+
end
21+
22+
assert(isAnimalType(animal, 'Cat'))
23+
```
24+
725
* `FIX` wrong hover and signature for method with varargs and overloads
826
* `FIX` [#2155]
927
* `FIX` [#2224]

script/core/completion/completion.lua

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1251,6 +1251,46 @@ local function insertDocEnum(state, pos, doc, enums)
12511251
return enums
12521252
end
12531253

1254+
---@param state parser.state
1255+
---@param pos integer
1256+
---@param doc vm.node.object
1257+
---@param enums table[]
1258+
---@return table[]?
1259+
local function insertDocEnumKey(state, pos, doc, enums)
1260+
local tbl = doc.bindSource
1261+
if not tbl then
1262+
return nil
1263+
end
1264+
local keyEnums = {}
1265+
for _, field in ipairs(tbl) do
1266+
if field.type == 'tablefield'
1267+
or field.type == 'tableindex' then
1268+
if not field.value then
1269+
goto CONTINUE
1270+
end
1271+
local key = guide.getKeyName(field)
1272+
if not key then
1273+
goto CONTINUE
1274+
end
1275+
enums[#enums+1] = {
1276+
label = ('%q'):format(key),
1277+
kind = define.CompletionItemKind.EnumMember,
1278+
id = stack(field, function (newField) ---@async
1279+
return {
1280+
detail = buildDetail(newField),
1281+
description = buildDesc(newField),
1282+
}
1283+
end),
1284+
}
1285+
::CONTINUE::
1286+
end
1287+
end
1288+
for _, enum in ipairs(keyEnums) do
1289+
enums[#enums+1] = enum
1290+
end
1291+
return enums
1292+
end
1293+
12541294
local function buildInsertDocFunction(doc)
12551295
local args = {}
12561296
for i, arg in ipairs(doc.args) do
@@ -1316,7 +1356,11 @@ local function insertEnum(state, pos, src, enums, isInArray, mark)
13161356
elseif src.type == 'global' and src.cate == 'type' then
13171357
for _, set in ipairs(src:getSets(state.uri)) do
13181358
if set.type == 'doc.enum' then
1319-
insertDocEnum(state, pos, set, enums)
1359+
if vm.docHasAttr(set, 'key') then
1360+
insertDocEnumKey(state, pos, set, enums)
1361+
else
1362+
insertDocEnum(state, pos, set, enums)
1363+
end
13201364
end
13211365
end
13221366
end

script/core/hover/description.lua

Lines changed: 44 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -477,34 +477,55 @@ local function tryDocEnum(source)
477477
if not tbl then
478478
return
479479
end
480-
local md = markdown()
481-
md:add('lua', '{')
482-
for _, field in ipairs(tbl) do
483-
if field.type == 'tablefield'
484-
or field.type == 'tableindex' then
485-
if not field.value then
486-
goto CONTINUE
487-
end
488-
local key = guide.getKeyName(field)
489-
if not key then
490-
goto CONTINUE
491-
end
492-
if field.value.type == 'integer'
493-
or field.value.type == 'string' then
494-
md:add('lua', (' %s: %s = %s,'):format(key, field.value.type, field.value[1]))
480+
if vm.docHasAttr(source, 'key') then
481+
local md = markdown()
482+
local keys = {}
483+
for _, field in ipairs(tbl) do
484+
if field.type == 'tablefield'
485+
or field.type == 'tableindex' then
486+
if not field.value then
487+
goto CONTINUE
488+
end
489+
local key = guide.getKeyName(field)
490+
if not key then
491+
goto CONTINUE
492+
end
493+
keys[#keys+1] = ('%q'):format(key)
494+
::CONTINUE::
495495
end
496-
if field.value.type == 'binary'
497-
or field.value.type == 'unary' then
498-
local number = vm.getNumber(field.value)
499-
if number then
500-
md:add('lua', (' %s: %s = %s,'):format(key, math.tointeger(number) and 'integer' or 'number', number))
496+
end
497+
md:add('lua', table.concat(keys, ' | '))
498+
return md:string()
499+
else
500+
local md = markdown()
501+
md:add('lua', '{')
502+
for _, field in ipairs(tbl) do
503+
if field.type == 'tablefield'
504+
or field.type == 'tableindex' then
505+
if not field.value then
506+
goto CONTINUE
507+
end
508+
local key = guide.getKeyName(field)
509+
if not key then
510+
goto CONTINUE
511+
end
512+
if field.value.type == 'integer'
513+
or field.value.type == 'string' then
514+
md:add('lua', (' %s: %s = %s,'):format(key, field.value.type, field.value[1]))
515+
end
516+
if field.value.type == 'binary'
517+
or field.value.type == 'unary' then
518+
local number = vm.getNumber(field.value)
519+
if number then
520+
md:add('lua', (' %s: %s = %s,'):format(key, math.tointeger(number) and 'integer' or 'number', number))
521+
end
501522
end
523+
::CONTINUE::
502524
end
503-
::CONTINUE::
504525
end
526+
md:add('lua', '}')
527+
return md:string()
505528
end
506-
md:add('lua', '}')
507-
return md:string()
508529
end
509530

510531
---@async

script/core/semantic-tokens.lua

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -711,6 +711,14 @@ local Care = util.switch()
711711
type = define.TokenTypes.namespace,
712712
}
713713
end)
714+
: case 'doc.attr'
715+
: call(function (source, options, results)
716+
results[#results+1] = {
717+
start = source.start,
718+
finish = source.finish,
719+
type = define.TokenTypes.decorator,
720+
}
721+
end)
714722

715723
---@param state table
716724
---@param results table

script/parser/guide.lua

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ local childMap = {
159159
['doc.class'] = {'class', '#extends', '#signs', 'comment'},
160160
['doc.type'] = {'#types', 'name', 'comment'},
161161
['doc.alias'] = {'alias', 'extends', 'comment'},
162-
['doc.enum'] = {'enum', 'extends', 'comment'},
162+
['doc.enum'] = {'enum', 'extends', 'comment', 'docAttr'},
163163
['doc.param'] = {'param', 'extends', 'comment'},
164164
['doc.return'] = {'#returns', 'comment'},
165165
['doc.field'] = {'field', 'extends', 'comment'},
@@ -182,6 +182,7 @@ local childMap = {
182182
['doc.cast.block'] = {'extends'},
183183
['doc.operator'] = {'op', 'exp', 'extends'},
184184
['doc.meta'] = {'name'},
185+
['doc.attr'] = {'#names'},
185186
}
186187

187188
---@type table<string, fun(obj: parser.object, list: parser.object[])>

script/parser/luadoc.lua

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ Symbol <- ({} {
156156
---@field calls? parser.object[]
157157
---@field generics? parser.object[]
158158
---@field generic? parser.object
159+
---@field docAttr? parser.object
159160

160161
local function parseTokens(text, offset)
161162
Ci = 0
@@ -252,6 +253,40 @@ local function nextSymbolOrError(symbol)
252253
return false
253254
end
254255

256+
local function parseDocAttr(parent)
257+
if not checkToken('symbol', '(', 1) then
258+
return nil
259+
end
260+
nextToken()
261+
262+
local attrs = {
263+
type = 'doc.attr',
264+
parent = parent,
265+
start = getStart(),
266+
finish = getStart(),
267+
names = {},
268+
}
269+
270+
while true do
271+
if checkToken('symbol', ',', 1) then
272+
nextToken()
273+
goto continue
274+
end
275+
local name = parseName('doc.attr.name', attrs)
276+
if not name then
277+
break
278+
end
279+
attrs.names[#attrs.names+1] = name
280+
attrs.finish = name.finish
281+
::continue::
282+
end
283+
284+
nextSymbolOrError(')')
285+
attrs.finish = getFinish()
286+
287+
return attrs
288+
end
289+
255290
local function parseIndexField(parent)
256291
if not checkToken('symbol', '[', 1) then
257292
return nil
@@ -1428,17 +1463,22 @@ local docSwitch = util.switch()
14281463
end)
14291464
: case 'enum'
14301465
: call(function ()
1466+
local attr = parseDocAttr()
14311467
local name = parseName('doc.enum.name')
14321468
if not name then
14331469
return nil
14341470
end
14351471
local result = {
1436-
type = 'doc.enum',
1437-
start = name.start,
1438-
finish = name.finish,
1439-
enum = name,
1472+
type = 'doc.enum',
1473+
start = name.start,
1474+
finish = name.finish,
1475+
enum = name,
1476+
docAttr = attr,
14401477
}
14411478
name.parent = result
1479+
if attr then
1480+
attr.parent = result
1481+
end
14421482
return result
14431483
end)
14441484
: case 'private'

script/vm/doc.lua

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -471,3 +471,18 @@ function vm.getCastTargetHead(doc)
471471
end
472472
return nil
473473
end
474+
475+
---@param doc parser.object
476+
---@param key string
477+
---@return boolean
478+
function vm.docHasAttr(doc, key)
479+
if not doc.docAttr then
480+
return false
481+
end
482+
for _, name in ipairs(doc.docAttr.names) do
483+
if name[1] == key then
484+
return true
485+
end
486+
end
487+
return false
488+
end

script/vm/global.lua

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -372,16 +372,36 @@ local compilerGlobalSwitch = util.switch()
372372
return
373373
end
374374
source._enums = {}
375-
for _, field in ipairs(tbl) do
376-
if field.type == 'tablefield' then
377-
source._enums[#source._enums+1] = field
378-
local subType = vm.declareGlobal('type', name .. '.' .. field.field[1], uri)
379-
subType:addSet(uri, field)
380-
elseif field.type == 'tableindex' then
381-
source._enums[#source._enums+1] = field
382-
if field.index.type == 'string' then
383-
local subType = vm.declareGlobal('type', name .. '.' .. field.index[1], uri)
375+
if vm.docHasAttr(source, 'key') then
376+
for _, field in ipairs(tbl) do
377+
if field.type == 'tablefield' then
378+
source._enums[#source._enums+1] = {
379+
type = 'doc.type.string',
380+
start = field.field.start,
381+
finish = field.field.finish,
382+
[1] = field.field[1],
383+
}
384+
elseif field.type == 'tableindex' then
385+
source._enums[#source._enums+1] = {
386+
type = 'doc.type.string',
387+
start = field.index.start,
388+
finish = field.index.finish,
389+
[1] = field.index[1],
390+
}
391+
end
392+
end
393+
else
394+
for _, field in ipairs(tbl) do
395+
if field.type == 'tablefield' then
396+
source._enums[#source._enums+1] = field
397+
local subType = vm.declareGlobal('type', name .. '.' .. field.field[1], uri)
384398
subType:addSet(uri, field)
399+
elseif field.type == 'tableindex' then
400+
source._enums[#source._enums+1] = field
401+
if field.index.type == 'string' then
402+
local subType = vm.declareGlobal('type', name .. '.' .. field.index[1], uri)
403+
subType:addSet(uri, field)
404+
end
385405
end
386406
end
387407
end

test/completion/common.lua

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3815,6 +3815,32 @@ f(<??>)
38153815
},
38163816
}
38173817

3818+
TEST [[
3819+
local x = 1
3820+
local y = 2
3821+
3822+
---@enum(key) Enum
3823+
local t = {
3824+
x = x,
3825+
y = y,
3826+
}
3827+
3828+
---@param p Enum
3829+
local function f(p) end
3830+
3831+
f(<??>)
3832+
]]
3833+
{
3834+
{
3835+
label = '"x"',
3836+
kind = define.CompletionItemKind.EnumMember,
3837+
},
3838+
{
3839+
label = '"y"',
3840+
kind = define.CompletionItemKind.EnumMember,
3841+
},
3842+
}
3843+
38183844
TEST [[
38193845
--
38203846
<??>

0 commit comments

Comments
 (0)