-
Notifications
You must be signed in to change notification settings - Fork 586
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
[Go] syntax rework #1662
[Go] syntax rework #1662
Conversation
* Contextual types. Types are scoped where types are expected. There's no whitelist of "known" types. * Better understands the language and its syntax. Better at handling whitespace and comments inside complex forms. Better at handling other nuances. Unlikely to be confused by unusual code style. * Vars and consts in the root scope are added to the symbol index and searchable by ⌘R, ⌘⇪R, and `goto_definition`. * Supports parenthesized `type (...)` groups, not just `const (...)` and `var (...)`. * The first argument to `new` and `make` is scoped as a type. * Methods declared inside an `interface` are added to the symbol index, reflecting the fact that they actually exist as functions. * Supports embedded structs. * Supports inherited interfaces. * Supports imaginary number literals. * Variable declarations are scoped differently from other variable occurrences. * `iota` is scoped only in constant initialization expressions. * Symbols in ⌘R are annotated with their origin: `var`, `const`, `type` or `func`. * Auto-pairing of backticks. * Much more comprehensive tests. * All keywords and predeclared identifiers are added to auto-completions by default. * Better snippets that don't mess with auto-completion. * Slightly better indentation rules that more closely match `gofmt`. Current shortcomings (?): * Fewer meta scopes: needs feedback. * No support for block labels: needs feedback.
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.
Did a small review of everything that's not the actual syntax definition or test file(s).
}, | ||
{ "keys": ["backspace"], "command": "run_macro_file", "args": {"file": "res://Packages/Default/Delete Left Right.sublime-macro"}, "context": | ||
[ | ||
{ "key": "setting.auto_match_enabled", "operator": "equal", "operand": true }, |
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.
Doesn't have a selector
context specifier.
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.
Thanks, added the missing selector.
|
||
{ "keys": ["enter"], "command": "run_macro_file", "args": {"file": "res://Packages/Default/Add Line in Braces.sublime-macro"}, "context": | ||
[ | ||
{ "key": "setting.auto_indent", "operator": "equal", "operand": true }, |
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.
Also doesn't have a selector
context specifier.
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.
Thanks, added the missing selector.
|
||
"completions": [ | ||
// https://golang.org/ref/spec#Keywords | ||
"break", |
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.
I suggest adding a description for these completions, i.e. keyword
. See http://docs.sublimetext.info/en/latest/reference/completions.html.
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 the docs don't mention any descriptions.
Apparently, some completions in the standard packages use tab-separated triggers: word\tdescription
. Tried this; it looks cool in the completion list, but suppresses the normal buffer completions, which is exactly what you don't want, especially in a standard package. If we could add descriptions without messing things up, I'd love to.
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.
Played with generating sublime-snippet
files for these completions. Snippets have descriptions and don't suppress normal buffer completions. They also don't appear when you just hit ^Space
or equivalent to bring up the completion list. The downside is that they clog up the Command Palette.
Really the problem is that even one sublime-completion
with a tab-separated description completely suppresses buffer completion. It's ridiculous and wrong.
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.
Meh, sounds like sublimehq/sublime_text#1061 is striking again. I thought tab triggers wouldn't affect it.
Or maybe it is actually a different issue, but that would be surprising.
@@ -0,0 +1,11 @@ | |||
{ | |||
// Prefer tabs because gofmt enforces tabs. | |||
"translate_tabs_to_spaces": false, |
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 is certainly debatable, but I don't have insight on whether people write Go without gofmt.
Go/Go.sublime-settings
Outdated
// Prefer tabs because gofmt enforces tabs. | ||
"translate_tabs_to_spaces": false, | ||
// Trigger autocompletion on dot access. | ||
"auto_complete_triggers": [ |
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.
Many packages use dots for attribute access, however none of them defines auto_complete_triggers
. I'm not sure whether they should or should not, but this is something we should discuss, imo.
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 certainly could be removed. I'll run without this setting for a few days to get a feel.
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.
Removed the trigger setting for now.
<dict> | ||
<key>scope</key> | ||
<string> | ||
variable.other.constant.declaration.go - meta.block.go |
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.
entity.name.constant.go
would be more appropriate, assuming the syntax definition is updated as well.
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.
Agreed. The problem is that applying different const/var scopes depending on whether we're inside a block seems to require lots of duplication in the syntax; not sure it's worth it.
@@ -0,0 +1,16 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> |
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.
You can define both, the indexed and non-indexed symbols, in the same file, assuming their scope selectors are equal. This applies to the other files as well.
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.
These are defined in separate files to keep symbolTransformation
from applying to the indexed symbols and messing up "goto_definition". I'd love to be able to merge the files, but it doesn't seem possible while keeping the current rule logic.
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.
Can you confirm that symbolTransformation
does indeed affect the symbol that is used for the index if showInIndexedSymbolList
is set? Previous experience doesn't indicate so (and neither to the docs derived from that).
Even with two different files, since the scope selectors are the same it would have the exact same effect as all the meta settings will be set on any token that is matched.
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.
Interesting! I double checked, and indeed, it looks like symbolTransformation
doesn't affect indexing. Must have mixed it up with something else when I was writing this.
Merged some of the symbol files. Thanks!
* consistent with other syntaxes for C-style languages
Something I did for my YAML rework was to have a sample file containing lots of examples with bad highlighting in the original and then providing a Screenshot of that file being rendered with and without the pr to give a better before-after comparison (#90). |
@FichteFoll Nice idea. Added comparison screenshots. |
* support negative exponents * support fractional notation in complex numbers * punctuation scopes for dot and exponent * storage scopes for octal and hex prefixes
Hi, |
@cskujbus An excellent point. I followed the established convention of scoping type keywords the same as type names, but frankly, it makes no sense whatsoever. Perhaps we should break with the convention, and ask the rest of the syntax developers to follow suit. |
I’m not inclined to revamp the scope names for function and class keywords. Most languages that use those have the ability to treat such as first class citizens, so I think it makes sense the keywords are scoped as |
For now, I suppose the best action forward is to scope them as |
My inner language-author/syntax-author/Lisper feels that all language keywords should have a unified scope, so that a simplified color scheme can consistently mark them as keywords, without special-casing the various Satisfying both use cases requires the scope on keywords like I would propose Long story short: what if we scope all type keywords, such as Addendum for consistency with the argument above. I don't see a reason why |
@mitranim thank you for this detailed explanation, I just wanted to know the reasoning behind classifying some keywords as storage types (VS Code for example seems classifying all Go keywords in the same scope). |
Co-Authored-By: Mitranim <me@mitranim.com>
Type keywords now use "storage.keyword" rather than "storage.type". This distinguishes them from type names while keeping the "storage" prefix. This is consistent with the default coloring for most other languages, but a color scheme can also choose to treat them like regular keywords. This commit also changes "var" and "const" from "storage.modifier" to "storage.keyword", for logical consistency with the change above.
Added punctuation scopes for comment start and comment end. Added more detailed annotation meta scopes. Also by @deathaxe, see mitranim/sublime-gox#1
I really wanted to merge this for the next dev build, but it is extensively using I don't want to break a bunch of syntax coloring for users, and thus am not inclined to merge this since it takes scope names in a new direction that is different (in a major way) from all of the syntaxes that have been working on over the past couple of years. For consistency sake, I want new syntax work to be consistent with other actively maintained syntaxes. So to merge this, we would have to revamp scope names in a bunch of syntaxes, change the standard and revamp color schemes. |
Glad to see you back in action, @wbond! I've updated the |
I suppose replacing storage.type.keyword.function with storage.type.function would be appropriate, which is used across multiple syntaxes iirc. And similar occurances. Not sure about interface and const, however. |
I am more inclined for that format @FichteFoll. The impression I get is that @mitranim is trying to make it possible to color |
I'd rather get this merged and we can discuss subtle changes to scope later. |
Just updated my Sublime build. One thing I have noticed is the new highlighting used for types within a package. For example: From what I can tell, both the native type It may just be that I am not used to the change, but I think I would prefer to be able to highlight them differently. Previously |
(This is what I know from other syntaxes and is how I understand the scope names, which may be wrong) |
Thanks for asking. This is an important difference between my syntaxes and most other ST built-ins. I've been meaning to raise this topic for a while now. For the language user, there's no functional difference between predefined and user-defined types. Standard library types like The idea of treating types differently is so weird, I can't even comprehend where it's coming from. Maybe it's inertia from syntaxes that wanted but couldn't scope types properly? Modern general-purpose languages are explicitly designed to be extensible. Complicated programs tend to develop their own DSLs, speaking mostly in their own "language", often supplanting built-in types and idioms. Treating all types equally, exactly the way the language does, supports this notion. A syntax's job is to reflect the language. When the language treats all types equally, so does the syntax. Yes, many built-in ST syntaxes have these weird ideas about "built-in" and "support" types. This doesn't make them any less wrong. I plan to convince other syntax developers to revise this notion across all standard packages. |
Not sure about the origin, but this is just the existing way to achieve @ccampbell 's request. I honestly find it helpful to see language defined functions ( You are right with But the possibility to distinguish between atomic and complex types should be applied anyway. Maybe something like |
I'm in favor of scoping builtin types and functions. It must be admitted that scoping builtins is not a truly syntactic concern. In most languages, a built-in function or type is parsed exactly the same as any other type. You can have a completely accurate syntax definition that doesn't scope any builtins at all. On the other hand, to the extent that builtins are defined by the language itself, I think that it's useful to use scopes to distinguish them. One reason is that builtins generally don't have lexical declarations, so when I see something highlighted as a builtin, I know not to look for one. In the absence of full language-specific intellisense, builtin highlighting also serves as a first line of defense against typos. I think that support scopes should be purely additive. That is, a builtin function should be scoped just like any other function, plus whatever extra scope builtins get. The core syntaxes don't all do this, and I think they should. For one thing, this makes it easier for users who don't want builtin highlighting to modify their color scheme to disable it. What builtins deserve highlighting? The answer surely depends on the language. In JavaScript, there is a fixed set of global types and functions that do not need to be included and are available in any environment. These, I think, should be scoped. There are also many other global builtins available in other environments, such as web browsers. I'm not convinced that these should be scoped in the core language. For JavaScript, I'm planning to write an extension for JS Custom to allow users to choose between sets of builtins (like browser/node) and to add their own. |
This is becoming somewhat off-topic and approaching RFC levels. I suggest to summarize a few options and formulate those into a proposal in a several issue. I also have a thing or two to say about this, later. After all, this doesn't just affect Go. |
@Thom1729 thanks for the explanation. These points make a lot of sense. I like the idea of built-ins scoping being purely additive. Reserving it for a small, rarely-expanded set of language built-ins, rather than any "library" APIs like the DOM, also seems like a no-brainer. Getting back to Go. Unlike most languages, it lets you tell apart, on a glance, local/external and private/public definitions:
Syntactically, built-ins overlap only with private local definitions. In addition, the number of built-in types and functions is fairly small and easy to remember. Since I still don't understand the benefit of additional "builtin" or "support" scoping, my default preference would be to stick with |
This PR is a complete rework of the Go syntax.
Improvements:
Contextual types. Types are scoped where types are expected. There's no whitelist of "known" types.
Better understands the language and its syntax. Better at handling whitespace and comments inside complex forms. Better at handling other nuances. Unlikely to be confused by unusual code style.
Vars and consts in the root scope are added to the symbol index and searchable by ⌘R, ⌘⇪R, and
goto_definition
.Supports parenthesized
type (...)
groups, not justconst (...)
andvar (...)
.The first argument to
new
andmake
is scoped as a type.Methods declared inside an
interface
are added to the symbol index, reflecting the fact that they actually exist as functions.Supports embedded structs.
Supports inherited interfaces.
Supports imaginary number literals.
Variable declarations are scoped differently from other variable occurrences.
iota
is scoped only in constant initialization expressions.Symbols in ⌘R are annotated with their origin:
var
,const
,type
orfunc
.Auto-pairing of backticks.
Much more comprehensive tests.
All keywords and predeclared identifiers are added to auto-completions by default.
Better snippets that don't mess with auto-completion.
Slightly better indentation rules that more closely match
gofmt
.Current shortcomings (?):
Fewer meta scopes: needs feedback.
No support for block labels: needs feedback.
While this syntax is ready-to-use and fairly complete, I expect the current maintainers, particularly @wbond who's responsible for the current version of the Go syntax, to have many qualms and request many changes. Arguably, this version has some "regressions", particularly where meta scopes are concerned. This needs feedback and discussion, as I don't fully understand what role many of those meta scopes were intended to serve.
While the PR is pending, the syntax is available standalone: https://github.com/Mitranim/sublime-gox
Screenshot before-after:
Screenshot of symbol index before-after:
(Many other differences didn't fit into the screenshots. This uses my Cloud color scheme, available at https://github.com/Mitranim/sublime-themes.)