summary refs log tree commit diff stats
diff options
context:
space:
mode:
authornfnty <git@nfnty.se>2017-02-05 21:19:41 +0100
committernfnty <git@nfnty.se>2017-02-05 21:22:05 +0100
commitf7199d8e235bb033353da3b1274233b21fd6207f (patch)
treec864b9c4f55e483bd6f1c5ec7114bffbfe1357e5
parent24dd1af4f0bd05ad781e0f79723df2b07cb70218 (diff)
downloadranger-f7199d8e235bb033353da3b1274233b21fd6207f.tar.gz
Add `$XDG_DATA_HOME` support
Fixes #303
Fixes #448
-rw-r--r--doc/ranger.113
-rw-r--r--doc/ranger.pod15
-rw-r--r--ranger/__init__.py9
-rw-r--r--ranger/colorschemes/__init__.py2
-rwxr-xr-xranger/config/commands.py12
-rw-r--r--ranger/core/actions.py1
-rw-r--r--ranger/core/fm.py12
-rw-r--r--ranger/core/main.py46
-rw-r--r--ranger/gui/colorscheme.py10
-rw-r--r--ranger/gui/widgets/console.py2
10 files changed, 78 insertions, 44 deletions
diff --git a/doc/ranger.1 b/doc/ranger.1
index 193351d6..16abc635 100644
--- a/doc/ranger.1
+++ b/doc/ranger.1
@@ -139,7 +139,8 @@ ranger \- visual file manager
 .SH "SYNOPSIS"
 .IX Header "SYNOPSIS"
 \&\fBranger\fR [\fB\-\-version\fR] [\fB\-\-help\fR] [\fB\-\-debug\fR] [\fB\-\-clean\fR]
-[\fB\-\-confdir\fR=\fIdirectory\fR] [\fB\-\-copy\-config\fR=\fIwhich\fR]
+[\fB\-\-cachedir\fR=\fIdirectory\fR] [\fB\-\-confdir\fR=\fIdirectory\fR] [\fB\-\-datadir\fR=\fIdirectory\fR]
+[\fB\-\-copy\-config\fR=\fIwhich\fR]
 [\fB\-\-choosefile\fR=\fItarget\fR] [\fB\-\-choosefiles\fR=\fItarget\fR]
 [\fB\-\-choosedir\fR=\fItarget\fR] [\fB\-\-selectfile\fR=\fIfilepath\fR]
 [\fB\-\-list\-unused\-keys\fR] [\fB\-\-list\-tagged\-files\fR=\fItag\fR]
@@ -182,9 +183,15 @@ exception in the statusbar/log and try to keep running.
 Activate the clean mode:  ranger will not access or create any configuration
 files nor will it leave any traces on your system.  This is useful when your
 configuration is broken, when you want to avoid clutter, etc.
+.IP "\fB\-\-cachedir\fR=\fIdir\fR" 14
+.IX Item "--cachedir=dir"
+Change the cache directory of ranger from \f(CW$XDG_CACHE_HOME\fR or ~/.cache/ranger to \*(L"dir\*(R".
 .IP "\fB\-r\fR \fIdir\fR, \fB\-\-confdir\fR=\fIdir\fR" 14
 .IX Item "-r dir, --confdir=dir"
-Change the configuration directory of ranger from ~/.config/ranger to \*(L"dir\*(R".
+Change the configuration directory of ranger from \f(CW$XDG_CONFIG_HOME\fR or ~/.config/ranger to \*(L"dir\*(R".
+.IP "\fB\-\-datadir\fR=\fIdir\fR" 14
+.IX Item "--datadir=dir"
+Change the data directory of ranger from \f(CW$XDG_DATA_HOME\fR or ~/.local/share/ranger to \*(L"dir\*(R".
 .IP "\fB\-\-copy\-config\fR=\fIfile\fR" 14
 .IX Item "--copy-config=file"
 Create copies of the default configuration files in your local configuration
@@ -348,6 +355,8 @@ can use it for something like this command:
 .PP
 \&\f(CW%confdir\fR expands to the directory given by \fB\-\-confdir\fR.
 .PP
+\&\f(CW%datadir\fR expands to the directory given by \fB\-\-datadir\fR.
+.PP
 The macro \f(CW%space\fR expands to a space character. You can use it to add spaces to
 the end of a command when needed, while preventing editors to strip spaces off
 the end of the line automatically.
diff --git a/doc/ranger.pod b/doc/ranger.pod
index f11c5964..f77a6030 100644
--- a/doc/ranger.pod
+++ b/doc/ranger.pod
@@ -8,7 +8,8 @@ ranger - visual file manager
 =head1 SYNOPSIS
 
 B<ranger> [B<--version>] [B<--help>] [B<--debug>] [B<--clean>]
-[B<--confdir>=I<directory>] [B<--copy-config>=I<which>]
+[B<--cachedir>=I<directory>] [B<--confdir>=I<directory>] [B<--datadir>=I<directory>]
+[B<--copy-config>=I<which>]
 [B<--choosefile>=I<target>] [B<--choosefiles>=I<target>]
 [B<--choosedir>=I<target>] [B<--selectfile>=I<filepath>]
 [B<--list-unused-keys>] [B<--list-tagged-files>=I<tag>]
@@ -67,9 +68,17 @@ Activate the clean mode:  ranger will not access or create any configuration
 files nor will it leave any traces on your system.  This is useful when your
 configuration is broken, when you want to avoid clutter, etc.
 
+=item B<--cachedir>=I<dir>
+
+Change the cache directory of ranger from $XDG_CACHE_HOME or ~/.cache/ranger to "dir".
+
 =item B<-r> I<dir>, B<--confdir>=I<dir>
 
-Change the configuration directory of ranger from ~/.config/ranger to "dir".
+Change the configuration directory of ranger from $XDG_CONFIG_HOME or ~/.config/ranger to "dir".
+
+=item B<--datadir>=I<dir>
+
+Change the data directory of ranger from $XDG_DATA_HOME or ~/.local/share/ranger to "dir".
 
 =item B<--copy-config>=I<file>
 
@@ -246,6 +255,8 @@ can use it for something like this command:
 
 %confdir expands to the directory given by B<--confdir>.
 
+%datadir expands to the directory given by B<--datadir>.
+
 The macro %space expands to a space character. You can use it to add spaces to
 the end of a command when needed, while preventing editors to strip spaces off
 the end of the line automatically.
diff --git a/ranger/__init__.py b/ranger/__init__.py
index 8e320aee..e497ae06 100644
--- a/ranger/__init__.py
+++ b/ranger/__init__.py
@@ -26,14 +26,15 @@ TIME_BEFORE_FILE_BECOMES_GARBAGE = 1200
 MAX_RESTORABLE_TABS = 3
 MACRO_DELIMITER = '%'
 DEFAULT_PAGER = 'less'
-CACHEDIR = os.path.expanduser("~/.cache/ranger")
 USAGE = '%prog [options] [path]'
 VERSION = 'ranger-master %s\n\nPython %s' % (__version__, sys.version)
 
 
-# If the environment variable XDG_CONFIG_HOME is non-empty, CONFDIR is ignored
-# and the configuration directory will be $XDG_CONFIG_HOME/ranger instead.
-CONFDIR = '~/.config/ranger'
+# These variables are ignored if the corresponding
+# XDG environment variable is non-empty and absolute
+CACHEDIR = os.path.expanduser('~/.cache/ranger')
+CONFDIR = os.path.expanduser('~/.config/ranger')
+DATADIR = os.path.expanduser('~/.local/share/ranger')
 
 args = None  # pylint: disable=invalid-name
 
diff --git a/ranger/colorschemes/__init__.py b/ranger/colorschemes/__init__.py
index fb52df0e..9e55dc1e 100644
--- a/ranger/colorschemes/__init__.py
+++ b/ranger/colorschemes/__init__.py
@@ -1 +1 @@
-"""Colorschemes are required to be located here or in CONFDIR/colorschemes/"""
+"""Colorschemes are required to be located here or in confdir/colorschemes/"""
diff --git a/ranger/config/commands.py b/ranger/config/commands.py
index 7c118143..6fa5b904 100755
--- a/ranger/config/commands.py
+++ b/ranger/config/commands.py
@@ -370,7 +370,7 @@ class set_(Command):
             # Cycle through colorschemes when name, but no value is specified
             if name == "colorscheme":
                 return sorted(self.firstpart + colorscheme for colorscheme
-                              in get_all_colorschemes())
+                              in get_all_colorschemes(self.fm))
             return self.firstpart + str(settings[name])
         if bool in settings.types_of(name):
             if 'true'.startswith(value.lower()):
@@ -380,7 +380,7 @@ class set_(Command):
         # Tab complete colorscheme values if incomplete value is present
         if name == "colorscheme":
             return sorted(self.firstpart + colorscheme for colorscheme
-                          in get_all_colorschemes() if colorscheme.startswith(value))
+                          in get_all_colorschemes(self.fm) if colorscheme.startswith(value))
 
 
 class setlocal(set_):
@@ -661,14 +661,14 @@ class console(Command):
 class load_copy_buffer(Command):
     """:load_copy_buffer
 
-    Load the copy buffer from confdir/copy_buffer
+    Load the copy buffer from datadir/copy_buffer
     """
     copy_buffer_filename = 'copy_buffer'
 
     def execute(self):
         from ranger.container.file import File
         from os.path import exists
-        fname = self.fm.confpath(self.copy_buffer_filename)
+        fname = self.fm.datapath(self.copy_buffer_filename)
         try:
             fobj = open(fname, 'r')
         except OSError:
@@ -683,13 +683,13 @@ class load_copy_buffer(Command):
 class save_copy_buffer(Command):
     """:save_copy_buffer
 
-    Save the copy buffer to confdir/copy_buffer
+    Save the copy buffer to datadir/copy_buffer
     """
     copy_buffer_filename = 'copy_buffer'
 
     def execute(self):
         fname = None
-        fname = self.fm.confpath(self.copy_buffer_filename)
+        fname = self.fm.datapath(self.copy_buffer_filename)
         try:
             fobj = open(fname, 'w')
         except OSError:
diff --git a/ranger/core/actions.py b/ranger/core/actions.py
index 597b3279..ab549b37 100644
--- a/ranger/core/actions.py
+++ b/ranger/core/actions.py
@@ -275,6 +275,7 @@ class Actions(  # pylint: disable=too-many-instance-attributes,too-many-public-m
         macros['rangerdir'] = ranger.RANGERDIR
         if not ranger.args.clean:
             macros['confdir'] = self.fm.confpath()
+            macros['datadir'] = self.fm.datapath()
         macros['space'] = ' '
 
         if self.fm.thisfile:
diff --git a/ranger/core/fm.py b/ranger/core/fm.py
index a879ffad..002ecc0f 100644
--- a/ranger/core/fm.py
+++ b/ranger/core/fm.py
@@ -105,7 +105,7 @@ class FM(Actions,  # pylint: disable=too-many-instance-attributes
                                   priority=settings.SIGNAL_PRIORITY_AFTER_SYNC)
 
         if not ranger.args.clean and self.tags is None:
-            self.tags = Tags(self.confpath('tagged'))
+            self.tags = Tags(self.datapath('tagged'))
         elif ranger.args.clean:
             self.tags = TagsDummy("")
 
@@ -113,7 +113,7 @@ class FM(Actions,  # pylint: disable=too-many-instance-attributes
             if ranger.args.clean:
                 bookmarkfile = None
             else:
-                bookmarkfile = self.confpath('bookmarks')
+                bookmarkfile = self.datapath('bookmarks')
             self.bookmarks = Bookmarks(
                 bookmarkfile=bookmarkfile,
                 bookmarktype=Directory,
@@ -302,6 +302,14 @@ class FM(Actions,  # pylint: disable=too-many-instance-attributes
         assert not ranger.args.clean, "Accessed configuration directory in clean mode"
         return os.path.join(ranger.args.confdir, *paths)
 
+    def datapath(self, *paths):
+        """returns path to ranger's data directory"""
+        assert not ranger.args.clean, "Accessed data directory in clean mode"
+        path_compat = self.confpath(*paths)  # COMPAT
+        if os.path.exists(path_compat):
+            return path_compat
+        return os.path.join(ranger.args.datadir, *paths)
+
     @staticmethod
     def relpath(*paths):
         """returns the path relative to rangers library directory"""
diff --git a/ranger/core/main.py b/ranger/core/main.py
index 18fb7dd3..444f0287 100644
--- a/ranger/core/main.py
+++ b/ranger/core/main.py
@@ -52,8 +52,9 @@ def main(
     if 'SHELL' not in os.environ:
         os.environ['SHELL'] = 'sh'
 
-    LOG.debug("config dir: '%s'", args.confdir)
     LOG.debug("cache dir: '%s'", args.cachedir)
+    LOG.debug("config dir: '%s'", args.confdir)
+    LOG.debug("data dir: '%s'", args.datadir)
 
     if args.copy_config is not None:
         fm = FM()
@@ -63,9 +64,9 @@ def main(
         fm = FM()
         try:
             if sys.version_info[0] >= 3:
-                fobj = open(fm.confpath('tagged'), 'r', errors='replace')
+                fobj = open(fm.datapath('tagged'), 'r', errors='replace')
             else:
-                fobj = open(fm.confpath('tagged'), 'r')
+                fobj = open(fm.datapath('tagged'), 'r')
         except OSError:
             pass
         else:
@@ -134,6 +135,10 @@ def main(
         if fm.settings.preview_images and fm.settings.use_preview_script:
             if not os.path.exists(args.cachedir):
                 os.makedirs(args.cachedir)
+        # Create data directory
+        if not args.clean:
+            if not os.path.exists(args.datadir):
+                os.makedirs(args.datadir)
 
         # Run the file manager
         fm.initialize()
@@ -198,20 +203,17 @@ https://github.com/hut/ranger/issues
         return exit_code  # pylint: disable=lost-exception
 
 
+def xdg_path(env_var):
+    path = os.environ.get(env_var)
+    if path and os.path.isabs(path):
+        return os.path.join(path, 'ranger')
+    return None
+
+
 def parse_arguments():
     """Parse the program arguments"""
     from optparse import OptionParser  # pylint: disable=deprecated-module
-    from ranger import CONFDIR, CACHEDIR, USAGE, VERSION
-
-    if 'XDG_CONFIG_HOME' in os.environ and os.environ['XDG_CONFIG_HOME']:
-        default_confdir = os.environ['XDG_CONFIG_HOME'] + '/ranger'
-    else:
-        default_confdir = CONFDIR
-
-    if 'XDG_CACHE_HOME' in os.environ and os.environ['XDG_CACHE_HOME']:
-        default_cachedir = os.environ['XDG_CACHE_HOME'] + '/ranger'
-    else:
-        default_cachedir = CACHEDIR
+    from ranger import CONFDIR, CACHEDIR, DATADIR, USAGE, VERSION
 
     parser = OptionParser(usage=USAGE, version=VERSION)
 
@@ -221,12 +223,15 @@ def parse_arguments():
                       help="don't touch/require any config files. ")
     parser.add_option('--logfile', type='string', metavar='file',
                       help="log file to use, '-' for stderr")
-    parser.add_option('-r', '--confdir', type='string',
-                      metavar='dir', default=default_confdir,
-                      help="change the configuration directory. (%default)")
     parser.add_option('--cachedir', type='string',
-                      metavar='dir', default=default_cachedir,
+                      metavar='dir', default=(xdg_path('XDG_CACHE_HOME') or CACHEDIR),
                       help="change the cache directory. (%default)")
+    parser.add_option('-r', '--confdir', type='string',
+                      metavar='dir', default=(xdg_path('XDG_CONFIG_HOME') or CONFDIR),
+                      help="change the configuration directory. (%default)")
+    parser.add_option('--datadir', type='string',
+                      metavar='dir', default=(xdg_path('XDG_DATA_HOME') or DATADIR),
+                      help="change the data directory. (%default)")
     parser.add_option('--copy-config', type='string', metavar='which',
                       help="copy the default configs to the local config directory. "
                       "Possible values: all, rc, rifle, commands, commands_full, scope")
@@ -270,10 +275,9 @@ def parse_arguments():
             sys.exit(1)
         return path
 
-    args.confdir = os.path.expanduser(args.confdir)
-    args.confdir = path_init('confdir')
-    args.cachedir = os.path.expanduser(args.cachedir)
     args.cachedir = path_init('cachedir')
+    args.confdir = path_init('confdir')
+    args.datadir = path_init('datadir')
     if args.choosefile:
         args.choosefile = path_init('choosefile')
     if args.choosefiles:
diff --git a/ranger/gui/colorscheme.py b/ranger/gui/colorscheme.py
index 4e26c81e..01862957 100644
--- a/ranger/gui/colorscheme.py
+++ b/ranger/gui/colorscheme.py
@@ -143,16 +143,16 @@ def _colorscheme_name_to_class(signal):  # pylint: disable=too-many-branches
                 raise ColorSchemeError("The module contains no valid colorscheme!")
 
 
-def get_all_colorschemes():
+def get_all_colorschemes(fm):
     colorschemes = set()
     # Load colorscheme names from main ranger/colorschemes dir
-    for item in os.listdir(ranger.RANGERDIR + '/colorschemes'):
+    for item in os.listdir(os.path.join(ranger.RANGERDIR, 'colorschemes')):
         if not item.startswith('__'):
             colorschemes.add(item.rsplit('.', 1)[0])
     # Load colorscheme names from ~/.config/ranger/colorschemes if dir exists
-    if os.path.isdir(os.path.expanduser(ranger.CONFDIR + '/colorschemes')):
-        for item in os.listdir(os.path.expanduser(
-                ranger.CONFDIR + '/colorschemes')):
+    confpath = fm.confpath('colorschemes')
+    if os.path.isdir(confpath):
+        for item in os.listdir(confpath):
             if not item.startswith('__'):
                 colorschemes.add(item.rsplit('.', 1)[0])
     return list(sorted(colorschemes))
diff --git a/ranger/gui/widgets/console.py b/ranger/gui/widgets/console.py
index 86a80177..5d7f6b0e 100644
--- a/ranger/gui/widgets/console.py
+++ b/ranger/gui/widgets/console.py
@@ -40,7 +40,7 @@ class Console(Widget):  # pylint: disable=too-many-instance-attributes,too-many-
         self.history = History(self.settings.max_console_history_size)
         # load history from files
         if not ranger.args.clean:
-            self.historypath = self.fm.confpath('history')
+            self.historypath = self.fm.datapath('history')
             if os.path.exists(self.historypath):
                 try:
                     fobj = open(self.historypath, 'r')