Skip to content

Instantly share code, notes, and snippets.

@OdatNurd
Created March 29, 2018 17:51
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save OdatNurd/0b69ee70f8b1a5bc1bcddd11b8c28fa5 to your computer and use it in GitHub Desktop.
Save OdatNurd/0b69ee70f8b1a5bc1bcddd11b8c28fa5 to your computer and use it in GitHub Desktop.
Allows placement of Sublime snippet overrides in the User folder, automatically creating empty overrides to mask the packaged version
import sublime
import sublime_plugin
import os
import textwrap
# Related Reading:
# https://forum.sublimetext.com/t/overriding-default-latex-snippet-in-user-folder-not-working/35900
# Sometimes a package (including those shipped with Sublime) contains snippets
# that a user would like to alter; for example to match their own code style.
#
# Although this is possible with a package override, doing so requires you to
# recreate your overrides on all machines where you use Sublime, which is an
# extra step that could get out of sync.
#
# Placing your customized snippets in your User package mitigates this problem
# but brings with it the problem of having all such snippets appear twice, once
# in the User package and once in the original package.
#
# This plugin helps with this situation by allowing you to place snippet
# overrides directly into the User package using the same structure as you
# would use for a regular override.
#
# When executed, the plugin finds all snippets in the User package that mimic a
# snippet in another package and will create an empty override for that
# snippet, which will cause Sublime to ignore the packaged version of the
# snippet.
#
# As written here, this occurs every time the plugin is loaded and also when
# you execute the command, which could be added to the command palette or a
# menu entry as desired.
#
# To use it, move all of your snippet overrides into your User package or
# create new ones there, then drop the plugin into your User package. Note that
# to work the snippet must appear in the User package exactly as it appears
# in the original package. For example:
#
# Packages/User/Python/Snippets/for.sublime-snippet
#
# Keep in mind that in use the empty snippets this creates will block the
# original package snippets, even if the original package is updated. For this
# reason you may want to use OverrideAudit so that you can detect when this
# is happening. OverrideAudit is available from:
# https://packagecontrol.io/packages/OverrideAudit
def plugin_loaded():
"""
Runs the custom command at every plugin load (e.g. at Startup) to keep
everything up to date; could optionally do this only if there is a setting
set, or remove it entirely to require more direct action.
"""
_update_user_snippet_overrides()
def _create_empty_snippet(res_path, override_path):
"""
Try to create an empty snippet file at the provided path; returns the
success or failure of the operation and also displays a message about the
operation to the console for tracing purposes.
"""
try:
os.makedirs(os.path.split(override_path)[0], exist_ok=True)
open(override_path, 'a').close()
print("{plugin}: Created empty snippet for '{file}'".format(
plugin=__name__, file=res_path))
return True
except Exception as error:
print(textwrap.dedent("""
{plugin}: Error creating empty snippet for '{file}':
{plugin}: {err}""").lstrip().format(
plugin=__name__, file=res_path, err=error))
return False
def _update_user_snippet_overrides():
"""
Treats the User package as if it was the Packages folder and finds all
snippets whose path and name exactly match a snippet in an external
package.
For each snippet, if there is not already an unpacked version of that
snippet, a new empty file is created as a package override, blocking
Sublime from seeing the base snippet in favor of the version in the User
package instead.
This allows you to override snippets from other packages by placing the
overrides directly in your User package, to make syncing your
customizations between multiple computers easier.
"""
all_snippets = {file[file.index('/')+1:] for
file in sublime.find_resources("*.sublime-snippet")}
user_snippets = {file[file.index('/')+1:] for
file in all_snippets if file.startswith("User/")}
overrides = user_snippets & all_snippets
update = 0
error = 0
for snippet in overrides:
snippet_path = os.path.join(sublime.packages_path(), snippet)
if not os.path.exists(snippet_path):
if _create_empty_snippet(snippet, snippet_path):
update += 1
else:
error += 1
if update or error:
sublime.message_dialog(textwrap.dedent("""
Message from: {plugin}
Created empty overrides for User package snippets:
Created: {update}
Failed: {error}
See the console for details.
""").lstrip().format(plugin=__name__, update=update, error=error))
class CheckUserSnippetOverridesCommand(sublime_plugin.ApplicationCommand):
"""
Simple user facing command that executes the plugin manually at the user's
request.
"""
def run(self):
_update_user_snippet_overrides()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment