The single file extension carried 260 lines of infrastructure under its
four Nemo providers: the config file with live reload, the git query
layer, the TTL cache with .git watching, and repository detection. Any
second extension wanting repository awareness had to repeat all of it.
Move that foundation into a nemoRepoCore package with a deliberate plugin
API rather than whatever the providers happened to leave behind:
* Config gains layered defaults, so a plugin registers its own keys and
an empty config file is still a working one
* RepoInfo gains a root, a named last commit tuple and a summary string
* RepoCache gains refresh, invalidate and an invalidation callback
* discovery separates the cheap root check used on every drawn folder
from the upward walk used by on demand work such as menus
* nemoFiles collapses the uri scheme and directory guards every
provider was repeating
* launchers learn the per emulator flag for running a command
* version negotiation lets a plugin state the core it was built for
The config file moves to nemo-repo-core.json and is seeded from the old
nemo-repo-emblems.json when one exists, so no key changes name and
nothing needs editing by hand.
83 lines
2.8 KiB
Python
83 lines
2.8 KiB
Python
"""nemo-repo-core: the shared foundation for repository-aware Nemo plugins.
|
|
|
|
A plugin is a single .py file in ~/.local/share/nemo-python/extensions/ that
|
|
imports this package and registers one Nemo provider. Everything expensive
|
|
or fiddly lives here: the config file, the git query layer, the cache that
|
|
keeps Nemo from forking git on every redraw, and the path handling that
|
|
turns a Nemo.FileInfo into something git can be pointed at.
|
|
|
|
Minimal plugin:
|
|
|
|
from nemoRepoCore import (coreConfig, findRepoRoot, localDirectoryPath,
|
|
repoCache, requireCore)
|
|
requireCore("1.0.0")
|
|
|
|
coreConfig.registerDefaults({"indicators": {"mine": {"enabled": True}}})
|
|
|
|
class MyProvider(GObject.GObject, Nemo.InfoProvider):
|
|
def update_file_info(self, file):
|
|
path = localDirectoryPath(file)
|
|
if path is None:
|
|
return
|
|
root = findRepoRoot(path)
|
|
if root is None:
|
|
return
|
|
repoCache.registerFileObject(root, file)
|
|
info = repoCache.get(root)
|
|
...
|
|
|
|
Stability policy for everything listed in __all__:
|
|
|
|
* Within a major version, names are never removed and signatures only ever
|
|
gain optional arguments. New helpers may appear; a plugin that asked for
|
|
1.0.0 keeps working on 1.4.0.
|
|
* A major bump may remove or reshape anything. requireCore() refuses to
|
|
load a plugin against a different major, so a mismatch is a clear error
|
|
at startup instead of a subtle misbehaviour later.
|
|
* Names not in __all__, and anything with a leading underscore, are
|
|
internal and may change in any release.
|
|
"""
|
|
|
|
from .Config import Config, coreConfig, coreDefaults, defaultConfigPath, legacyConfigPath
|
|
from .discovery import (findEnclosingRepoRoot, findRepoRoot, hasMarkerDirectory,
|
|
isRepoRoot, repoInfoFor)
|
|
from .gitQuery import computeRepoInfo, gitBinary, runGit
|
|
from .launchers import (editorAvailable, launchEditor, launchTerminal,
|
|
resolveTerminal)
|
|
from .logs import pluginLogger
|
|
from .nemoFiles import localDirectoryPath, localPath, singleLocalDirectory
|
|
from .RepoCache import RepoCache, repoCache
|
|
from .RepoInfo import LastCommit, RepoInfo
|
|
from .version import CoreVersionError, coreVersion, requireCore
|
|
|
|
__all__ = [
|
|
"Config",
|
|
"CoreVersionError",
|
|
"LastCommit",
|
|
"RepoCache",
|
|
"RepoInfo",
|
|
"computeRepoInfo",
|
|
"coreConfig",
|
|
"coreDefaults",
|
|
"coreVersion",
|
|
"defaultConfigPath",
|
|
"editorAvailable",
|
|
"findEnclosingRepoRoot",
|
|
"findRepoRoot",
|
|
"gitBinary",
|
|
"hasMarkerDirectory",
|
|
"isRepoRoot",
|
|
"launchEditor",
|
|
"launchTerminal",
|
|
"legacyConfigPath",
|
|
"localDirectoryPath",
|
|
"localPath",
|
|
"pluginLogger",
|
|
"repoCache",
|
|
"repoInfoFor",
|
|
"requireCore",
|
|
"resolveTerminal",
|
|
"runGit",
|
|
"singleLocalDirectory",
|
|
]
|