/
cptngreen
/
ranger_orglinemode
Обзор
Документация
Войти
/
cptngreen
/
ranger_orglinemode
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
develop
__init__.py
307 строк
11 KB
CptnGreen
Verify and log
30 окт 2024, 06:54
30 окт 2024, 06:54
64b30f6
Код
Авторство
О чём код?
from __future__ import (absolute_import, division, print_function) import os import re import sys from functools import lru_cache import logging import ranger.api from ranger.api import register_linemode from ranger.core.linemode import LinemodeBase from ranger.api.commands import Command import ranger.gui.context import ranger.gui.widgets.browsercolumn from ranger.gui.colorscheme import ColorScheme, get_all_colorschemes from ranger.gui.color import ( black, blue, cyan, green, magenta, red, white, yellow, default, normal, bold, reverse, dim, BRIGHT, default_colors ) from ranger.container.settings import ALLOWED_SETTINGS from ranger.gui import colorscheme as ranger_colorscheme # Configuration COLORIZED_TAGS = {'urgent', 'work', 'project'} SHOW_TITLES = False _ORIGINAL_COLORSCHEME = None _ACTIVE = False LOGGER = logging.getLogger(__name__) def verify_colorscheme_registration(): """Verify if our colorscheme is properly registered""" if ranger.fm is None: LOGGER.debug("FM not available for colorscheme verification") return False LOGGER.debug("Available colorschemes: %s", list(get_all_colorschemes(ranger.fm))) LOGGER.debug("ColorScheme registry: %s", list(ranger_colorscheme.ColorScheme.registry.keys())) return 'org' in ranger_colorscheme.ColorScheme.registry class OrgColorScheme(ColorScheme): """Custom colorscheme for org-mode files""" name = 'org' def __init__(self): super(OrgColorScheme, self).__init__() def use(self, context): fg, bg, attr = default_colors if context.reset: return default_colors elif context.in_browser: if context.empty or context.error: fg = red elif context.directory: fg = blue elif context.executable: fg = green attr |= bold elif context.media: fg = magenta # Only color tags in the infostring if context.infostring: if context.org_tag_urgent: fg = red attr |= bold elif context.org_tag_work: fg = magenta attr |= bold elif context.org_tag_project: fg = yellow attr |= bold if context.selected: attr = reverse return fg, bg, attr def _register_colorscheme(fm): """Register the org colorscheme with ranger""" try: # Make sure our colorscheme is available in both the registry and allowed settings ranger_colorscheme.ColorScheme.registry['org'] = OrgColorScheme # Get the actual colorscheme class scheme_class = OrgColorScheme # Add to allowed settings if 'colorscheme' in ALLOWED_SETTINGS: ALLOWED_SETTINGS['colorscheme'].add('org') # Add to confpath colorschemes if possible if hasattr(fm, 'confpath'): colorscheme_path = fm.confpath('colorschemes') if colorscheme_path and not os.path.exists(colorscheme_path): try: os.makedirs(colorscheme_path) except OSError as e: LOGGER.warning("Could not create colorschemes directory: %s", e) LOGGER.debug("Colorscheme registration verification...") LOGGER.debug("Registered: %s", verify_colorscheme_registration()) return True except Exception as e: LOGGER.error("Failed to register colorscheme: %s", str(e)) return False class org_toggle_titles(Command): """ :org_toggle_titles Toggle between showing filenames or titles for org files """ def execute(self): global SHOW_TITLES SHOW_TITLES = not SHOW_TITLES self.fm.ui.browser.need_redraw = True self.fm.notify(f"Org titles {'enabled' if SHOW_TITLES else 'disabled'}") class org_mode_toggle(Command): """ :org_mode_toggle Toggle org mode on/off """ def execute(self): global _ACTIVE, _ORIGINAL_COLORSCHEME try: _ACTIVE = not _ACTIVE if _ACTIVE: self.fm.execute_console('linemode orgmode') _ORIGINAL_COLORSCHEME = self.fm.settings.colorscheme # Re-register and apply colorscheme if _register_colorscheme(self.fm): try: # Force reload available colorschemes self.fm.commands.load_commands_from_module(sys.modules[__name__]) if verify_colorscheme_registration(): self.fm.settings.set("colorscheme", "org", signal=True) LOGGER.debug("Colorscheme set to 'org'") else: raise ValueError("Colorscheme 'org' not properly registered") except Exception as e: LOGGER.error("Failed to apply colorscheme: %s", str(e)) self.fm.notify("Failed to apply colorscheme", bad=True) return self.fm.notify("Org mode activated") else: self.fm.execute_console('linemode filename') if _ORIGINAL_COLORSCHEME: self.fm.settings.set("colorscheme", _ORIGINAL_COLORSCHEME, signal=True) LOGGER.debug("Restored original colorscheme: %s", _ORIGINAL_COLORSCHEME) self.fm.notify("Org mode deactivated") # Force complete UI redraw self.fm.ui.need_redraw = True for col in self.fm.ui.browser.columns: col.need_redraw = True except Exception as e: LOGGER.error("Error toggling org mode: %s", str(e)) self.fm.notify(f"Failed to toggle org mode: {str(e)}", bad=True) # Add custom context keys dynamically based on tags ranger.gui.context.CONTEXT_KEYS.extend([ f'org_tag_{tag}' for tag in COLORIZED_TAGS ]) # Initialize context attributes for key in ranger.gui.context.CONTEXT_KEYS: if key.startswith('org_tag_'): setattr(ranger.gui.context.Context, key, False) OLD_HOOK_BEFORE_DRAWING = ranger.gui.widgets.browsercolumn.hook_before_drawing def new_hook_before_drawing(fsobject, color_list): """Add colors based on org tags""" try: if fsobject.path.endswith('.org'): tags = get_org_tags(fsobject) for tag in tags: tag_lower = tag.lower() if tag_lower in COLORIZED_TAGS: color_list.append(f'org_tag_{tag_lower}') except Exception as e: LOGGER.error("Error in hook_before_drawing: %s", str(e)) return OLD_HOOK_BEFORE_DRAWING(fsobject, color_list) ranger.gui.widgets.browsercolumn.hook_before_drawing = new_hook_before_drawing @lru_cache(maxsize=128) def get_org_tags(fobj): """Extract org tags from the :TAGS: property""" tags = set() try: with open(fobj.path, 'r', encoding='utf-8') as f: for line in f: line = line.strip() if line.startswith(':TAGS:'): tags_str = line.split(':TAGS:', 1)[1].strip() tags.update(tag.strip().lower() for tag in tags_str.split() if tag.strip()) break except Exception as e: LOGGER.error("Error reading org tags from %s: %s", fobj.path, str(e)) return tags def get_org_status(content): """Extract org status from properties""" try: for line in content.split('\n'): line = line.strip() if line.startswith(':STATUS:'): return line.split(':STATUS:', 1)[1].strip() except Exception as e: LOGGER.error("Error getting org status: %s", str(e)) return "" def get_org_title(content): """Extract title from #+title: line""" try: title_match = re.search(r'#\+title:\s*(.+)$', content, re.MULTILINE | re.IGNORECASE) if title_match: return title_match.group(1).strip() except Exception as e: LOGGER.error("Error getting org title: %s", str(e)) return None def get_org_icon(status): """Get icon for org status""" icons = { 'TODO': '', 'DONE': '✓', 'IN_PROGRESS': '', 'WAITING': '', '': '' } return icons.get(status, icons['']) class OrgLinemode(LinemodeBase): name = 'orgmode' uses_metadata = True def filetitle(self, fobj, metadata): """Format the line title""" if not fobj.path.endswith('.org'): return fobj.relative_path try: with open(fobj.path, 'r', encoding='utf-8') as f: content = f.read(4096) status = get_org_status(content) icon = get_org_icon(status) if SHOW_TITLES: title = get_org_title(content) if title: return f"{icon} {title}" return f"{icon} {fobj.relative_path}" except Exception as e: LOGGER.error("Error formatting org line title for %s: %s", fobj.path, str(e)) return fobj.relative_path def infostring(self, fobj, metadata): """Show tags in the infostring""" if not fobj.path.endswith('.org'): return "" try: tags = get_org_tags(fobj) if tags: return ' '.join(f"+{tag}" for tag in sorted(tags)) except Exception as e: LOGGER.error("Error formatting org infostring for %s: %s", fobj.path, str(e)) return "" def initialize_plugin(): """Initialize the plugin""" try: # Register the linemode register_linemode(OrgLinemode) # Pre-register the colorscheme with ranger's system ranger_colorscheme.ColorScheme.registry['org'] = OrgColorScheme # Ensure it's in allowed settings if 'colorscheme' in ALLOWED_SETTINGS: ALLOWED_SETTINGS['colorscheme'].add('org') LOGGER.info('Org mode plugin initialized successfully') LOGGER.debug('Colorscheme registration status after init: %s', verify_colorscheme_registration()) return True except Exception as e: LOGGER.error('Failed to initialize org mode plugin: %s', str(e)) return False # Initialize plugin when module is loaded initialize_plugin()