Skip to content

table literals with descriptions #2128

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
max397574 opened this issue May 24, 2023 · 14 comments
Open

table literals with descriptions #2128

max397574 opened this issue May 24, 2023 · 14 comments
Labels
enhancement New feature or request

Comments

@max397574
Copy link
Contributor

max397574 commented May 24, 2023

I expect something like this or something similar to this to work but it doesn't
also when I e.g. split it up onto multiple lines

---@field cat { ["name"]: string # the name of the cat, ["age"]: integer # the age of the cat }

everything is working fine without the descriptions

@C3pa
Copy link
Contributor

C3pa commented May 27, 2023

Currently, you can achieve this if you create a new class for the cat field:

---@class catClass
---@field name string the name of the cat
---@field age integer the age of the cat

---@class someClass
---@field cat catClass
---@field ...

@max397574
Copy link
Contributor Author

yes
but for my usecase this isn't quite a good way of doing it since the "classes" actually don't have a name
they should be inline

@C3pa
Copy link
Contributor

C3pa commented May 30, 2023

since the "classes" actually don't have a name

Mind elaborating a bit on this?

If I understood correctly, you don't want to define the catClass because it doesn't exist in real Lua code?

@max397574
Copy link
Contributor Author

yes

@C3pa
Copy link
Contributor

C3pa commented May 31, 2023

Well, why not? That's how many do it. In the end, the annotations are just comments. These affect just your autocomplete suggestions, not code behavior.

@sumneko sumneko added the enhancement New feature or request label May 31, 2023
@sumneko
Copy link
Collaborator

sumneko commented May 31, 2023

I haven't come up with a better syntax yet. For example, in the solution you provided, I can't decide where the comment ends.

(Translated by ChatGPT)

@max397574
Copy link
Contributor Author

could this perhaps be done when you spread the thing to multiple lines similarly to how it's possibel to add descriptions to enums? @sumneko

@DrSloth
Copy link

DrSloth commented Jul 11, 2024

Hello, i am also very interested in this feature. In my use case there are many functions that have "named arguments" they just receive a table as first arg and take the values from there. If someone wants to give me pointers where to start i would be glad to help implement this.

@tmillr
Copy link
Contributor

tmillr commented Aug 11, 2024

I haven't come up with a better syntax yet. For example, in the solution you provided, I can't decide where the comment ends.

(Translated by ChatGPT)

Maybe you could support syntax such as this:

-- Leading whitespace is insignificant and removed/ignored by the LSP.
-- Also if a line ends with `,` or `;`, ignore/remove it from the description as well.

---@field cat {
---  name: string the name of the cat
---  age: integer the age of the cat
---}

---@param cat {
---  name: string the name of the cat,
---  age: integer the age of the cat,
---}

Then just keep a count of balanced braces to find the end.


Or, maybe:

---@field cat {
---  @field name string the name of the cat
---  @field age integer the age of the cat
---}

---@param cat {
---  @field name string the name of the cat
---  @field age integer the age of the cat
---}

@tomlau10
Copy link
Contributor

Using a @class would be better. As otherwise with @alias or literal table structure annotation, it would lead to this issue: #2785 (comment), where the whole table structure get expanded during hover preview / set type inline hint 😇

I understand the argument here that the cat just a field with a specific table value, and is not a class. But in LuaLS class is just a type container. If the concern is not wanting to pollute the class types list, we may use namespaces in class names, just like what the luv library did: https://github.com/LuaCATS/luv/blob/3615eb12c94a7cfa7184b8488cf908abb5e94c9c/library/types.lua#L74-L96

---@class uv.fs_stat.result.time
---@field sec integer
---@field nsec integer

---@class uv.fs_stat.result
---
---@field dev       integer
---@field mode      integer
---@field nlink     integer
---@field uid       integer
---@field gid       integer
---@field rdev      integer
---@field ino       integer
---@field size      integer
---@field blksize   integer
---@field blocks    integer
---@field flags     integer
---@field gen       integer
---@field atime     uv.fs_stat.result.time
---@field mtime     uv.fs_stat.result.time
---@field ctime     uv.fs_stat.result.time
---@field birthtime uv.fs_stat.result.time
---@field type      string
  • uv.fs_stat is a library function
  • uv.fs_stat.result is the return value of that function
  • inside this class there are some time table fields, which is defined as uv.fs_stat.result.time
  • using this pattern, if uv.fs_stat.result has another date table with year, month, day, we may write it as a separate class
---@class uv.fs_stat.result.date
---@field year integer
---@field month integer
---@field day integer

(instead of ---@field date { year: integer, month: integer, day: integer } under uv.fs_stat.result)

@C3pa
Copy link
Contributor

C3pa commented Aug 12, 2024

I totally agree with tomlau10 here. We do the same in MWSE: https://github.com/MWSE/MWSE/blob/master/misc/package/Data%20Files/MWSE/core/meta/lib/tes3.lua#L34
For a function with the following signature, we do the annotations like this:

--- @param params tes3.addArmorSlot.params
function tes3.addArmorSlot(params) end

---Table parameter definitions for `tes3.addArmorSlot`.
--- @class tes3.addArmorSlot.params
--- @field slot number Armor slot number. A number greater than 10 to configure a slot for.
--- @field name string The human-readable name for the armor slot.
--- @field key string? *Optional*. The key placed in the `tes3.armorSlot` table. If no key is provided, the name will be used.
--- @field weight number? *Default*: `0`. A stand-in for the armor base weight value, typically controlled by a GMST (e.g. iHelmWeight).
--- @field scalar number? *Default*: `0.1`. A multiplier with range 0.0-1.0 that controls how much of an item's armor value applies to a character's overall armor rating. For comparison, standard chest armor uses 0.3, helmets, greaves and pauldrons use 0.1, and gauntlets use 0.05.

@tmillr
Copy link
Contributor

tmillr commented Aug 13, 2024

The current convention is to just come up with a name and create classes (unless you only have 2-3 fields and are sure that you don't need descriptions), but it still might be nice to have a shorthand for certain cases (mainly function args/kwargs where the table type is unique and has a small number of fields that need descriptions). It's effectively an anonymous type, or an extension of a function's type/signature. But it's not a necessary feature and we can do without it for now (since we have the @class workaround).

@ChristinWhite
Copy link

Is there a reason something like this wouldn't be a good idea for a small number of fields that are functioning as named arguments?

--- @param opts table ...
--- @param opts.name string ...
--- @param opts.age integer ... 

or

--- @param opts table ...
--- @field opts.name string ...
--- @field opts.age integer ... 

This would maintain nearly the same annotation conventions without adding a lot of complexity for cases when there are only 2–3 fields.

Classes certainly work, but it feels like it adds a level of visual noise and the cognitive load that may not be necessary. I'd prefer to be able to read through it linearly without bouncing between different annotation blocks

@tomlau10
Copy link
Contributor

tomlau10 commented Sep 13, 2024

Is there a reason something like this wouldn't be a good idea for a small number of fields

Here maybe the problems (just my guess)

  • first of all @field is specifically for @class, and not all @param are of table type. What if you write @field after a non table type param? should it throw error?
---@param opts integer
---@field opts.name string ???
  • when parsing the @field syntax, it must specify the field name, instead of a table index syntax opts.name. Because this field is attached to the @class type above. Otherwise this complicates the things if your @param name doesn't match with what you write in @field:
---@param optsA table
---@field optsB.name string ???
  • the suggested syntax is not extendable. What if the opts is a multi level table?
---@param opts table
---@field opts.a table
---@field opts.b table
---@field opts.a.name integer ???
---@field opts.b.name integer ???

the complexity here seems exponential 😅

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

7 participants