15. Packages
Packages are simply a set of Resource Files used by Sublime Text, gathered into a single directory named after the Package.
A Package Resource is simply a Resource File that is part of a Package and therefore in a Package directory.
Another (more compact) form they can come in (e.g. the shipped Packages and most
user-installed Packages are in this form) is in a .sublime-package file,
which is simply a .zip file containing all the files of that package, preserving
the Package’s directory structure.
Compressed or not, any package file can be viewed using:
Tools > Command Palette... > View Package File
Files retrieved from a compressed file will be read-only, but may be saved as editable files using.
File > Save As...
(They remain read-only until they are closed and then re-opened again from where they were saved.)
Be advised: if there is a .sublime-package, as well as a loose file in a
<data_path>/Packages/<pkg_name>/ directory, the contents of the loose file
will override the ENTIRE file stored in the .sublime-package file. See
Overriding below for more details.
Sublime Text ships with over 50 Packages pre-installed, and many, many user-created Packages are available through several channels, the easiest of which is using the Package Control Package, which provides very easy management of the Packages you have installed with any given Sublime-Text installation.
15.1. Sublime Text Packages vs Python Packages
As it turns out, the name “Package” in Sublime Text’s Python context is indeed
aptly chosen: Sublime Text indeed “considers” a Sublime Text Package
as a Python Package, despite its not having a __init__.py file in it, which is
normally what makes a Python Package a Package.
Rationale: From your Sublime Text Package, you can do relative importing, which is ONLY legal from within a Python Package, and generates an exception when it is used outside of a Python Package.
from . import sibling_module
This is logical actually, since the importlib package (comes with Python, and is
used “under the covers” as the implementation of the import statement) allows
directly importing of Python modules as packages whether they have a
__init__.py file in them or not. So I suspect that is the mechanism being used
by Sublime Text for “bringing in” individual Python plugins as part of a
package named after the parent directory, and is probably also why the Sublime
Data/User/ directory is sometimes referred to as the “User Package”.
And why shouldn’t Sublime Text use that powerful mechanism? It’s Python’s way of making new functionality available safely under its own namespace.
Indeed, API Environments Overview describes the environment Plugins are run in, and the 3rd paragraph hints strongly that it indeed treats a Sublime Text Package as a Python Package.
15.2. Locations
The concept of a “Packages Directory” is really 5 possible locations for any given Package Resource File.
- Default Package:
Loaded first;
Default.sublime-package[1]Represented location: <data_path>/Packages/Default/
Actual location: <executable_path>/Packages/
- shipped Packages:
Loaded next (alphabetically by Package name);
<pkg_name>.sublime-packagefiles shipped with Sublime Text are stored here. (Do not change this directory’s contents.) [1]Represented location: <data_path>/Packages/<pkg_name>/
Actual location: <executable_path>/Packages/
- installed Packages:
Loaded next (alphabetically by Package name); Packages installed by user are stored here when they are designed to remain in
.sublime-packageformat. [1]Represented location: <data_path>/Packages/<pkg_name>/
Actual location: <data_path>/Installed Packages/ (not editable)
- unpacked Packages:
Loaded next (alphabetically by Package name); Packages installed by the user when designed to be unpacked (loose files) by Package Control, as well as user-created Packages can be stored here.
Represented location: <data_path>/Packages/<pkg_name>/
Actual location: same (on disk, Resource files editable)
(See note below.)
- User Package:
Loaded last; <data_path>/User/. Customizations unique to each user are stored here. Path representation:
Packages/User/.Represented location: <data_path>/Packages/User/
Actual location: same (on disk, Resource files editable)
If you are a power user, your customizations will go in the latter 2 directories.
The User Package can be used to develop new packages while they are in
experimental stages. Once in a more complete state, they can be moved to
<data_path>/Packages/<pkg_name>/.
15.3. Overriding
The above loading sequence is how “overrides” or customized behavior are implemented.
Note carefully that when the Package (including the User Package) has a file like
Default (Windows).sublime-keymap or Main.sublime-menu, it does not replace
the whole Keymap or Main Menu. In these cases, the overriding happens at a finer
level of granularity: these files contain JSON data structures (e.g. a list or tree
structure [respectively] of dictionary objects), and the value of each entry in the
data structure overwrites the already-loaded value for the entry with the same key
and hierarchy location in the data structure. So you can think of the contents of
both files as being “merged”, where due to the loading sequence outlined above, the
values loaded from the Packages lower in the list overwrite the same values from
Packages higher in the list. It is this sequence that governs what overrides what.
Note that the above-described “merge” override behavior is what happens between the
Package (including the User Package) and the Sublime Text application, and is
restricted to just some (not all) of the Resource Files
that contain Sublime-relaxed-JSON format data:
.sublime-commands
.sublime-completions
.sublime-keymap
.sublime-menu
.sublime-mousemap
.sublime-settings
But this does not apply to any of the other types of Resource Files:
.sublime-build
.sublime-color-scheme
.tmTheme
.sublime-macro
.tmPreferences
.py
.sublime-snippet
.sublime-syntax
.tmLanguage
.sublime-theme
15.3.1. Overriding Whole Files from a Zipped Package
Once you understand the “merge-type” overriding described above, it is important to understand that there is another type of overriding (whole-file overriding) that is triggered when:
the Package being overridden is in archive form (i.e. with
.sublime-packagefile extension, which will be either an installed Package or a shipped Package, andthe override file is placed in an unpacked Package directory (i.e. in <data_path>/Packages/<pkg_name>/ with an identical relative path and name).
In this case, Sublime Text literally ignores that same file from the
.sublime-package file and replaces it with loose file in the unpacked Package
directory.
In this case, the loose-file directory <data_path>/Packages/<pkg_name>/ is called an “Override Package”.
Illustrated:
<data_path>/Packages/Installed Packages/<pkg_name>.sublime-package, or
<executable_path>/Packages/<pkg_name>.sublime-package -----+
| loose file with
| same name and
| same relative
| subdirectory
<data_path>/Packages/<pkg_name>/... <--------------------------------+
When the Override Package directory is empty, it doesn’t change anything. But for
each occurrence of a file with the exact same relative subdirectory and filename as
in the .sublime-package file, Sublime Edit ignores the .sublime-package file
and uses the loose file in the Override Package instead.
An interesting aspect of Override Packages is that Python plugins therein are able to
use relative import paths for accessing other modules in the corresponding
.sublime-package file as if they were part of it.
Example: You want to add functionality to the Python Package’s def (function)
Snippet. Its default content is provided
in <executable_path>/Packages/Python.sublime-package.
The way to find the Snippet file that is involved, make a copy of the
Python.sublime-package file in a safe, empty directory, change its extension to
.zip and then extract the contents out of the file. Scan the package Snippet
files for
<tabTrigger>def</tabTrigger>or just>def<
and you will find it in the ./Snippets/ subdirectory as function.sublime-snippet.
Make a copy of that file and place it in
<data_path>/Packages/Python/Snippets/
then modify it to suit you. Sublime Text reloads it as soon as you save it so the turn-around time on modifications-to-testing is remarkably short.
Note
The following two Packages provide a convenient way to create an override of a single Package file. The Commands they provide that do this are:
PackageResourceViewer: Open Resource
OverrideAudit: Create Override
Both of these commands:
open the file in an editable form, with an “apparent” path <data_path>/Packages/<pkg_name>/<resource_file>, even though that file (and directory) may not exist yet, and
use the
Ctrl+S(Save file) operation to create the file if it is not already there, as well as create the new <data_path>/Packages/<pkg_name>/ directory if it did not already exist.
Note
Some packages are configured to be installed as loose files in the
<data_path>/Packages/<pkg_name>/. When this is the case, once they are
installed, the only instance of that Package is as loose files in that directory.
When this is the case, editing of those Package Resource files (when they
are not created by yourself) is not recommended because those files get replaced
when the Package is updated. If you wish to override only certain files in an
unpacked Package, you can create a .sublime-package file out of it by
zipping its contents, preserving the directory structure under the
<data_path>/Packages/<pkg_name>/
directory, naming the zipped file
<pkg_name>.sublime-package
and moving the newly-created file into the
<data_path>/Installed Packages/
directory. Then in the original (unpacked) directory (which now becomes
an Override Package because of the existence of the
<pkg_name>.sublime-package file where Sublime Text will load it), keep only
the files you wish to override.
Caution
A precaution about Override Packages: if/when the overridden file(s) in the
corresponding .sublime-package is updated, you will not be notified.
The OverrideAudit package provides monitoring of override files and will notify you when the file it overrides has been updated.
15.4. Creating New Packages
You create a new package by simply creating a directory under <data_path>/Packages/.
This directory is conveniently accessible via Preferences > Browse Packages....
15.4.1. A Package’s Python Version
As of Sublime Text build 4200, the default Python version used by a package is 3.3. However, Python 3.8 is available. To get your Package to use Python 3.8, place a file in the top directory of the package containing just 3 bytes: “3.8”.
MyPackage/
.python-version
15.5. Managing Package Complexity
As functionality is added to Packages being developed, they can become quite complex. (Sometimes they have complex designs to start with.) For increased maintainability (via modularity) it can be useful to move related groups of related functionality into their own Python modules.
Simpler Packages can factor out related functionality into their own sibling
(top-level) Python modules which make use of each others’ facilities via the from .
import sibling_module statement.
More complex Packages sometimes factor out related functionality as Subpackages for the same reason that Python supports Subpackages within Packages: modularity and maintainability—each Subpackage has its own sphere of responsibility. The method of doing this is exactly the same as implementing Python Subpackages. Usually developers will want to limit doing this to when it makes sense to do so: when the subpackage is relatively self-contained, providing its own data and/or services to the main Package, and (preferably) only depending upon external Packages that ship with Python. (What you don’t want is to have 2 or more modules that are circularly dependent upon one another. Doing that generates an exception while the Package is being loaded, and will thus prevent your Package from being loaded successfully.)
There is an important caveat to using Subpackages in a Sublime Text Package if
you have the Package Control Package installed (which is true for virtually all
Sublime Text installations). The reason for this is that the Package
Control Package automatically updates installed Packages while Sublime Text
is running, and when it does this, it does not re-start the Python Interpreter,
but instead uses importlib.reload() to reload the top-level Python modules
(.py files) in each installed Package that gets updated. If an updated Package
has Subpackages that might have been updated, those Subpackages do not get
automatically reloaded (with their possibly-updated logic) until Sublime Text
restarts. For Packages that will never change again, this is not an issue. However,
for packages that get updated periodically, when the update happens, until
Sublime Text is restarted, there is a risk of such Packages being in an
inconsistent state and possibly broken unless the Package itself addresses this
caveat internally.
Here is how to do it.
Let’s say your Package is called ProComment and is structured like this:
ProComment/
procomment.py <-- central Plugin
lib/
__init__.py
debug.py
utils.py
src/
__init__.py
core.py
contexts.py
func_parsing.py
commands/
__init__.py
insert_comment.py
insert_datestamp.py
insert_timestamp.py
Your central Plugin is named procomment.py and you have 3 Subpackages: lib,
src/ and src/commands/. In your central Plugin, implement something like
this:
""" procomment.py """
import importlib
import sys
import os
from typing import Tuple
# =========================================================================
# Data
# =========================================================================
_cfg_compressed_pkg_ext = '.sublime-package'
# Use name of parent directory as `package_name`.
module_path, _ = os.path.splitext(os.path.realpath(__file__))
parent_dir, submodule_name = os.path.split(module_path)
_, package_name = os.path.split(parent_dir)
if package_name.endswith(_cfg_compressed_pkg_ext):
package_name = package_name[:-len(_cfg_compressed_pkg_ext)]
del _
this_module_name = f'{package_name}.{submodule_name}'
_reload_indent_level = -1
# Can't use `debugging = is_debugging(DebugBit.IMPORTING)` here because
# the import required to support it causes a circular import.
debugging = True
if debugging:
print(f'{this_module_name} >>> module execution')
# =========================================================================
# Load / Reload
# =========================================================================
def reload(dotted_subpkg: str, submodules: Tuple[str, ...] = ()):
"""
Reload each module in `submodules` only if previously loaded. This is a
precondition of calling ``importlib.reload()`` but is also for efficiency:
- if Sublime Text is just starting, nothing important happens here (because
the cached modules will not have been added to ``sys.modules`` yet), and
and the various ``import`` statements do the loading in the usual way;
- if ``Package Control`` is updating this Package (or the central Plugin
was just saved during development), then this function recursively
reloads each loaded module, and the ``import`` statements then do
nothing since each target module will already be in ``sys.modules``.
Note: The below works on the basis that ``<sublime_data>/Packages``
directory was placed in ``sys.path`` by Sublime Text. So the
module names being constructed below have to look like this:
MyPackage.subdir.module
MyPackage.subdir.subdir.module
etc.
:param dotted_subpkg: dotted directory portion of module names that
will be found in the keys of ``sys.modules``.
Example: 'MyPackage.src.commands'
:param submodules: tuple of submodule names
"""
global _reload_indent_level
_reload_indent_level += 1
indent = ' ' * _reload_indent_level
if debugging:
if _reload_indent_level == 0:
print('vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv')
print(f'{indent}reload(): >>> {dotted_subpkg=} {submodules=}')
if not submodules:
# Called from top-level Plugin.
module_name = dotted_subpkg
if module_name in sys.modules:
if debugging:
print(f'{indent}Reloading({module_name})')
importlib.reload(sys.modules[module_name])
else:
# Called from subpackage.
for submodule in submodules:
module_name = f'{dotted_subpkg}.{submodule}'
if module_name in sys.modules:
if debugging:
print(f'{indent}Reloading({module_name})')
importlib.reload(sys.modules[module_name])
if debugging:
print(f'{indent}reload(): <<<')
if _reload_indent_level == 0:
print('^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^')
_reload_indent_level -= 1
reload(package_name + '.lib') # Recurse into .lib/ subpackage.
reload(package_name + '.src') # Recurse into .src/ subpackage.
from .lib import *
from .src import *
# =========================================================================
# Events
# =========================================================================
def plugin_loaded():
core.on_plugin_loaded()
def plugin_unloaded():
core.on_plugin_unloaded()
if debugging:
print(f'{this_module_name} <<<')
Then in each __init__.py file for each Subpackage:
""" lib/__init__.py """
from ..procomment import reload
from .debug import IntFlag, DebugBit, is_debugging
from .utils import sublime_submodule_name
submodule_name = sublime_submodule_name(__file__, 2)
debugging = is_debugging(DebugBit.IMPORTING)
if debugging:
print(f'{submodule_name} >>> module execution')
reload(submodule_name, ('debug', 'utils'))
from . import utils
__all__ = [
'debug',
'utils'
]
if debugging:
print(f'{submodule_name} <<<')
""" src/__init__.py """
from ..procomment import reload
from ..lib.debug import IntFlag, DebugBit, is_debugging
from ..lib.utils import sublime_submodule_name
submodule_name = sublime_submodule_name(__file__, 2)
debugging = is_debugging(DebugBit.IMPORTING)
if debugging:
print(f'{submodule_name} >>> module execution')
reload(submodule_name, ('core', 'contexts', 'func_parsing'))
reload(submodule_name + '.commands') # Recurse into .commands/ subpackage.
from . import core
from .contexts import *
from .commands import *
__all__ = [
'core',
'func_parsing',
# events/contexts
"ProCommentContextEventListener",
# commands/*
"ProCommentInsertDatestampCommand",
"ProCommentInsertTimestampCommand",
'ProCommentInsertCommentCommand',
]
if debugging:
print(f'{submodule_name} <<<')
""" src/commands/__init__.py """
from ...procomment import reload
from ...lib.debug import IntFlag, DebugBit, is_debugging
from ...lib.utils import sublime_submodule_name
subpackage_name = sublime_submodule_name(__file__, 3)
debugging = is_debugging(DebugBit.IMPORTING)
if debugging:
print(f' {subpackage_name} >>> module execution')
reload(subpackage_name, ('insert_datestamp', 'insert_timestamp', 'insert_comment'))
from .insert_comment import ProCommentInsertCommentCommand
from .insert_datestamp import ProCommentInsertDatestampCommand
from .insert_timestamp import ProCommentInsertTimestampCommand
__all__ = [
# Comment Commands
'ProCommentInsertCommentCommand',
# Datestamp/Timestamp Commands
'ProCommentInsertDatestampCommand',
'ProCommentInsertTimestampCommand',
]
if debugging:
print(f' {subpackage_name} <<<')
where sublime_submodule_name is defined in .lib/utils.py as:
_cfg_compressed_pkg_ext = '.sublime-package'
def sublime_submodule_name(file_path: str, subpackage_depth: int):
"""
Convert `file_path` to the indicated imported Python Module name. Example
given `subpackage_depth` == 2:
file_path: == '/path/to/Sublime Text/Packages/ProComment/src/__init__.py'
Result: 'ProComment.src'
file_path: == '/path/to/Sublime Text/Packages/ProComment.sublime-package/src/__init__.py'
Result: 'ProComment.src'
file_path: == '/path/to/Sublime Text/Packages/ProComment/src/core.py'
Result: 'ProComment.src.core'
:param file_path: `__file__` for each module calling this function.
:param subpackage_depth: Number of directories below `Sublime Text/Packages/`
"""
module_list = []
working_path, _ = os.path.splitext(file_path)
for i in range(subpackage_depth + 1):
remaining, submodule = os.path.split(working_path)
include = True
if submodule == '__init__':
include = False
elif i == subpackage_depth and submodule.endswith(_cfg_compressed_pkg_ext):
submodule = submodule[:-len(_cfg_compressed_pkg_ext)]
if include:
module_list.append(submodule)
working_path = remaining
return '.'.join(reversed(module_list))
and produces a return value that looks like: ProComment.src.commands based on the
physical path contained in __file__—exactly what the reload() function
needs.
Note carefully that src/__init__.py explicitly recursed into the src/commands/
directory like this—after all its modules at that level were reloaded:
reload(subpackage_name + '.commands') # Recurse into .commands/ subpackage.
This pattern then causes a “cascade” of all the modules being reloaded: when
procomment.py gets either loaded (for the first time), reloaded (by Package
Control, or saved during development).
The end result of this pattern is:
When Sublime Text starts, all Subpackages get loaded via a cascade of
importstatements.When the
Package ControlPackage updates your Package and reloads the central Plugin (or when you save your central Plugin during development), all the modules in each Subpackage get reloaded via a cascade ofreload()calls.
If you would like to verify/trace that visually, you can see the cascade of importing
and reloading in the debug output (from the code above) into the Console Panel when
Sublime Text is first started. This is when the loading is mostly being
done by import statements:
reloading plugin ProComment.procomment
ProComment.procomment >>> module execution
vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
reload(): >>> dotted_subpkg='ProComment.lib' submodules=()
reload(): <<<
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
reload(): >>> dotted_subpkg='ProComment.src' submodules=()
reload(): <<<
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ProComment.lib >>> module execution
vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
reload(): >>> dotted_subpkg='ProComment.lib' submodules=('debug', 'utils')
Reloading(ProComment.lib.debug)
Reloading(ProComment.lib.utils)
reload(): <<<
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ProComment.lib <<<
ProComment.src >>> module execution
vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
reload(): >>> dotted_subpkg='ProComment.src' submodules=('core', 'contexts', 'func_parsing')
reload(): <<<
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
reload(): >>> dotted_subpkg='ProComment.src.commands' submodules=()
reload(): <<<
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ProComment.src.commands >>> module execution
vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
reload(): >>> dotted_subpkg='ProComment.src.commands' submodules=('insert_datestamp', 'insert_timestamp', 'insert_comment')
reload(): <<<
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ProComment.src.commands <<<
ProComment.src <<<
ProComment.procomment <<<
And this is the debug output each time procomment.py is saved during development,
or when the Package Control Package updates the package while Sublime Text
is running). This is when the loading is being done entirely by the cascade of calls
to the reload() function:
reloading plugin ProComment.procomment
ProComment: Plugin unloaded at 28-Feb-2026 13:26
ProComment.procomment >>> module execution
vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
reload(): >>> dotted_subpkg='ProComment.lib' submodules=()
Reloading(ProComment.lib)
ProComment.lib >>> module execution
reload(): >>> dotted_subpkg='ProComment.lib' submodules=('debug', 'utils')
Reloading(ProComment.lib.debug)
Reloading(ProComment.lib.utils)
reload(): <<<
ProComment.lib <<<
reload(): <<<
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
reload(): >>> dotted_subpkg='ProComment.src' submodules=()
Reloading(ProComment.src)
ProComment.src >>> module execution
reload(): >>> dotted_subpkg='ProComment.src' submodules=('core', 'contexts', 'func_parsing')
Reloading(ProComment.src.core)
Reloading(ProComment.src.contexts)
Reloading(ProComment.src.func_parsing)
reload(): <<<
reload(): >>> dotted_subpkg='ProComment.src.commands' submodules=()
Reloading(ProComment.src.commands)
ProComment.src.commands >>> module execution
reload(): >>> dotted_subpkg='ProComment.src.commands' submodules=('insert_datestamp', 'insert_timestamp', 'insert_comment')
Reloading(ProComment.src.commands.insert_datestamp)
Reloading(ProComment.src.commands.insert_timestamp)
Reloading(ProComment.src.commands.insert_comment)
reload(): <<<
ProComment.src.commands <<<
reload(): <<<
ProComment.src <<<
reload(): <<<
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ProComment.procomment <<<
Debugging: [0x2002]
- LOAD_UNLOAD: 0x0002
- IMPORTING : 0x2000
ProComment: Initialized at 28-Feb-2026 13:26.
When you turn debugging output off, and all of the above happens silently and happily in the background.
Note
The lines:
Debugging: [0x2002]
- LOAD_UNLOAD: 0x0002
- IMPORTING : 0x2000
is from the lib/debug.py module as a result of having at least 1 debugging
bit turned on at the time the Console output was captured.
The line:
ProComment: Initialized at 23-Feb-2026 11:53.
at the end is a result of having the LOAD_UNLOAD debugging bit turned on at the time the Console output was captured.
15.6. Troubleshooting Packages
Because Sublime Text is so customizable, it is possible for 3rd-party Packages and/or local customization to interfere with one another, or cause other problems. You might see this, for example, as Python exceptions that don’t make sense in the Console Panel, or certain functionality isn’t behaving as you expect.
15.6.1. Safe Mode
As of Sublime Text 4, you can now launch Sublime Text in Safe Mode by using this option on the command line to launch it.
subl –safe-mode
Sublime Text initially displays this dialog box to describe the run-time environment:
Fig. 15.6.1.1 Screenshot showing Safe Mode Announcement
When launched this way, Sublime Text uses an alternate Data Directory
thus disabling all 3rd-party Packages and local customizations, as well as
internally not loading any previous sessions (i.e. from any .sublime-workspace
files). This will help you to verify whether the behavior is, or is not,
coming from Sublime Text itself or one of its shipped Packages.
The alternate Data Directory used is:
- Windows:
%APPDATA%/Sublime |nbsp| Text (Safe Mode)/- Windows Portable Version:
path/to/application/Data (Safe Mode)/- Linux:
~/.config/sublime-text-safe-mode/- MacOS:
~/Library/Application Support/Sublime |nbsp| Text (Safe Mode)/
If the behavior is still being exhibited, it is most likely from a corrupted shipped Package file and can be remedied by re-installing Sublime Text.
If the behavior disappears, then you know it was coming from somewhere in the Data Directory.
A nice thing about Safe Mode is that you can install experimental customizations or packages you think might have caused problems, and it will not affect Sublime Text’s ability to start and behave normally because:
such packages will be installed in the alternate Data Directory, thus not impacting normal sessions, and
each time Sublime Text starts in Safe Mode, it deletes any content in the Safe-Mode Data Directory, so it “doesn’t hurt” if a package installed there did something it wasn’t supposed to.
Caution: don’t store anything important in the Safe-Mode Data Directory!
15.6.2. Diagnosing Trouble from the Data Directory
If you have reached the conclusion that the trouble you are experiencing has come from the Data Directory (3rd-Party Packages and/or local customization), you can discover the source of the problem by following these steps. Knowing when the problem started is also an asset, because the cause will most likely have occurred just before the problem started.
Close Sublime Text if it is running.
Rename the Data Directory to another name to keep it as a backup and reference about what Packages you installed and what customizations you made.
Re-start Sublime Text.
When Sublime Text starts, it will create a fresh new Data Directory.
Note: In subsequent steps, it is recommended to keep the contents of the renamed (backup) of the problematic Data Directory unaltered for sake of preserving the evidence. This is so that if your first attempt at isolating the problem isn’t successful, you can repeat it (using smaller or different steps) as many times as needed until you have isolated the problem.
15.6.2.1. Diagnosis by Isolating Packages
Now you can re-install 3rd-Party Packages you had in place (and were working correctly) well before the problem started. Test to verify whether the problem is occurring after this step.
If the problem is not occurring at this point, you can continue to diagnose by re-adding each subsequent Package one by one, until the behavior returns, at which point you will know what Package to exclude or disable.
On the other hand, if the problem *is occurring*, you know the problem is somewhere in that group of Packages, and you can take steps to further isolate the source by reverting and repeating this step with only half of the Packages, and keep dividing the problematic group until you have isolated the source.
15.6.2.2. Diagnosis by Isolating Customizations
If you have reached this point and the problem has not returned, now you can add your own customizations back in, one at a time, until the problem resurfaces. If/when you encounter the problem again, you will know where to investigate further to remedy, or, as the case may be, what not to do.
15.7. Further Reading
The more you know about Python’s Import System, the more you will understand some of the power of Sublime Text Packages and their facilities brought to bear by Python itself (e.g. their ability use modular subpackages to cleverly manage Package complexity, and thereby make a Package more understandable, and thereby more maintainable).