Packages: Get rid of snippets directories in default language packages

Created on 9 Jun 2019  Â·  13Comments  Â·  Source: sublimehq/Packages

A much easier way of resolving the issue that motivated this issue in the ST Core repo: https://github.com/SublimeTextIssues/Core/issues/901

Screen Shot 2019-06-09 at 10 34 20 AM

The default language packages should not ship with snippets. Languages change, and the snippets get outdated. People don't write JS the way they did in 2012. Most of these JS snippets are useless and/or bizarre.

I think whoever has write access to the default language packages ought to just remove snippets from all of them.

Most helpful comment

As I see it, the core packages should not generally be opinionated.

Syntax highlighting is a great example. For instance, the Python syntax is useful for anyone using Python. It supports many versions of Python, and it isn't designed to favor any particular style of Python code. When it does make compromises, those compromises are as generic as possible: scoping annotations as types, highlighting placeholders in strings, and so on.

More opinionated syntax highlighting is likely to cause problems for users. For instance, the JavaScript syntax currently marks functions named escape and unescape as invalid.deprecated. This was intended to highlight inappropriate use of deprecated functionality, but it causes problems for users who name their own functions escape and unescape. (#1929) In another example, the JavaScript syntax has long given special treatment to dollar signs in identifiers, even though the language itself does not. This is convenient for users of the jQuery framework, which was once ubiquitous. However, even though jQuery use is declining in favor of newer frameworks, an attempt to remove the special cases in the syntax was met with a significant backlash from users used to the old behavior.

I take from this two lessons:

  1. We shouldn't add highly opinion-based functionality to the core packages.
  2. When such functionality exists, it is risky to change it.

Snippets are inherently opinionated. For instance, consider the JavaScript for snippet:

for (var i = Things.length - 1; i >= 0; i--) {
    Things[i]
}

This isn't wrong, but it isn't the way that I would write it. It isn't the way that most people would write it. There probably isn't any single way that most people would write it, accounting for details like variable names, spacing preferences, semicolons, and so on. In other words, even though the snippet isn't per se wrong, it's nevertheless wrong for most members of its target audience (i.e. Sublime users writing JavaScript for loops).

This snippet might be an extreme example, but the principle applies: snippets are not generic in the same way as syntax definitions, tmPreferences files, and so on. This also makes maintaining snippets problematic. You fix a syntax definition when there's a bug or when new language features appear. What is the process to updating a snippet? A new version is merely a new opinion; mostly, it will annoy the users who liked the old opinion.

This is to say that in the hypothetical universe in which Sublime did not ship snippets in the default packages, I don't think that we should hypothetically start now. In this universe, the question is a bit thornier. The snippets are here, and we can't effectively maintain them for the reasons given above. (The fact that most of them have sat without modification for three years may serve as evidence for that point.)

There's a high bar to adding new functionality to the default packages (as opposed to, e.g., improving syntax definitions). The bar to removing existing features should be equally high. In order to remove the snippets, it's not enough that the snippets are not universally helpful. Even a feature that is completely useless is, in itself, merely neutral to the user experience and can safely be left in place indefinitely. Are unwanted snippets actively deleterious to the user experience? If they could easily be disabled, then so they could be ignored. But snippets can't be disabled in a straightforward manner — they don't take an arbitrary context, and there's no way to ignore resources in a granular fashion. (That might be a nice feature, but it's a feature we don't have, and it's rather out of scope of the present discussion.)

Are the core snippets truly an active misfeature? This, also, is ultimately a matter of opinion. But if I can speak only of my own feelings, then, yes, it is. When I see for expand to:

for (var i = Things.length - 1; i >= 0; i--) {
    Things[i]
}

I cringe internally:

  • Why an indexed for loop instead of for … of?
  • Why var and not let?
  • Where's the semicolon?
  • Why are we iterating backward? This saves one (1) CPU instruction in C, and most likely does absolutely nothing helpful in JavaScript.
  • If we're trying that hard to save one single instruction, why are we not caching the property access Things.length?

Again, every single one of these complaints is a matter of opinion. There is no way to fix the snippet without making another set of JavaScript developers cringe for entirely different reasons. There is no happy medium for something as subjective and inherently opinionated as snippets.

What, then, are our options?

  1. Leave the snippets in place as they are.
  2. Update them to 2019 consensus best practices (whatever those may be).
  3. Move the snippets to a separate core package that can be ignored.
  4. Move the snippets outside the default packages.

I think that (2) is the worst of both worlds: core snippet users don't like that they've changed, and plenty of non-users still have to deal with snippets they don't like. (4) is ideal in theory, but a bit risky in practice: it could be a breaking change for some users. (1) is always an option, of course, but if the current state of the snippets didn't bother users, then this issue wouldn't exist.

(3), then, seems a reasonable compromise. Users who like the core snippets can use them and everyone else can easily ignore them. It's hard to see a downside relative to the current approach. Users who currently ignore snippets the hard way would be forced to do it the easy way, which is the sort of change it's hard to get upset about. A graceful migration path might be as follows:

  1. Move the snippets to a new default package, “Snippets — Legacy”.
  2. Add that package to the default ignored_packages.
  3. Add a separate package on Package Control containing the old functionality.
  4. Remove the “Snippets — Legacy” package.

All that said, I can imagine that some functionality currently available as snippets might be worth preserving in the default packages, such as the minimal HTML5 template. But I have my own opinions on templating.

All 13 comments

Also, I originally created this issue in the wrong repo, so I'm going to reproduce comments from that thread:

From @frou

I agree that some dood coming up with snippets they personally thought were kinda neat, is not a high enough bar for those to be in everyone else's face forevermore.

I mean why is there a goofy wordplay on Common Lisp terminology in the Go package? Whoever comes up with these things should just keep them to themselves in their User package.

from @keith-hall

We had a small discussion about this on Discord about a month ago. Some functionality should definitely still be included by default - not necessarily in the form of snippets though - like the html Tab snippet. Perhaps that one could be replicated with a keybinding that triggers on Tab if the syntax at the caret is plain text or html and would insert the html template (which would have to be provided as a package resource I guess, unless we can still bundle snippets but without tab triggers by default). It would ofc mean that users relying on snippets being available in the command palette or more easily discoverable through autocompletion would have their workflow interrupted. Or maybe just better to vote on which snippets to remove or keep?

This could be resolved like what happened with the legacy Colour Schemes:

Move all of the code snippet files out of this repo and put them into a single package that can be easily installed by those who still want them.

Here's a PR that gets rid of Python and JavaScript snippets to get the ball rolling: #1989

Move all of the code snippet files out of this repo and put them into a single "Snippets - Legacy" package that can be easily installed by those who still want them.

I was going to propose something similar. I very much like the idea of making this a "Legacy" package and allowing users to opt in to using these snippets.

Regarding snippet "quality", at least with regard to JS and Python: even if these snippets were "great", I think forcing the same set of snippets on all ST users is a bad design choice, especially because snippets are difficult to disable, and impossible to disable in a way that requires no future maintenance.

I don't care if Guido van Rossum himself wrote the Python snippets. I (and probably most ST users) don't want to see for loop snippets every time I type an f. If I wanted to, I'd download some specific snippets package, or copy a few snippets from some snippets package, or write my own. Snippets are very easy to write.

This issue should be marked [RFC]. I have more thoughts, but I should take the time to collect them.

As I see it, the core packages should not generally be opinionated.

Syntax highlighting is a great example. For instance, the Python syntax is useful for anyone using Python. It supports many versions of Python, and it isn't designed to favor any particular style of Python code. When it does make compromises, those compromises are as generic as possible: scoping annotations as types, highlighting placeholders in strings, and so on.

More opinionated syntax highlighting is likely to cause problems for users. For instance, the JavaScript syntax currently marks functions named escape and unescape as invalid.deprecated. This was intended to highlight inappropriate use of deprecated functionality, but it causes problems for users who name their own functions escape and unescape. (#1929) In another example, the JavaScript syntax has long given special treatment to dollar signs in identifiers, even though the language itself does not. This is convenient for users of the jQuery framework, which was once ubiquitous. However, even though jQuery use is declining in favor of newer frameworks, an attempt to remove the special cases in the syntax was met with a significant backlash from users used to the old behavior.

I take from this two lessons:

  1. We shouldn't add highly opinion-based functionality to the core packages.
  2. When such functionality exists, it is risky to change it.

Snippets are inherently opinionated. For instance, consider the JavaScript for snippet:

for (var i = Things.length - 1; i >= 0; i--) {
    Things[i]
}

This isn't wrong, but it isn't the way that I would write it. It isn't the way that most people would write it. There probably isn't any single way that most people would write it, accounting for details like variable names, spacing preferences, semicolons, and so on. In other words, even though the snippet isn't per se wrong, it's nevertheless wrong for most members of its target audience (i.e. Sublime users writing JavaScript for loops).

This snippet might be an extreme example, but the principle applies: snippets are not generic in the same way as syntax definitions, tmPreferences files, and so on. This also makes maintaining snippets problematic. You fix a syntax definition when there's a bug or when new language features appear. What is the process to updating a snippet? A new version is merely a new opinion; mostly, it will annoy the users who liked the old opinion.

This is to say that in the hypothetical universe in which Sublime did not ship snippets in the default packages, I don't think that we should hypothetically start now. In this universe, the question is a bit thornier. The snippets are here, and we can't effectively maintain them for the reasons given above. (The fact that most of them have sat without modification for three years may serve as evidence for that point.)

There's a high bar to adding new functionality to the default packages (as opposed to, e.g., improving syntax definitions). The bar to removing existing features should be equally high. In order to remove the snippets, it's not enough that the snippets are not universally helpful. Even a feature that is completely useless is, in itself, merely neutral to the user experience and can safely be left in place indefinitely. Are unwanted snippets actively deleterious to the user experience? If they could easily be disabled, then so they could be ignored. But snippets can't be disabled in a straightforward manner — they don't take an arbitrary context, and there's no way to ignore resources in a granular fashion. (That might be a nice feature, but it's a feature we don't have, and it's rather out of scope of the present discussion.)

Are the core snippets truly an active misfeature? This, also, is ultimately a matter of opinion. But if I can speak only of my own feelings, then, yes, it is. When I see for expand to:

for (var i = Things.length - 1; i >= 0; i--) {
    Things[i]
}

I cringe internally:

  • Why an indexed for loop instead of for … of?
  • Why var and not let?
  • Where's the semicolon?
  • Why are we iterating backward? This saves one (1) CPU instruction in C, and most likely does absolutely nothing helpful in JavaScript.
  • If we're trying that hard to save one single instruction, why are we not caching the property access Things.length?

Again, every single one of these complaints is a matter of opinion. There is no way to fix the snippet without making another set of JavaScript developers cringe for entirely different reasons. There is no happy medium for something as subjective and inherently opinionated as snippets.

What, then, are our options?

  1. Leave the snippets in place as they are.
  2. Update them to 2019 consensus best practices (whatever those may be).
  3. Move the snippets to a separate core package that can be ignored.
  4. Move the snippets outside the default packages.

I think that (2) is the worst of both worlds: core snippet users don't like that they've changed, and plenty of non-users still have to deal with snippets they don't like. (4) is ideal in theory, but a bit risky in practice: it could be a breaking change for some users. (1) is always an option, of course, but if the current state of the snippets didn't bother users, then this issue wouldn't exist.

(3), then, seems a reasonable compromise. Users who like the core snippets can use them and everyone else can easily ignore them. It's hard to see a downside relative to the current approach. Users who currently ignore snippets the hard way would be forced to do it the easy way, which is the sort of change it's hard to get upset about. A graceful migration path might be as follows:

  1. Move the snippets to a new default package, “Snippets — Legacy”.
  2. Add that package to the default ignored_packages.
  3. Add a separate package on Package Control containing the old functionality.
  4. Remove the “Snippets — Legacy” package.

All that said, I can imagine that some functionality currently available as snippets might be worth preserving in the default packages, such as the minimal HTML5 template. But I have my own opinions on templating.

Thanks for taking the time to think this through, this is a really great write-up.

I concur on option 3) being the best option, in that it doesn't break snippets for users that currently depend on them, but also makes it trivial to disable them.

@Thom1729
What's the process for getting something like this approved? I would be super happy create a PR that takes all the snippets and moves them into their own package.

The first thing to do is to let the discussion sit and accumulate more input. It might be some time before the next series of dev builds, which is the earliest possible opportunity for a change to happen. If a consensus develops, then a PR might be appropriate.

@wbond would presumably make the final call either way. From Sublime HQ's perspective, there may be other reasons to go with one option over another.

@Thom1729 Given your option (3) [which I agree is a good way forward], why are steps 2-4 in your subsequent list necessary? After step 1, people who like the snippets or have no strong opinion needn't do anything, and people who don't like them could codify that by manually modifying ignored_packages. Job done?

The idea is to phase out the default snippets, which means they eventually need to become not the default. By adding it to the default ignored_packages settings, new users of ST won't be confronted with the snippets anymore while anyone that modified their settings list at least once (e.g. by installing a single package with PC) would be unaffected by the step.

After the snippets have then officially been deprecated, they could slowly be removed from the default distribution entirely and require manual intervention from interested users (3-4).

I don't feel comfortable with the idea of putting all snippets into a single "Snippets - Legacy" package, because it means all or nothing. Snippets should be able to be enabled/disabled per syntax.

So here is an idea of how to achieve something like (3) with the existing infrastructure.

All snippets are located in dedicated sub directories for each syntax and thus can be easily identified. Sublime Text's build process already creates dedicated packages for each syntax.

So why not creating two packages per syntax?

1) <Syntax Name> Syntax.sublime-package
2) <Syntax Name> Snippets.sublime-package

The Syntax package contains everything except the snippets folder of a syntax.
The Snippets package contains the content of the snippets folder of a syntax.

According to the changelog fixed in Build 4050.

Use ignored_snippets to disable default snippets.

According to the changelog fixed in Build 4050.

4050? Has the Sublime Text 4 train started?

We do have a limited beta of "Sublime Text" published, although we have only published it in low-traffic communication channels for the project. This is an effort to help iron out some of the bigger issues before a wider release. I'm sure with a little looking you can find it. :-)

Was this page helpful?
0 / 5 - 0 ratings