diff options
-rw-r--r-- | doc/ranger.pod | 3 | ||||
-rw-r--r-- | ranger/api/__init__.py | 8 | ||||
-rw-r--r-- | ranger/config/commands.py | 6 | ||||
-rw-r--r-- | ranger/container/fsobject.py | 10 | ||||
-rw-r--r-- | ranger/core/actions.py | 4 | ||||
-rw-r--r-- | ranger/core/linemode.py | 78 | ||||
-rw-r--r-- | ranger/gui/widgets/browsercolumn.py | 42 |
7 files changed, 115 insertions, 36 deletions
diff --git a/doc/ranger.pod b/doc/ranger.pod index 75da97b9..7b3354c4 100644 --- a/doc/ranger.pod +++ b/doc/ranger.pod @@ -1040,6 +1040,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<LinemodeBase> class. +See the I<ranger.core.linemode> module for some examples. + =item load_copy_buffer Load the copy buffer from F<~/.config/ranger/copy_buffer>. This can be used to 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/config/commands.py b/ranger/config/commands.py index 6467f98a..60b5a26f 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=<regexp> | tag=<tag(s)>] <linemode>", 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 2f2b5197..f7cf7f97 100644 --- a/ranger/container/fsobject.py +++ b/ranger/container/fsobject.py @@ -12,14 +12,12 @@ 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 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 @@ -86,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: @@ -112,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 POSSIBLE_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 be7c7a00..33903859 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 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 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 new file mode 100644 index 00000000..ee770cb0 --- /dev/null +++ b/ranger/core/linemode.py @@ -0,0 +1,78 @@ +# -*- coding: utf-8 -*- + +from abc import * + +DEFAULT_LINEMODE = "filename" + + +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 "" diff --git a/ranger/gui/widgets/browsercolumn.py b/ranger/gui/widgets/browsercolumn.py index 563716bb..2e9bf7a2 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 = drawn.linemode_dict[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 = 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, 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.relative_path - elif use_linemode == "permissions": - text = "%s %s %s %s" % (drawn.get_permission_string(), - drawn.user, drawn.group, drawn.relative_path) - + 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: |