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
New syntax checker chaining system #961
Conversation
Sounds really good to me! |
@lunaryorn I like it, but can think of few edge cases and have a few questions/suggestions:
|
One more question: Will you use |
TL;DR: |
a80ef82
to
6e48c71
Compare
@lunaryorn - Continuing our discussion from #939. This new syntax looks to be a huge improvement over the previous I would ask for a (hopefully simple) modification to the proposed method, to be able to define arbitrary |
@mkcode With arbitrary kinds how'd you order syntax checkers? What kind of "convention" do you have in mind? And why should proselint have its own kind? Isn't it a style checker, obviously? |
The convention I had in mind are the
Not sure. Perhaps have any user defined types run last.
That isn't immediately obvious to me. That is what I would guess, but 'style' can mean different things in different contexts. The proselint checker isn't special, it's probably the least important of any! The purpose of it having it's own kind, would be so that it is always run - not dependent on any previous checkers. If you end up making kinds execute concurrently like it was mentioned, even better! Looking at the code, I see no difference in how the different kinds are handled, so they are essentially different Queues - which the different checkers insert into if they want to wait for the results of a previous checker. Perhaps I am missing something and this is a bad idea? If so, Apologies for the PR pollution. Perhaps you would prefer to discuss in #939, and not here? |
You'd have a list variable which defined the order, I guess. It wouldn't be bad IMO to expose that kind of thing. |
@mkcode I'm not sure whether I see the problem you're trying to solve. If you defined the proselint checker with @purcell I'm not sure, but I think I disagree. Making kinds configurable adds extra complexity, which I'd rather like to avoid unless I see a compelling reason. If there's a syntax checker that doesn't fit into any of said kinds I'd rather hard-code a new kind into Flycheck. But proselint fits perfectly into |
After reading what |
@Simplify Ah, I thought that proselint would only check for writing style. But if it does more, why not put it into But ultimately it doesn't really matter: I'm against an From what I see in the screenshot, colorguard would be a |
The problem is that most developers, including me, think of |
Might be it will be better to use something like |
@JAremko In how far do you think Given the apparent obscurity of [1] Technically the chain is linearized currently, though, for simplicity. For this reason parallel execution of checkers of the same "kind" won't come any time soon. The current goal is to get a system that scales better in terms of maintenance overhead, and not to improve performance. |
My input was ambiguous itself, sorry. 😄 I was talking about ambiguous behavior not wording. When two checkers conflict with each other, which one will run?
I think it's nice if end user could just use it without solving the conflicts. |
Another good example. Mediocre linter that works with major modes |
@Simplify The current implementation resolves conflicts in order of Regarding your example, if you wrote a syntax checker for a "meta-linter" you'd add Likewise in your second example: Put the good linter first in
I'm not sure what you mean, but it's Flycheck's aim to work with minimal or no user interaction required and I think the new syntax checker chaining system proposed by this PR goes a long way to achieve this goal. But at some point a user has to make a choice if there are equivalent linters. Flycheck can't know whether you prefer eslint or jshint for your Javascript, or GCC or Clang for your C. That's what That covers both ways of making a choice: Opting out from particular syntax checkers as well as explicitly choosing what you'd like to use. |
This new system sounds very nice and well-designed. I think the potential for confusion between levels isn't too worrying. Some small questions before I make a pass on the code:
In any case, this looks like a great proposal :) |
(unless (or modes predicate) | ||
(error "Missing :modes or :predicate in syntax checker %s" symbol)) | ||
(unless modes | ||
(error "Missing :modes in syntax checker %s" symbol)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm. Why is this change needed? Without it, I could imagine e.g. "ispell" being a flycheck checker applicable in all buffers.
Some related thoughts while looking at the diff:
|
Return a list of all syntax checkers to apply on the current | ||
checker in order." | ||
;; Luckily `seq-sort' calls out to `sort' internally which is stable, thus | ||
;; sorting by. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment looks incomplete :)
(also: congrats on updating the checker definitions 👍) |
I can think of a specific example, e.g. |
@cpitclaudel We do need I'd rather not like to preserve backwards compatibility. We've got no formal versioning policy for deprecations and thus can't give a timeframe for the removal anyway so we'd essentially just delay the breakage in my opinion. On the other hand we can't map As for your suggestion about a selection strategy, I don't known, but it feels really complicated. I can't imagine writing a docstring for that, let alone an implementation. If you can come up with a good implementation for that I'd be happy to talk about a PR, but I'd rather not like to delay this pull request for that suggestions, and I'd not like to implement it. I'd rather get rid of local checker selection entirely and see if we can get along with only disabled checkers and local bindings for Generally, I'd like to keep this pull request as simple as possible, to get it done soon. It's been open far too long. In fact, I do intend to get rid of For the same reason—simplification—I'd like to force Likewise I'd defer the discussion about clang and GCC. Currently it's not possible to run both at the same time either because they don't chain to each other. I added |
@cpitclaudel As for the diff it's not up to date. I've got a private branch on top of current I think I may just create a new pull request and close this one, but I haven't decided yet. I've got time to spare next weekend so I hope to deliver something by that time. |
Superseded by #1072. |
Thanks for the convincing example @purcell, and thanks for the thoughtful answer @lunaryorn :) |
See #836 for a motivation. To summarize, the current system is cumbersome to maintain and hard to understand. This in-progress PR intends to provide a new simpler system that addresses these shortcomings.
I'm opening it early to collect feedback on the approach and the implementation. Inviting @flycheck/core-developers, @flycheck/maintainers, @mgudemann and @purcell.
Connects to #836.
Design
Instead of
:next-checkers
we now have three properties to control when a checker is selected::stage
: The kind of syntax checker, e.g.syntax
,type
,lint
,style
,test
, which serves to order checker execution.:conflicts-with
: A list of syntax checkers this syntax checker conflicts with, i.e. may not be used together with.:maximum-level
: The maximum error level in the current buffer this syntax checker should still run at.I hope that the meaning of these properties is fairly obvious: Flycheck runs all syntax checkers in order of their
:stage
(e.g. syntax checkers before type checkers, and so on). To find all checkers it goes throughflycheck-checkers
and collects all checkers that support the current buffer, and then evicts conflicting checkers from first to last.Finally, after it has assembled the chain, it runs all syntax checkers one by one, and skips over any checker if the highest error level in the current buffer is greater (by priority) than the
:maximum-level
.Pros
:stage
and the new checker seamlessly plugs into existing ones. There's no need forflycheck-add-next-checker
anymore.:next-checkers
it was never obvious whether Flycheck would try to run all or just the first.:next-checkers
of all other Go checkers anymore.Cons
flycheck-select-checker
and related functionality is gone. We'll recommend buffer-local bindings offlycheck-checkers
as alternative, which is actually simpler, too. But there'll not be an interactive command anymore.:next-checkers
indefinitely.Status
:kind
to:stage
flycheck-select-checker
and friendsflycheck-checkers
Todo after merging
:next-checkers
.