From 19ee5a7427059c8f570cc050acca1e1e6305bd8c Mon Sep 17 00:00:00 2001 From: Wojciech Siewierski Date: Sun, 22 Feb 2015 01:33:57 +0100 Subject: linemode refactoring; custom linemodes possible --- ranger/config/commands.py | 6 +-- ranger/container/fsobject.py | 7 ++- ranger/core/actions.py | 4 +- ranger/core/linemode.py | 91 +++++++++++++++++++++++++++++++++++++ ranger/gui/widgets/browsercolumn.py | 42 ++++++----------- 5 files changed, 114 insertions(+), 36 deletions(-) create mode 100644 ranger/core/linemode.py diff --git a/ranger/config/commands.py b/ranger/config/commands.py index 55f6442b..6e2ba26d 100644 --- a/ranger/config/commands.py +++ b/ranger/config/commands.py @@ -390,7 +390,7 @@ class setintag(setlocal): class default_linemode(Command): def execute(self): import re - from ranger.container.fsobject import POSSIBLE_LINEMODES + from ranger.core.linemode import REGISTERED_LINEMODES if len(self.args) < 2: self.fm.notify("Usage: default_linemode [path= | tag=] ", bad=True) @@ -410,9 +410,9 @@ class default_linemode(Command): # Extract and validate the line mode from the command line linemode = self.rest(1) - if linemode not in POSSIBLE_LINEMODES: + if linemode not in REGISTERED_LINEMODES: self.fm.notify("Invalid linemode: %s; should be %s" % - (linemode, "/".join(POSSIBLE_LINEMODES)), bad=True) + (linemode, "/".join(REGISTERED_LINEMODES)), bad=True) # Add the prepared entry to the fm.default_linemodes entry = [method, argument, linemode] diff --git a/ranger/container/fsobject.py b/ranger/container/fsobject.py index 08161c3c..32b1dc8b 100644 --- a/ranger/container/fsobject.py +++ b/ranger/container/fsobject.py @@ -12,14 +12,13 @@ DOCUMENT_BASENAMES = ('bugs', 'bugs', 'changelog', 'copying', 'credits', BAD_INFO = '?' -POSSIBLE_LINEMODES = ("filename", "metatitle", "permissions") -DEFAULT_LINEMODE = "filename" - import re from grp import getgrgid from os import lstat, stat, getcwd from os.path import abspath, basename, dirname, realpath, splitext, extsep, relpath from pwd import getpwuid +from ranger.core.linemode import REGISTERED_LINEMODES +from ranger.core.linemode import DEFAULT_LINEMODE from ranger.core.shared import FileManagerAware, SettingsAware from ranger.ext.shell_escape import shell_escape from ranger.ext.spawn import spawn @@ -112,7 +111,7 @@ class FileSystemObject(FileManagerAware, SettingsAware): # Set the line mode from fm.default_linemodes for method, argument, linemode in self.fm.default_linemodes: - if linemode in POSSIBLE_LINEMODES: + if linemode in REGISTERED_LINEMODES: if method == "always": self._linemode = linemode break diff --git a/ranger/core/actions.py b/ranger/core/actions.py index 1167dab5..aa10e34f 100644 --- a/ranger/core/actions.py +++ b/ranger/core/actions.py @@ -27,7 +27,7 @@ from ranger.core.tab import Tab from ranger.container.file import File from ranger.core.loader import CommandLoader, CopyLoader from ranger.container.settings import ALLOWED_SETTINGS -from ranger.container.fsobject import POSSIBLE_LINEMODES, DEFAULT_LINEMODE +from ranger.core.linemode import REGISTERED_LINEMODES, DEFAULT_LINEMODE MACRO_FAIL = "<\x01\x01MACRO_HAS_NO_VALUE\x01\01>" @@ -167,7 +167,7 @@ class Actions(FileManagerAware, EnvironmentAware, SettingsAware): if mode == "normal": mode = DEFAULT_LINEMODE - if mode not in POSSIBLE_LINEMODES: + if mode not in REGISTERED_LINEMODES: self.notify("Unhandled linemode: `%s'" % mode, bad=True) return diff --git a/ranger/core/linemode.py b/ranger/core/linemode.py new file mode 100644 index 00000000..8b5084b0 --- /dev/null +++ b/ranger/core/linemode.py @@ -0,0 +1,91 @@ +# -*- coding: utf-8 -*- + +from abc import * + +DEFAULT_LINEMODE = "filename" +REGISTERED_LINEMODES = dict() + +def register_linemode(*linemodes): + """Register a linemode in a dictionary of available linemodes.""" + for linemode in linemodes: + REGISTERED_LINEMODES[linemode.name] = linemode() + +def lookup_linemode(name): + """Lookup the linemode instance by its name""" + return REGISTERED_LINEMODES[name] + + +class LinemodeBase(object): + """Supplies the file line contents for BrowserColumn. + + Attributes: + name (required!) - Name by which the linemode is referred to by the user + + uses_metadata - True if metadata should to be loaded for this linemode + + required_metadata - + If any of these metadata fields are absent, fall back to + the default linemode + """ + __metaclass__ = ABCMeta + + uses_metadata = False + required_metadata = [] + + name = abstractproperty() + + @abstractmethod + def filetitle(self, file, metadata): + """The left-aligned part of the line.""" + raise NotImplementedError + + @abstractmethod + def infostring(self, file, metadata): + """The right-aligned part of the line.""" + raise NotImplementedError + + +class DefaultLinemode(LinemodeBase): + name = "filename" + + def filetitle(self, file, metadata): + return file.drawn_basename + + def infostring(self, file, metadata): + # Should never be called for this linemode, implemented in BrowserColumn + raise NotImplementedError + + +class TitleLinemode(LinemodeBase): + name = "metatitle" + uses_metadata = True + required_metadata = ["title"] + + def filetitle(self, file, metadata): + name = metadata.title or file.basename + if metadata.year: + return "%s - %s" % (metadata.year, name) + else: + return name + + def infostring(self, file, metadata): + if metadata.authors: + authorstring = metadata.authors + if ',' in authorstring: + authorstring = authorstring[0:authorstring.find(",")] + return authorstring + return "" + + +class PermissionsLinemode(LinemodeBase): + name = "permissions" + + def filetitle(self, file, metadata): + return "%s %s %s %s" % (file.get_permission_string(), + file.user, file.group, file.drawn_basename) + + def infostring(self, file, metadata): + return "" + + +register_linemode(DefaultLinemode, PermissionsLinemode, TitleLinemode) diff --git a/ranger/gui/widgets/browsercolumn.py b/ranger/gui/widgets/browsercolumn.py index 564e9a5f..427a323d 100644 --- a/ranger/gui/widgets/browsercolumn.py +++ b/ranger/gui/widgets/browsercolumn.py @@ -12,6 +12,8 @@ from . import Widget from .pager import Pager from ranger.ext.widestring import WideString +from ranger.core import linemode + from ranger.gui.color import * class BrowserColumn(Pager): @@ -250,38 +252,25 @@ class BrowserColumn(Pager): # Extract linemode-related information from the drawn object metadata = None - use_linemode = drawn._linemode - if use_linemode == "metatitle": + current_linemode = linemode.lookup_linemode(drawn._linemode) + if current_linemode.uses_metadata: metadata = self.fm.metadata.get_metadata(drawn.path) - if not metadata.title: - use_linemode = "filename" + if not all(getattr(metadata, tag) + for tag in current_linemode.required_metadata): + current_linemode = linemode.lookup_linemode(linemode.DEFAULT_LINEMODE) metakey = hash(repr(sorted(metadata.items()))) if metadata else 0 key = (self.wid, selected_i == i, drawn.marked, self.main_column, drawn.path in copied, tagged_marker, drawn.infostring, drawn.vcsfilestatus, drawn.vcsremotestatus, self.fm.do_cut, - use_linemode, metakey) + current_linemode.name, metakey) if key in drawn.display_data: self.execute_curses_batch(line, drawn.display_data[key]) self.color_reset() continue - - # Deal with the line mode - text = "" - if use_linemode == "metatitle": - assert metadata.title, "Ensure that metadata.title is set!" - if metadata.year: - text = "%s - %s" % (metadata.year, metadata.title) - else: - text = metadata.title - if use_linemode == "filename": - text = drawn.drawn_basename - elif use_linemode == "permissions": - text = "%s %s %s %s" % (drawn.get_permission_string(), - drawn.user, drawn.group, drawn.drawn_basename) - + text = current_linemode.filetitle(drawn, metadata) if drawn.marked and (self.main_column or \ self.settings.display_tags_in_all_columns): @@ -312,14 +301,13 @@ class BrowserColumn(Pager): # info string infostring = [] infostringlen = 0 - if use_linemode == "filename": + if current_linemode.name == "filename": infostring = self._draw_infostring_display(drawn, space) - elif use_linemode == "metatitle": - if metadata.authors: - authorstring = metadata.authors - if ',' in authorstring: - authorstring = authorstring[0:authorstring.find(",")] - infostring.append([" " + authorstring + " ", ["infostring"]]) + else: + infostringdata = current_linemode.infostring(drawn, metadata) + if infostringdata: + infostring.append([" " + infostringdata + " ", + ["infostring"]]) if infostring: infostringlen = self._total_len(infostring) if space - infostringlen > 2: -- cgit 1.4.1-2-gfad0 From ca4aa285995f5dd1986c299453c7857b42ca2452 Mon Sep 17 00:00:00 2001 From: Wojciech Siewierski Date: Sun, 22 Feb 2015 01:51:57 +0100 Subject: doc/ranger.1: updated the linemode description in the man page --- doc/ranger.pod | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/ranger.pod b/doc/ranger.pod index 6888ee70..d19ddc0f 100644 --- a/doc/ranger.pod +++ b/doc/ranger.pod @@ -1035,6 +1035,9 @@ Sets the linemode of all files in the current directory. The linemode may be: available, fall back to the "filename" linemode if no metadata was found. See :meta command. +The custom linemodes may be added by subclassing the I class. +See the I module for some examples. + =item load_copy_buffer Load the copy buffer from F<~/.config/ranger/copy_buffer>. This can be used to -- cgit 1.4.1-2-gfad0 From d75308efa1aaa4a536bcf3301d3d079e6db3b4bb Mon Sep 17 00:00:00 2001 From: Wojciech Siewierski Date: Sun, 22 Feb 2015 16:34:30 +0100 Subject: further linemode refactoring - registered linemodes list moved to FileSystemObject - ranger.api module updated --- ranger/api/__init__.py | 8 ++++++++ ranger/container/fsobject.py | 9 ++++++--- ranger/core/actions.py | 4 ++-- ranger/core/linemode.py | 13 ------------- ranger/gui/widgets/browsercolumn.py | 4 ++-- 5 files changed, 18 insertions(+), 20 deletions(-) diff --git a/ranger/api/__init__.py b/ranger/api/__init__.py index a50f706f..cc0815c2 100644 --- a/ranger/api/__init__.py +++ b/ranger/api/__init__.py @@ -26,3 +26,11 @@ def hook_ready(fm): This hook is executed after the user interface is initialized. You should NOT print anything to stdout anymore from here on. Use fm.notify instead. """ + +from ranger.core.linemode import LinemodeBase + +def register_linemode(*linemodes): + """Register the linemodes in a dictionary of the available linemodes.""" + from ranger.container.fsobject import FileSystemObject + for linemode in linemodes: + FileSystemObject.linemode_dict[linemode.name] = linemode() diff --git a/ranger/container/fsobject.py b/ranger/container/fsobject.py index 32b1dc8b..43499e15 100644 --- a/ranger/container/fsobject.py +++ b/ranger/container/fsobject.py @@ -17,8 +17,7 @@ from grp import getgrgid from os import lstat, stat, getcwd from os.path import abspath, basename, dirname, realpath, splitext, extsep, relpath from pwd import getpwuid -from ranger.core.linemode import REGISTERED_LINEMODES -from ranger.core.linemode import DEFAULT_LINEMODE +from ranger.core.linemode import DEFAULT_LINEMODE, REGISTERED_LINEMODES from ranger.core.shared import FileManagerAware, SettingsAware from ranger.ext.shell_escape import shell_escape from ranger.ext.spawn import spawn @@ -85,6 +84,10 @@ class FileSystemObject(FileManagerAware, SettingsAware): basename_is_rel_to = None _linemode = DEFAULT_LINEMODE + linemode_dict = dict( + (linemode.name, linemode()) for linemode in + [DefaultLinemode, TitleLinemode, PermissionsLinemode] + ) def __init__(self, path, preload=None, path_is_abs=False, basename_is_rel_to=None): if not path_is_abs: @@ -111,7 +114,7 @@ class FileSystemObject(FileManagerAware, SettingsAware): # Set the line mode from fm.default_linemodes for method, argument, linemode in self.fm.default_linemodes: - if linemode in REGISTERED_LINEMODES: + if linemode in linemode_dict: if method == "always": self._linemode = linemode break diff --git a/ranger/core/actions.py b/ranger/core/actions.py index aa10e34f..6e0dc797 100644 --- a/ranger/core/actions.py +++ b/ranger/core/actions.py @@ -27,7 +27,7 @@ from ranger.core.tab import Tab from ranger.container.file import File from ranger.core.loader import CommandLoader, CopyLoader from ranger.container.settings import ALLOWED_SETTINGS -from ranger.core.linemode import REGISTERED_LINEMODES, DEFAULT_LINEMODE +from ranger.core.linemode import DEFAULT_LINEMODE MACRO_FAIL = "<\x01\x01MACRO_HAS_NO_VALUE\x01\01>" @@ -167,7 +167,7 @@ class Actions(FileManagerAware, EnvironmentAware, SettingsAware): if mode == "normal": mode = DEFAULT_LINEMODE - if mode not in REGISTERED_LINEMODES: + if mode not in self.thisfile.linemode_dict: self.notify("Unhandled linemode: `%s'" % mode, bad=True) return diff --git a/ranger/core/linemode.py b/ranger/core/linemode.py index 8b5084b0..ee770cb0 100644 --- a/ranger/core/linemode.py +++ b/ranger/core/linemode.py @@ -3,16 +3,6 @@ from abc import * DEFAULT_LINEMODE = "filename" -REGISTERED_LINEMODES = dict() - -def register_linemode(*linemodes): - """Register a linemode in a dictionary of available linemodes.""" - for linemode in linemodes: - REGISTERED_LINEMODES[linemode.name] = linemode() - -def lookup_linemode(name): - """Lookup the linemode instance by its name""" - return REGISTERED_LINEMODES[name] class LinemodeBase(object): @@ -86,6 +76,3 @@ class PermissionsLinemode(LinemodeBase): def infostring(self, file, metadata): return "" - - -register_linemode(DefaultLinemode, PermissionsLinemode, TitleLinemode) diff --git a/ranger/gui/widgets/browsercolumn.py b/ranger/gui/widgets/browsercolumn.py index 427a323d..2e9bf7a2 100644 --- a/ranger/gui/widgets/browsercolumn.py +++ b/ranger/gui/widgets/browsercolumn.py @@ -252,12 +252,12 @@ class BrowserColumn(Pager): # Extract linemode-related information from the drawn object metadata = None - current_linemode = linemode.lookup_linemode(drawn._linemode) + current_linemode = drawn.linemode_dict[drawn._linemode] if current_linemode.uses_metadata: metadata = self.fm.metadata.get_metadata(drawn.path) if not all(getattr(metadata, tag) for tag in current_linemode.required_metadata): - current_linemode = linemode.lookup_linemode(linemode.DEFAULT_LINEMODE) + current_linemode = drawn.linemode_dict[linemode.DEFAULT_LINEMODE] metakey = hash(repr(sorted(metadata.items()))) if metadata else 0 key = (self.wid, selected_i == i, drawn.marked, self.main_column, -- cgit 1.4.1-2-gfad0