Sublime Forum

Syntax highlighting and merge conflicts

#1

Would it be possible to allow merge conflict delimiters in all syntaxes? Currently this breaks highlighting. The reasoning would be that virtually all developers work with Git or similar versioning tools nowadays (it’s the future I know). And it would make life helluvalot easier if syntax highlighting didn’t break in conflicted files, broken code is already difficult enough.
Hey, we could even highlight those delimiters that show up. Now I know that in PHP for example <<< is the heredoc syntax, f*k PHP right? I mean <<<<<<< HEAD deserves a better status than that operator, it’s even got more arrows.

These are the ones I’m referring to:

<<<<<<< HEAD

(properly highlighted code in year 2017)

=======
>>>>>>> master
0 Likes

#2

I like this idea. You could start an issue about it on https://github.com/sublimehq/Packages
If it ever happens, an inheritance and overridability model of sublime syntax files would make this trivial.

0 Likes

#3

In principle, this would have to be done syntax by syntax. And this is the sort of thing that I’m leery of adding to a syntax: hardcoding an extension for a particular optional tool.

In addition, it may not always be possible to achieve good results. For instance:

<<<<<<< HEAD
class Foo {
=======
class FooBar {
>>>>>>> master
    myMethod() {}
}

You could take a reasonably stab at getting it to work with common cases, which might still be a worthwhile improvement.

Logically, this is behavior that a Git package should provide. Ideally, it would have some mechanism to patch an arbitrary existing syntax. I might suggest my own YAML Macros package for the task:

%YAML 1.2
%TAG ! tag:yaml-macros:YAMLMacros.lib.extend:
---
!extend
_base: JavaScript.sublime-syntax
name: JavaScript (Git Merge)

contexts: !merge
  prototype: !prepend
    - match: ^<<<<<<< ([\w-]+)$
      scope: some.scope
      captures:
        1: entity.name.branch
    - match: ^>>>>>>> ([\w-]+)$
      scope: some.scope
      captures:
        1: entity.name.branch
    - match: ^=======$
      scope: some.scope

I haven’t tested this, but something like it should work for simple cases.

Then the question would be how to have the package automatically provide patched versions of existing syntaxes and (maybe) how to supplant those syntaxes in menus.

0 Likes

#4

Putting it into the prototype would be perfect, yeah. Now that I think about it, maybe one could make a separate GitMergeConflict.sublime-syntax file that’s hidden: true, and that gets included in every prototype.

0 Likes

#5

As @ThomSmith rightly points out, this is effectively the C preprocessor, applied to every syntax. The C preprocessor is effectively the single most difficult thing to deal with in our Default syntaxes since there are two states that have to be tracked now, instead of a single one with the current code.

We aren’t ever going to be able to maintain semantically correct highlighting of code when random tokens are inserted at arbitrary positions. So should we try and create something harder to maintain that words in some situations?

1 Like

#6

Can we treat these markers as single line comments? Or is that the same thing?

0 Likes

#7

That’s fine, but the issue is that code tends to be repeated within the markers. See the example from @ThomSmith:

<<<<<<< HEAD
class Foo {
=======
class FooBar {
>>>>>>> master
    myMethod() {}
}

The class structure will never close because it would appear that there are nested classes and the second class keyword is never terminated by }.

2 Likes

#8

If we focus on this feature request, to just highlight the delimiters, that should be feasible right? Still on a language by language basis, but you could argue these markers are common enough and easy to match. I think it’s ok to ignore that the rest of the highlighting breaks, as long as it’s super easy to find the conflict markers in the code (e.g. because they’ve got a bright red background).

0 Likes

#9

The class structure will never close because it would appear that there are nested classes and the second class keyword is never terminated by }.

It breaks the syntax, understood. Tough one.

0 Likes

#10

Now, one thing we could do would be to exclude either the first or second block from highlighting. Assuming that each version is syntactically valid, this should result in a properly formatted file (except for issues like the merge markers being inside block comments). Of course, the other block would be plain white text.

I also have a crazy idea wherein the patched syntax would somehow be able to parse the first block, revert the stack, and then parse the second. I think that this is fundamentally impossible, but I haven’t proved it. This is simpler than the C preprocessor because you can’t nest conflict markers (right?).

1 Like

#11

@wbond brings up a good point about repeating constructs…

This seems like a solution, but when you encounter a ^={7}$, you would have to recall how many pushes you did when you encountered a <{7} ([\w-]+)$, and then pop exactly that amount. That seems impossible :hushed:

0 Likes

#12

What you’d do is push your current state with a with_prototype that pops on (?=^={7}$). That way, no matter what you pushed, you’d snap back to the starting context when you saw the marker.

The hard part is undoing a pop. I think, by a very handwavy argument, that this should be possible in some kinds of “upgraded” pushdown automata, but Sublime’s parser is a deterministic PDA, which is much weaker (it can’t even parse all context-free languages). My gut feeling is that it’s not possible: backtracking like this should provide too much computational power.

It might be interesting to consider whether a simple extension to Sublime’s parser might allow it. I’ve seen at least one suggestion to add a limited degree of nondeterminism to the parser in order to parse JavaScript and other languages that require it. I’ve toyed with the idea of a sort of memoizing nondeterministic parser that might be compatible with many of Sublime’s internal optimizations while providing greater expressive power. Such a parser might be able to handle cases like this, or even (in the same naive way) the C preprocessor.

0 Likes

#13

I am absolutely opposed to this suggestion! We don’t need another package which messes around with foreign resources, such as SublimeLinter which creates patched color schemes. Such hacks cause trouble and conflicts for sure in the one or the other situation. What if two packages try to hack the same resource? Something like that might work for personal use but MUST NOT be part of commonly published packages.

0 Likes

#14

Well, if there’s a better way to do it, then that would be preferable. The whole proposition is dodgy from a technical standpoint even without patching syntax definitions.

0 Likes

#15

Can we add a syntax option, like “Diff” and “Commit”. So it will not automatically apply when there is a Merge conflict, but we have the option to change to that syntax.

0 Likes

#16

You mean something like https://github.com/sublimehq/Packages/pull/4047 ?

1 Like

#18

I’m unable to find that syntax in status bar dropdown, nor via command pallet.

0 Likes

#19

Sure, because the PR is neither merged nor released.

1 Like

#20

Will it be xD

0 Likes

#21

Depends on support by other maintainers and sublimehq being willing to include Diff package into Sublime Merge as all other packages will require it.

1 Like