Skip to content
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

Follow-ups after adding default.yaml support #3259

Merged
merged 6 commits into from
Apr 21, 2024

Conversation

dmaluka
Copy link
Collaborator

@dmaluka dmaluka commented Apr 18, 2024

More follow-ups of #2933.

  • Fix set filetype unknown not working as expected in some scenarios.
  • Allow includes in default.yaml.
  • There is still even more stuff to fix and to refactor in the existing UpdateRules() logic. Just added TODOs for now.

Fix `set filetype unknown` not working as expected in the following
scenario:

1. open foo.txt (no filetype detected) -> ft is `unknown`, highlighted
   with default.yaml, as expected

2. `set filetype go` -> ft is `go`, highlighted with go.yaml as expected

3. `set filetype unknown` -> ft is still `go`, still highlighted with
   go.yaml (whereas expected behavior is: ft is `unknown`, highlighted
   with default.yaml)

Fix that by always updating b.SyntaxDef value, not reusing the old one.

This also makes the code simpler and easier to understand.
The "runtime" term is ambiguous: it refers to both built-in and user's
custom ("real runtime") files.
@@ -690,6 +690,7 @@ func parseDefFromFile(f config.RuntimeFile, header *highlight.Header) *highlight
}

if header == nil {
// TODO: use faster highlight.MakeHeader() when possible
Copy link
Collaborator

Choose a reason for hiding this comment

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

But highlight.MakeHeader() can only be used, when we iterate over config.RTSyntaxHeader, otherwise we can't guarantee, that we access the correct lines or am I wrong?
So in case of findRuntimeSyntaxDef() we could iterate over the config.RTSyntaxHeader first, to create the header structure and then iterate over the normal config.RTSyntax and passing the already created header to parseDefFromFile().

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes, so my point was that we should try to use config.RTSyntaxHeader whenever possible, to make it faster. That's what it is for.

Actually later I've realized that this should not have much impact on performance (for now): in findRuntimeSyntaxDef("default", nil) we're gonna call this MakeHeaderYaml() just once (for the file that satisfies the condition f.Name() == "default"), not hundreds of times.

So I think I'll remove this TODO. All this still looks messy, but I guess we should rather start cleaning this mess by figuring out how to fix the buggy include logic (per below comments) without making the code unreadable again...

if b.SyntaxDef != nil && highlight.HasIncludes(b.SyntaxDef) {
includes := highlight.GetIncludes(b.SyntaxDef)

var files []*highlight.File
// TODO: search in the user's custom syntax files first
Copy link
Collaborator

Choose a reason for hiding this comment

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

Yep, user defined includes aren't considered yet, but are worth to be considered.
It wasn't in the scope of my PR.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yeah, this issue is separate from your PR, this mess has been here before.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Maybe the following patch is a point to start...
RefactorIncludesInUpdateRules.patch.txt
...it's not yet tested, but maybe you can improve and extend it or you throw it away and create your own approach. 😉

It shall consider nested includes, as long as the include isn't present in the list.

Open TODOs:

  • prevent cyclic include
  • process user files as includes

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

It shall consider nested includes

Hmm yeah, good point, thanks.

Though it seems your patch will still not fix it: highlight.ResolveIncludes() is still gonna handle the current file only.

Looks like ParseDef() itself would need to take care about includes, transparently?

Copy link
Collaborator

@JoeKar JoeKar Apr 20, 2024

Choose a reason for hiding this comment

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

Though it seems your patch will still not fix it: highlight.ResolveIncludes() is still gonna handle the current file only.

Hm, the problem is that...

func resolveIncludesInDef(files []*File, d *Def) {
	for _, lang := range d.rules.includes {
		[...]
	}
        [...]
}

...in resolveIncludesInDef(), which again targets the base syntax definition and his level of includes only. Looks like we could drop this outer loop. Then it will append the (unfortunately) once again parsed rules to the base syntax definition, what I would expect it to do...since we already collected all files involved.

Edit1:
The above mentioned doesn't seem to be that easy, since the regions are processed in the same way.

After looking once again at my updated version of parseDefFromFile() (three returns) I came to the conclusion, that this isn't the best approach, since every iterated file will be fully parsed (all steps), even when we don't need it. So I will return to the single parsing steps within the searchSyntaxDefIncludes() till we've a better way to optimize the duplication there.

Looks like ParseDef() itself would need to take care about includes, transparently?

No bad idea, to fully keep it out of the buffer. But then we need to find a way how to deal with the different runtime files, controlled and feed by the buffer.

Edit2:
Ok, since ParseDef() will be involved already twice with the rework it doesn't seem to be feasible. A better logic, than already prepared, seems to be necessary.
Furthermore the logic of the buffer asking the highlighter for includes, searching in the runtime files and give them the highlighter back to do some additional resolving is complicated and hard to follow.

Edit3:
RefactorIncludesInUpdateRules2.patch.txt
Not really convincing. :(

Edit4:

Looks like ParseDef() itself would need to take care about includes, transparently?

No bad idea, to fully keep it out of the buffer. But then we need to find a way how to deal with the different runtime files, controlled and feed by the buffer.

Seems definitely to be the best idea and we don't need to care any longer about this jumping forth into the highlighter, back to the buffer and forth into the highlighter again. Let us do this directly while parsing the file respective definition of it. The rules and regions can be build and append in one step.
👍

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

...I was wrong: we already ensure that in the list returned by config.ListRuntimeFiles() user's custom files always come before default files. Moreover, since your #3066 we ensure that the same filetype never appears twice: if there are both a default file and a user's custom file for the given filetype, this list only contains the user's custom one. So we don't need to fix anything in this regard.

...Regarding nested includes: yes, jumping back and forth between the buffer and the highlighter seems to be a no-go, it would be tremendously ugly and would be just a work around the broken design of the highlight parser's API. The way to go seems to be to redesign this API.

But I don't feel like redesigning it right now, so maybe let's just document that nested includes are not supported for now.

RefactorIncludesInUpdateRules2.patch.txt
Not really convincing. :(

Actually the basic idea of your patch, i.e. just move the bulk of the include logic to a separate function and then fix it there, seems reasonable. Although, as I've just found, there is basically nothing to fix, but still it seems a good idea to move it to a separate function, to make UpdateRules() even shorter.

internal/buffer/buffer.go Outdated Show resolved Hide resolved
if b.SyntaxDef != nil && highlight.HasIncludes(b.SyntaxDef) {
includes := highlight.GetIncludes(b.SyntaxDef)

var files []*highlight.File
// TODO: search in the user's custom syntax files first
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

...I was wrong: we already ensure that in the list returned by config.ListRuntimeFiles() user's custom files always come before default files. Moreover, since your #3066 we ensure that the same filetype never appears twice: if there are both a default file and a user's custom file for the given filetype, this list only contains the user's custom one. So we don't need to fix anything in this regard.

...Regarding nested includes: yes, jumping back and forth between the buffer and the highlighter seems to be a no-go, it would be tremendously ugly and would be just a work around the broken design of the highlight parser's API. The way to go seems to be to redesign this API.

But I don't feel like redesigning it right now, so maybe let's just document that nested includes are not supported for now.

RefactorIncludesInUpdateRules2.patch.txt
Not really convincing. :(

Actually the basic idea of your patch, i.e. just move the bulk of the include logic to a separate function and then fix it there, seems reasonable. Although, as I've just found, there is basically nothing to fix, but still it seems a good idea to move it to a separate function, to make UpdateRules() even shorter.

@@ -950,6 +952,8 @@ func (b *Buffer) UpdateRules() {
break
}
}
// TODO: fix this mess. For each include, we should include
// exactly one file: either a built-in one or a user's custom one
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

So, I was wrong about this one too: since #3066 we already ensure that exactly one file will be included.

This len(files) >= len(includes) check is now not strictly necessary, but it provides a simple optimization (to exit the loop earlier), so we can keep it.

@dmaluka dmaluka merged commit 169a9a6 into zyedidia:master Apr 21, 2024
3 checks passed
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.

2 participants