Files
nemo-repo-emblems/nemoRepoEmblems.py
T
dualfroz 1b916d4d00 refactor: rebuild as an emblem plugin on nemo-repo-core
Everything that was not about drawing emblems moves out: the columns, the properties tab and the context menu are their own plugins now, and the config, git and cache layers come from nemo-repo-core.

The indicator list stops being hardcoded. Entries that are not one of the three git derived indicators are matched by marker_directory or marker_file, which is how claude_dir now works and how a user adds their own without touching the code.
2026-08-05 20:07:00 +02:00

132 lines
4.1 KiB
Python

#!/usr/bin/python3
"""nemo-repo-emblems: emblem overlays for repository folders in Nemo.
Four indicators ship by default: the folder is a git repository, it holds a
.claude directory, its working tree is dirty, it has commits the remote does
not. Indicators are declared in the config file, so extra ones can be added
without touching this file.
Requires nemo-repo-core: https://github.com/dualfroz/nemo-repo-core
"""
import importlib.util
import os
import sys
def _ensureCoreOnPath():
if importlib.util.find_spec("nemoRepoCore") is not None:
return
dataHome = os.environ.get("XDG_DATA_HOME") or os.path.expanduser("~/.local/share")
dataDirs = (os.environ.get("XDG_DATA_DIRS") or "/usr/local/share:/usr/share").split(":")
for base in [dataHome] + dataDirs:
candidate = os.path.join(base, "nemo-repo-core")
if os.path.isdir(os.path.join(candidate, "nemoRepoCore")):
sys.path.insert(0, candidate)
return
_ensureCoreOnPath()
import gi
gi.require_version("Nemo", "3.0")
from gi.repository import GObject, Nemo
from nemoRepoCore import (coreConfig, findRepoRoot, hasMarkerDirectory,
localDirectoryPath, pluginLogger, repoCache,
requireCore)
requireCore("1.0.0")
logger = pluginLogger("emblems")
gitIndicators = ("git_repo", "uncommitted_changes", "unpushed_commits")
pluginDefaults = {
"indicators": {
"git_repo": {
"enabled": True,
"emblem": "emblem-repo-git",
"description": "Folder contains a .git directory (or worktree file)",
},
"claude_dir": {
"enabled": True,
"emblem": "emblem-repo-claude",
"marker_directory": ".claude",
"description": "Folder contains a .claude directory",
},
"uncommitted_changes": {
"enabled": True,
"emblem": "emblem-repo-dirty",
"description": "git status shows staged, unstaged or untracked changes",
},
"unpushed_commits": {
"enabled": True,
"emblem": "emblem-repo-unpushed",
"description": "Branch is ahead of its upstream, or has no upstream",
},
},
}
coreConfig.registerDefaults(pluginDefaults)
def _enabledIndicators():
"""Config entries that are switched on and name an emblem, by key."""
active = {}
for key, entry in coreConfig.section("indicators").items():
if not isinstance(entry, dict) or not entry.get("enabled"):
continue
if entry.get("emblem"):
active[key] = entry
return active
def _markerMatches(path, entry):
markerDirectory = entry.get("marker_directory")
if markerDirectory and hasMarkerDirectory(path, markerDirectory):
return True
markerFile = entry.get("marker_file")
return bool(markerFile) and os.path.isfile(os.path.join(path, markerFile))
class RepoEmblemProvider(GObject.GObject, Nemo.InfoProvider,
Nemo.NameAndDescProvider):
def update_file_info(self, file):
path = localDirectoryPath(file)
if path is None:
return
active = _enabledIndicators()
for key, entry in active.items():
if key not in gitIndicators and _markerMatches(path, entry):
file.add_emblem(entry["emblem"])
repoRoot = findRepoRoot(path)
if repoRoot is None:
return
if "git_repo" in active:
file.add_emblem(active["git_repo"]["emblem"])
wantsDirty = "uncommitted_changes" in active
wantsUnpushed = "unpushed_commits" in active
if not (wantsDirty or wantsUnpushed):
return
repoCache.registerFileObject(repoRoot, file)
info = repoCache.get(repoRoot)
if info.error:
return
if wantsDirty and info.dirty:
file.add_emblem(active["uncommitted_changes"]["emblem"])
if wantsUnpushed and info.unpushed:
file.add_emblem(active["unpushed_commits"]["emblem"])
def get_name_and_desc(self):
return ["nemo-repo-emblems:::Emblem overlays for git repositories "
"and marker directories"]