lemmy-help icon indicating copy to clipboard operation
lemmy-help copied to clipboard

Local classes are recognized by lemmy-help but their methods aren't

Open idanarye opened this issue 3 years ago • 12 comments

I've created this file:

$ cat my_module.lua 
---@mod my_module
local M = {}

---@class Foo
M.Foo = {}

function M.Foo:bar()
end

---@class Baz
local Baz = {}

function Baz:qux()
end

return M

The I ran lemmy-help version 0.10.0 on it:

$ lemmy-help my_module.lua 
================================================================================
                                                                     *my_module*

Foo                                                                        *Foo*


M.Foo()                                                                  *M.Foo*


Baz                                                                        *Baz*


vim:tw=78:ts=8:noet:ft=help:norl:

The Foo class was exported and its method bar was recognized by lemmy-help, but qux did not get an entry even though its class Baz did. Is it because Baz is declared local? But these classes' methods should still get into the docs because users can still get them via functions.

idanarye avatar Dec 01 '22 17:12 idanarye

The Foo class was exported and its method bar was recognized by lemmy-help

If you look closely bar() is not recognized. It's a limitation. The parser, currently, can only recognize this <ident>[.:]<ident> far, so both M.foo and M.foo:bar will rendered as M.foo. Although, I do want to fix this limitation.

but qux did not get an entry even though its class Baz did. Is it because Baz is declared local? But these classes' methods should still get into the docs because users can still get them via functions.

Yes, local Baz is not included because it's defined as local. But ---@class Baz was included in help bcz lemmy-help doesn't know whether the class is private or not. If you want to exclude it from the help, then use ---@private. And I am pretty sure you can't access Baz from outside of the file.

---@private
---@class Baz
local Baz = {}

numToStr avatar Dec 05 '22 10:12 numToStr

If you look closely bar() is not recognized.

Oh, I think I got confused by M.Foo which was shown in addition to Foo...

Isn't this a problem though? I was kind of hoping lemmy-help parses its annotations in a similar way to Sumneko, where having a ---@class directly above a the declaration of the class in the code associates them with each other...

idanarye avatar Dec 05 '22 10:12 idanarye

Well, sumneko's lua parser is designed to work with its LSP server. So, it's natural that it knows more about code than lemmy-help straight & simple top-down parser. And fun part, lemmy-help only parses the code that it needs to be able to generate help doc.

numToStr avatar Dec 05 '22 11:12 numToStr

What if we could manually annotate it? Something like:

---@owner Baz
function Baz:qux()
end

Then lemmy-help will know that this function belongs to ---@class Baz, which is on a single global namespace, and it won't have to statically analyze the flow of the Lua code like Sumneko does.

idanarye avatar Dec 05 '22 16:12 idanarye

What's the point of it? In your example you are exporting M so only methods and properties attached to M will be documented. Beside that, any ---@class, ---@type, ---@alias will also be included unless ---@private is used.

numToStr avatar Dec 05 '22 18:12 numToStr

My actual usecase is this: https://github.com/idanarye/nvim-channelot/blob/main/lua/channelot/init.lua

But that's may be too long to read and discuss, so consider this:

---@mod my_module
local M = {}

---@class Foo
local Foo = {}

function Foo:bar()
end

---@return Foo
function M.make_foo()
end

return M

I'm not exporting Foo here, because I don't want it to be created by the users directly - only by calling make_foo (which, BTW, can be a method of a different class. But let's keep the example simple)

Still - users can get their hand on an instance of Foo and invoke it's :bar() method, and thus I want this method to be documented in the vimdoc that lemmy-help generates.

idanarye avatar Dec 05 '22 19:12 idanarye

Also, it could be a workaround to the three-idents-name problem.

idanarye avatar Dec 05 '22 19:12 idanarye

Still - users can get their hand on an instance of Foo and invoke it's :bar() method,

How? You are only exporting M and Foo is defined locally. I maybe not an expert on lua, but I am pretty sure that lua doesn't work like that.

numToStr avatar Dec 06 '22 04:12 numToStr

local my_module = require('my_module')
local foo_instance = my_module.make_foo()
foo_instance:bar()

idanarye avatar Dec 06 '22 09:12 idanarye

local my_module = require('my_module')
local foo_instance = my_module.make_foo()
foo_instance:bar()

Ahh, Now I understand. I was keep thinking about the same file.


Hmm, it's an interesting use case. I guess we can directly look for exported identifiers, let say ---@class Baz is there and then you have function Baz:foo(). Then we can check whether both have the same identifier i.e., Baz; if yes then document it otherwise discard it. This way we won't be needing the ---@owner tag as you suggested. And obviously this whole thing won't work if ---@private in used. Now the problems:

  • The identifier lookup, currently every node it stored in an array and so to make it optimal we need to store exported identifiers in hashmap.
  • This will definitely interfere with the --prefix-* options as they modify the identifier name used for the doc tag.

numToStr avatar Dec 06 '22 10:12 numToStr

What was the intended use then? Were classes supposed to be their own files, so each file is either a class or a bundle of free functions?

idanarye avatar Dec 06 '22 12:12 idanarye

That's subjective, You could separate classes into their own files. But you can also use ---@class as type for (exported) function params.

numToStr avatar Dec 06 '22 13:12 numToStr