diff options
author | toonn <toonn@toonn.io> | 2021-09-05 21:25:25 +0200 |
---|---|---|
committer | toonn <toonn@toonn.io> | 2021-09-05 21:28:22 +0200 |
commit | d75dd6971ee8f67eebedfc797ae57154ae1ffb69 (patch) | |
tree | f18bf0e1e2dfd4c9185003c3db6f2cec9cff5124 | |
parent | bb2734a3899aed931390ec16a64c5938cb68277c (diff) | |
download | ranger-d75dd6971ee8f67eebedfc797ae57154ae1ffb69.tar.gz |
commands: Rename setlocal to setinpath
The `setlocal` name is hard to remember, `setintag` is much easier to recall, so we will follow the same naming style. `setlocal` remains available as an alias for `setinpath`. A new abstract class, `_setlocal`, is introduced as a basis for the `setinpath` command because we want to reuse it for the original behavior of `setlocal`. Several bug fixes have been integrated in this new base class. The shifting of arguments was only incidentally correct most of the time. The matching of quoted arguments only worked in the absence of nested quotes.
-rwxr-xr-x | ranger/config/commands.py | 93 |
1 files changed, 75 insertions, 18 deletions
diff --git a/ranger/config/commands.py b/ranger/config/commands.py index 1bd6f96f..5af41723 100755 --- a/ranger/config/commands.py +++ b/ranger/config/commands.py @@ -482,36 +482,93 @@ class set_(Command): return None -class setlocal(set_): - """:setlocal path=<regular expression> <option name>=<python expression> +class _setlocal(set_): + """Shared class for setinpath and setinregex - Gives an option a new value. + By implementing the _arg abstract propery you can affect what the name of + the pattern/path/regex argument can be, this should be a regular expression + without match groups. + + By implementing the _format_arg abstract method you can affect how the + argument is formatted as a regular expression. """ - PATH_RE_DQUOTED = re.compile(r'^setlocal\s+path="(.*?)"') - PATH_RE_SQUOTED = re.compile(r"^setlocal\s+path='(.*?)'") - PATH_RE_UNQUOTED = re.compile(r'^path=(.*?)$') + from abc import (ABCMeta, abstractmethod, abstractproperty) + + __metaclass__ = ABCMeta + + @abstractproperty + def _arg(self): + """The name of the option for the path/regex""" + raise NotImplementedError + + def __init__(self, *args, **kwargs): + super(set_, self).__init__(*args, **kwargs) + # We require quoting of paths with whitespace so we have to take care + # not to match escaped quotes. + self.PATH_RE_DQUOTED = re.compile( + r'^set.+?\s+{arg}="(.*?[^\\])"'.format(arg=self._arg()) + ) + self.PATH_RE_SQUOTED = re.compile( + r"^set.+?\s+{arg}='(.*?[^\\])'".format(arg=self._arg()) + ) + self.PATH_RE_UNQUOTED = re.compile( + r'^{arg}=(.+?)$'.format(arg=self._arg()) + ) def _re_shift(self, match): if not match: return None - path = os.path.expanduser(match.group(1)) - for _ in range(len(path.split())): + path = match.group(1) + for _ in range(1 + min(1, len(path.split()))): self.shift() - return path + return os.path.expanduser(path) + + @abstractmethod + def _format_arg(self, arg): + """How to format the argument as a regular expression""" + raise NotImplementedError def execute(self): - path = self._re_shift(self.PATH_RE_DQUOTED.match(self.line)) - if path is None: - path = self._re_shift(self.PATH_RE_SQUOTED.match(self.line)) - if path is None: - path = self._re_shift(self.PATH_RE_UNQUOTED.match(self.arg(1))) - if path is None and self.fm.thisdir: - path = "^" + re.escape(self.fm.thisdir.path) + "$" - if not path: + arg = self._re_shift(self.PATH_RE_DQUOTED.match(self.line)) + branch = 0 + if arg is None: + arg = self._re_shift(self.PATH_RE_SQUOTED.match(self.line)) + branch = 1 + if arg is None: + arg = self._re_shift(self.PATH_RE_UNQUOTED.match(self.arg(1))) + branch = 2 + if arg is None and self.fm.thisdir: + arg = self.fm.thisdir.path + branch = 3 + if arg is None: return + else: + arg = self._format_arg(arg) name, value, _ = self.parse_setting_line() - self.fm.set_option_from_string(name, value, localpath=path) + self.fm.set_option_from_string(name, value, localpath=arg) + + +class setinpath(_setlocal): + """:setinpath path=<path> <option name>=<python expression> + + Sets an option when in a directory that matches <path>, relative paths can + match multiple directories, for example, ``path=build`` would match a build + directory in any directory. If the <path> contains whitespace it needs to + be quoted and nested quotes need to be backslash-escaped. The "path" + argument can also be named "pattern" to allow for easier switching with + ``setinregex``. + """ + def _arg(self): + return "(?:path|pattern)" + + def _format_arg(self, arg): + return "{0}$".format(re.escape(arg)) + + +class setlocal(setinpath): + """:setlocal is an alias for :setinpath""" + pass class setintag(set_): |