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

Confusing syntax highlighting #11

Closed
schiegl opened this issue Feb 3, 2017 · 24 comments
Closed

Confusing syntax highlighting #11

schiegl opened this issue Feb 3, 2017 · 24 comments

Comments

@schiegl
Copy link

schiegl commented Feb 3, 2017

The purpose of syntax highlighting is in my opinion to tell different type of constructs apart. It would be great to tell these apart by color:

  • Types .... e.g. Int, Text, IO a
  • Keywords .... e.g let, otherwise, ::, ->
  • Primitives .... e.g. 5, "String"
  • Data constructors .... e.g. Right, Just
  • Function declaration, arguments
  • Control characters .... e.g. (,), `

But right now, there are:

  • Distinctions between Prelude/Non-Prelude which are useless in my opinion (they also don't hold if there is a custom prelude)
  • Prelude functions have the same color as function declarations
  • 3 different color for types (Bold, Thin Green, Thin Red).

screen

I find the highlighting confusing at the moment. What do you think?

btw. this is not just the theme I'm using, most other themes behave like that

@JustusAdam
Copy link
Owner

JustusAdam commented Feb 3, 2017

I understand your problems with the highlighting, however some of that is due to your theme.

In my theme function names in type signatures have a color different from that of prelude functions, so I think the only way to 'fix' that is to remove highlighting for prelude functions alltogether, which might not be the worst idea, since the set of types and functions exposed in prelude differs a lot between different versions of haskell/ghc.

For some reason on my theme though prelude types now have the same color as data constructors, even though I didn't change anything.
I therefore must conclude that much of the problems are with the themes. None of which seem to be particularly tailored towards Haskell.

If you want to influence that however, you can either edit the theme, or try reassigning the tags in the language grammar.
The highlighting grammar only tags the code, the theme then decides how to highlight it.

Also for your list, I'd add (as distiction)

  • Types IO, Either should be different from type arguments IO a
  • Operators ++, == should be different from 'keywords' ::, ->, \, =

As for function arguments, this one's quite tricky, because of how permissive Haskell's grammar is with newlines.

@JustusAdam
Copy link
Owner

Oh and I think the issue with the three colors for types, is that there's no appropriate rule for inline type signatures.

@schiegl
Copy link
Author

schiegl commented Feb 3, 2017

In my theme function names in type signatures have a color different from that of prelude functions, so I think the only way to 'fix' that is to remove highlighting for prelude functions alltogether, which might not be the worst idea, since the set of types and functions exposed in prelude differs a lot between different versions of haskell/ghc.

Yes. Also I don't really see value in highlighting Prelude functions as there is no inherent difference.

I therefore must conclude that much of the problems are with the themes. None of which seem to be particularly tailored towards Haskell.

That is true some fit better than others.

Types IO, Either should be different from type arguments IO a

Type constructors are basically types. It would make sense to color type variables slightly different. But it's not a priority to me.

Operators ++, == should be different from 'keywords'

Defintely. I would treat them like regular functions, which they are.

Oh and I think the issue with the three colors for types, is that there's no appropriate rule for inline type signatures.

Why can't there just be Type? Why differentiate? I don't think there is a difference between an inline type and the regular "type signature" type. Is there?

@JustusAdam
Copy link
Owner

Yes. Also I don't really see value in highlighting Prelude functions as there is no inherent difference.

Me neither. Interestingly, if you look at the theme selector and visual rules, they aren't special because they are prelude functions, but because they are the only ones actually marked as functions. All other functions are unmarked.

Type constructors are basically types. It would make sense to color type variables slightly different. But it's not a priority to me.

I think its nice for beginners, to have a visual distinction here.

Operators ++, == should be different from 'keywords'

Defintely. I would treat them like regular functions, which they are.

Maybe, but they differ from functions because they are infix, which in my opinion warrants a visual distinction too.

Why can't there just be Type? Why differentiate? I don't think there is a difference between an inline type and the regular "type signature" type. Is there?

That's not what I meant. I don't mean to make a visual distinction. What I'm saying is that the Haskell grammar currently does not detect inline type signatures as type signatures.

@schiegl
Copy link
Author

schiegl commented Feb 4, 2017

Maybe, but they differ from functions because they are infix, which in my opinion warrants a visual distinction too.

Maybe, but you have to be careful. Too many colors reduce readability. And infix functions are usually pretty readable by default as they are symbols most of the time.

That's not what I meant. I don't mean to make a visual distinction. What I'm saying is that the Haskell grammar currently does not detect inline type signatures as type signatures.

I see. I am not familiar with the internals. Maybe there's a way to use regex since all types appear after ::.

JustusAdam added a commit that referenced this issue Feb 4, 2017
Removed all prelude functions
Added rules for inline type signatures
Changed data, newtype and type markup to be like type signature

See #11
JustusAdam added a commit that referenced this issue Feb 4, 2017
Added more end chars to inline type signature

See #11
@JustusAdam
Copy link
Owner

I have implemented some of your suggestions, maybe have a look at it and tell me what you think.

@schiegl
Copy link
Author

schiegl commented Feb 5, 2017

screen

It looks a lot better in my opinion. Now it would be nice if the function name could also be colored to enhance readability of the function arguments. Beyond that I can't really think of anything important.

@JustusAdam
Copy link
Owner

I agree, I like it too. If you noticed I also changed how data definitions and type definitions are highlighted, they are constant with type signatures now.

As for the function itself, I'm still trying to figure out how best to do that. I't be relatively easy to highlight the function name, if there is an = following it in the same line. But that wouldn't highlight for cases where the = is in one of the following lines, which might be okay though.

I't probably (most likely) also apply to let and where bindings.

And there's the question whether to highlight ne name only if there are arguments following it. In my opinion it'd be best to highlight them all, which should make it easier to figure out where something is defined, no matter whether it's a function or other constant.

@JustusAdam
Copy link
Owner

Also as a tip: the grammar only adds tags to the source code elements. The theme governs the actual colors.

If you want to change how the highlighting works, you can probably submit some patches to the theme, by adding Haskell specific rules.
if then source file is Haskell, the elements are tagged with haskell, ergo if you don't like how, lets say how keyword.operator tagged elements are highlighted, you can change that in the theme just for haskell by adding a .keyword.operator.haskell css rule. And you can find out about the tags for a specific source item by using Inspect TM Scopes from the command pallet.

JustusAdam added a commit that referenced this issue Feb 5, 2017
@schiegl
Copy link
Author

schiegl commented Feb 6, 2017

And there's the question whether to highlight ne name only if there are arguments following it. In my opinion it'd be best to highlight them all, which should make it easier to figure out where something is defined, no matter whether it's a function or other constant.

I am not sure if highlighting let the same way as global functions is such a good idea. It's easier to scroll through a file when you immediately see where a function begins. But anyway.. you forgot that there are ways to define functions without =

fun a
  | a > 3 = ...
  | otherwise = ...

@JustusAdam
Copy link
Owner

But anyway.. you forgot that there are ways to define functions without =

I didn't forget. As I said, those with = on the same line are "easy" (including those using guards, provided the = is on the same line). But if the = is on the following line the parser gets much more complicated. I might try that some other time.

Have you had a look at it yet? I implemented the version with = on the same line. In my opinion its nice to be able to see immediately where something is defined.
Plus it's consistent with the fact that in Haskell there's no difference between local and global bindings, except the scope.

JustusAdam added a commit that referenced this issue Feb 6, 2017
@schiegl
Copy link
Author

schiegl commented Feb 6, 2017

Have you had a look at it yet?

I did. Yeah you're right, both technically only differ in scope. But I still find it a bit annoying if there something in my do-block that looks like a new global function. It's hard to see where global functions start and end.

@JustusAdam
Copy link
Owner

I've published a new version (1.5.0) with some of the suggested changes.

I'm not sure yet whether to add the highlighting for function names in definitions and for identifiers and so on.
The problem with those is that it'll be very difficult, if not impossible, to get right.

@dsifford
Copy link
Contributor

@JustusAdam Are you accepting pull requests?

I, too, think that not, otherwise, and bool should be scoped to keyword to align with their siblings in Data.Bool (&& and ||).

I'd be glad to add these in if you don't mind.


Also, slightly unrelated to above, but, while the mic is still hot..... How attached are you to the XML format? Would you accept a PR if I addressed the above issues and converted from XML to JSON? IMHO, JSON is much easier to maintain.

Thanks for considering 😊

@JustusAdam
Copy link
Owner

Are && and || currently highlighted as keywords? I don't think they should. If they are that's an error on my part. I think that in Haskell, where you can redefine pretty much everything, it doesn't make much sense to treat certain operators or functions differently than others (at least that's my opinion).

As far as the JSON, XML thing is concerned: I personally prefer JSON, but when I wrote/converted this grammar there was no mention of a JSON format for the grammar in the vscode docs.
As for adding it now ... maybe, but we would loose the nice git blame information ... I feel a bit conflicted about that.

@dsifford
Copy link
Contributor

dsifford commented Nov 17, 2017

Are && and || currently highlighted as keywords?

Yep, just confirmed again to make sure.

I think that in Haskell, where you can redefine pretty much everything, it doesn't make much sense to treat certain operators or functions differently than others (at least that's my opinion).

That's a fair point. No disagreement with your logic.

However.... Would it be fair to say that for an overwhelming majority of the cases, the operations defined in Data.Bool are used as defined? (disclosure: I'm, at best, a Haskell "hobbiest", so I really am ignorant to how actual seasoned programmers work on a day-to-day basis).

What about a compromise between our opinions here and scoping the operations in Data.Bool to something along the lines of support.function.data.bool.haskell so that by default, they are scoped as a function, but theme maintainers can dial them to whatever color they feel is appropriate?

Do seasoned haskell users ever re-declare those functions to non-functions? Or are they generally the same type in those circumstances?

As for adding it now ... maybe, but we would loose the nice git blame information ... I feel a bit conflicted about that.

Fair concern. I'll leave that to you.

At the end of the day, if we can't find a common ground, I'll prob just fork the repo. No hard feelings either way!

@JustusAdam
Copy link
Owner

I have reached a decision.
I think the boolean operations not, bool and otherwise along with the operators || and && should not receive special treatment.
Haskell does not treat them differently (for instance with respects to precedence and other syntactic concepts) and so I feel we should not either (the same way we disabled special highlighting for prelude functions).

Besides I think there's already a lot of colour floating around here so I don't think adding more makes anything easier to read. Let me know if you'd like to submit a PR for that change otherwise I'm putting it on my agenda.

In actuality I'd really like to hear from a beginner Haskell programmer how they feel about special highlighting for "standard" functions and operators (and by "standard" I mean a stable, useful subset of Prelude functions and operators, such as || and not which every old, new and custom Prelude tends to have and which are used frequently).

As for the JSON language configuration. I'd tend to agree that a JSON formatted config is easier to read, maintain and reason about because there's less syntax clutter. If vscode accepts a JSON grammar I'll merge a PR for this if you send me one.

@phil-lgr
Copy link

phil-lgr commented May 22, 2018

@JustusAdam thank you so much for this extension.. I'm doing Haskell for the first time and it's.. brutal, but this extension helps a lot, great work!

@dsifford regarding the brackets..

I suggest to try: Bracket Pair Colorizer

Definitely helps with Haskell:

image

My biggest trouble when reading Haskell is differentiating constructor and functions from variables or arguments:

image

here the function, the arguments, the constructor Lcall are all of the same color, it makes reading Haskell code very difficult for beginners.. because you have to spot where the functions are vs Constructors vs arguments vs variables.

Let me know if I can help in any way 🙏

@JustusAdam
Copy link
Owner

@phil-lgr That is an issue of your theme, not the Haskell highlighting. I cannot, unfortunately, directly influence how things are highlighted I can only make suggestions to the theme. If you choose a different theme ("Monokai" for instance) it will actually highlight the constructors 😉

@nanlan2017
Copy link

As @phil-lgr said, Is it possible to differentiate functions from variables or arguments ? I used TM Scope to inspect these elements , they're all recognized as "source.haskell".

@JustusAdam
Copy link
Owner

@nanlan2017 You mean top level function declarations? Like this one?

foo argument = body

You want foo to be highlighted?

@phil-lgr
Copy link

phil-lgr commented Aug 1, 2018

I'm using https://www.monokai.pro/ and yes.. it would be really nice

@JustusAdam
Copy link
Owner

So first of all, I don't think it is a good idea to highlight functions specifically. Haskell makes no distinction between functions and data (apart from a bit of syntactic sugar) and so neither should we. However that's not the real problem.

The grammar possibilities in vscode are somewhat limited. Specifically highlighting top level identifiers is tricky, if the = sign is one a following line. I'm not even sure if it is possible (because template Haskell also exists).

So we could highlight

foo arg = bar

But not

foo arg 
  = bar

Which is common syntax, especially when the argument patterns are longer.

I think this would lead to very confusing behaviour of the highlighter.

@sheaf
Copy link
Collaborator

sheaf commented May 6, 2020

Closing as syntax highlighting for prelude functions/types has since been removed.

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

No branches or pull requests

6 participants