Skip to content

Add a new flag to control line-length of comment lines separately.#10

Open
csilvers wants to merge 3 commits intowalle:masterfrom
Khan:master
Open

Add a new flag to control line-length of comment lines separately.#10
csilvers wants to merge 3 commits intowalle:masterfrom
Khan:master

Conversation

@csilvers
Copy link

This allows users to have a longer line-length limit for code than for
natural-language text.

One example is a project that wants "most" code to fit in 80 columns,
but will allow the occassional long line. The best way to implement
this in lll right now is to have a longer line limit (say, 100
columns) with an understanding the code-reviewers will make sure most
lines are not over 80 columns. But we still want all comment lines to
fit within 80 columns, since there's no good reason for them not to.
This new flag allows for that.

@csilvers
Copy link
Author

I forgot to say in the commit message, but I also fixed a buglet in util_test where expected and actual were reversed.

This allows users to have a longer line-length limit for code than for
natural-language text.

One example is a project that wants "most" code to fit in 80 columns,
but will allow the occassional long line.  The best way to implement
this in `lll` right now is to have a longer line limit (say, 100
columns) with an understanding the code-reviewers will make sure most
lines are not over 80 columns.  But we still want all comment lines to
fit within 80 columns, since there's no good reason for them not to.
This new flag allows for that.
@Zamiell
Copy link

Zamiell commented Mar 29, 2020

@walle Any chance of merging this?
It's a little ridiculous that the lll linter complains about code like the following:

// Get the project path
// https://stackoverflow.com/questions/18537257/how-to-get-the-directory-of-the-currently-running-file
if v, err := os.Executable(); err != nil {
	fmt.Println("Failed to get the path of the currently running executable:", err)
} else {
	projectPath = filepath.Dir(v)
}

Copy link
Owner

@walle walle left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm sorry, I missed this PR completly :(

I think it makes sense to make this configurable, but we should probably
add support for other comment prefixes.

Also added an open question, that doesn't need to be solved in this PR,
about multi line comments.

Could you please also update the README to document the new flag(s)
and their usage? If so, please add the caveat that it only works for
one line comments right now (unless we solve the multi line issue).

The request changes feedback is because of the flag name -l which
conflicts with the previous max length flag.
As it would break the current behaviour.

func ProcessFile(w io.Writer, path string, maxLength, tabWidth int,
exclude *regexp.Regexp) error {
// length is greater than maxLength. If the line is a comment line, it
// writes an error if the line length is greater than maxLength *or*
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could say something like: if it is identifed as a comment compared to maxCommentLength?

// length is greater than maxLength. If the line is a comment line, it
// writes an error if the line length is greater than maxLength *or*
// maxCommentLength.
func ProcessFile(w io.Writer, path string,
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not for this PR, for later consideration.

The argument list is growing a bit too much. Maybe we should pass a config struct here instead.

exclude *regexp.Regexp) error {
// Process checks all lines in the reader and writes an error if the line
// length is greater than MaxLength. If the line is a comment line, it
// writes an error if the line length is greater than maxLength *or*
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could say something like: if it is identifed as a comment compared to maxCommentLength?


// isComment reports whether a given line of input is a comment line.
// It does this by checking if the line starts with `//` (excluding tabs).
func isComment(line string) bool {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will only work for languages that use // as the comment indicator.
Maybe we can make it configurable as well? For languages that use e.g. # for comment syntax.
Defaulting to // makes sense though.

Open question. Not sure how we should handle multiline comments, it would be nice
to add the support here if we add the flag. But we would need to look back and forward
to see if the line is part of a block comment.
Maybe that would be better done as a later step, when the line have been flagged
as too long. If we search and find that the line is part of a multiline comment we
re-evaluate it to check against the max comment length.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I didn't realize this linter was intended for use by non-go code as well. As you mention, there are already a lot of params here already, so I'm a little reluctant to add another one to identify the comment character (and make people pass it in who are using this for non-go languages). We could maybe auto-detect based on file extension, or just by analyzing the text. But that's probably too fancy.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As for multi-line, knowing how to format multi-line natural-language text -- which might have bullet-point lists, or code snippets, or other whitespace-sensitive formatting -- is very difficult. In the version I wrote for golangci-lint, I have some heuristics I use but I'm not 100% happy with them.

Copy link
Owner

@walle walle Apr 8, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I wrote the tool my idea was to use it for all the files in the
projects I was working on. But if I recall correctly the flags

GoOnly           bool     `arg:"-g,env,help:only check .go files"`
SkipTests        bool     `arg:"-t,env,help:skip _test.go files"`
Vendor           bool     `arg:"env,help:check files in vendor directory"`

where added when adding the linter to gometalinter.

I'll take a look to the parameter list and see if I can do something
better with it to be able to add more configuration stuff easily.

For the multi-line issue, yes indeed a bit difficult. But I would probably
go with a quite naive approach first and see how far it helps.

@walle
Copy link
Owner

walle commented Apr 5, 2020

@Zamiell Thanks for bumping this PR! Somehow I completly missed it :(

@Zamiell
Copy link

Zamiell commented Apr 5, 2020

No problem, thanks for your work on this excellent linter.

@Zamiell
Copy link

Zamiell commented Apr 5, 2020

As a side note, is it possible to just make lll ignore lines that are over X characters when there are no spaces in them? Either by default or possibly behind a new flag? (And maybe it should only apply to comments.)

@csilvers
Copy link
Author

csilvers commented Apr 5, 2020

Thanks for the detailed feedback!

We wanted to use lll in the context of golangci-lint. It turns out they have their own implementation of lll so we ended up making changes there. golangci-lint gives access to the AST, so we implemented things that way, which was more annoying in some ways but made it easier to, e.g., deal with multi-line comments.

The end result ended up being quite complicated, and it's still not super-well tested within our org, but I'm happy to share it if you'd like! But these days I'm basically on childcare full time and won't be able to get to this PR for a while. Someone else who could use it is very welcome to commandeer it and push it over the finish line!

csilvers and others added 2 commits April 5, 2020 14:43
Co-Authored-By: Fredrik Wallgren <fredrik.wallgren@gmail.com>
Co-Authored-By: Fredrik Wallgren <fredrik.wallgren@gmail.com>
@codecov-io
Copy link

Codecov Report

Merging #10 into master will increase coverage by 0.40%.
The diff coverage is 100.00%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master      #10      +/-   ##
==========================================
+ Coverage   90.76%   91.17%   +0.40%     
==========================================
  Files           2        2              
  Lines          65       68       +3     
==========================================
+ Hits           59       62       +3     
  Misses          4        4              
  Partials        2        2              
Impacted Files Coverage Δ
lll.go 89.47% <100.00%> (ø)
utils.go 100.00% <100.00%> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 4438bcc...8c79f08. Read the comment docs.

@walle
Copy link
Owner

walle commented Apr 8, 2020

@Zamiell l I would add a new flag for that. Let me see if I can get some
time to add the feature soon :)

@csilvers Aha ok, I didn't know it was re-implemented in golangci-lint I'll
take a look.

And now worries about getting the PR over the finish line, I will try to
dedicate some time to it asap. And maybe add some more things :)

Thank you for your contribution!

@Zamiell
Copy link

Zamiell commented Apr 8, 2020

@walle Thanks. To go a little bit more in depth on my suggestion, it is probably better to just copy the various flags (and the corresponding algorithms) from the most popular long-line-linter in the world, eslint max-len: https://eslint.org/docs/rules/max-len

We can see the source code for it here: https://github.com/eslint/eslint/blob/master/lib/rules/max-len.js

Specifically, relating to my suggestion, it has flags for "ignoreStrings", and "ignoreUrls", both of which are set to true by default. I think having them be true by default is a sensible idea, for both max-len and for lll!

Furthermore, if you have the time, I think it would actually be ideal if lll provided all of the flags that max-len does, as I think that people will probably expect similar functionality.

@Zamiell
Copy link

Zamiell commented May 19, 2020

walle, any progress on this? I also have another request, but I'll put it in a new issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants