summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--ranger/config/commands.py21
-rw-r--r--ranger/container/directory.py41
-rw-r--r--ranger/container/fsobject.py14
-rw-r--r--ranger/core/fm.py10
5 files changed, 71 insertions, 16 deletions
diff --git a/.gitignore b/.gitignore
index 55687146..5357ead2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,3 +3,4 @@
 *.pyo
 stuff/*
 doc/ranger.1.html
+build
diff --git a/ranger/config/commands.py b/ranger/config/commands.py
index 51bff937..2c5babba 100644
--- a/ranger/config/commands.py
+++ b/ranger/config/commands.py
@@ -1261,3 +1261,24 @@ class log(Command):
 
         pager = os.environ.get('PAGER', ranger.DEFAULT_PAGER)
         self.fm.run([pager, tmp.name])
+
+class flat(Command):
+    """
+    :flat <level>
+
+    Flattens the directory view up to level specified.
+        -1 fully flattened
+        0  remove flattened view
+    """
+
+    def execute(self):
+        try:
+            level = self.rest(1)
+            level = int(level)
+        except ValueError:
+            self.fm.notify("Need an integer number (-1, 0, 1, ...)", bad=True)
+            return
+        self.fm.thisdir.unload()
+        self.fm.thisdir.flat = level
+        self.fm.thisdir.load_content()
+
diff --git a/ranger/container/directory.py b/ranger/container/directory.py
index de69c467..c6987a76 100644
--- a/ranger/container/directory.py
+++ b/ranger/container/directory.py
@@ -52,6 +52,7 @@ class Directory(FileSystemObject, Accumulator, Loadable):
     cycle_list = None
     loading = False
     progressbar_supported = True
+    flat = 0
 
     filenames = None
     files = None
@@ -182,7 +183,7 @@ class Directory(FileSystemObject, Accumulator, Loadable):
         self.move_to_obj(self.pointed_obj)
 
     # XXX: Check for possible race conditions
-    def load_bit_by_bit(self):
+    def load_bit_by_bit(self, flat=0):
         """An iterator that loads a part on every next() call
 
         Returns a generator which load a part of the directory
@@ -193,6 +194,18 @@ class Directory(FileSystemObject, Accumulator, Loadable):
         self.percent = 0
         self.load_if_outdated()
 
+        basename_is_rel = True if flat else False
+
+        def walklevel(some_dir, level):
+            some_dir = some_dir.rstrip(os.path.sep)
+            assert os.path.isdir(some_dir)
+            num_sep = some_dir.count(os.path.sep)
+            for root, dirs, files in os.walk(some_dir):
+                yield root, dirs, files
+                num_sep_this = root.count(os.path.sep)
+                if level != -1 and num_sep + level <= num_sep_this:
+                    del dirs[:]
+
         try:
             if self.runnable:
                 yield
@@ -200,7 +213,17 @@ class Directory(FileSystemObject, Accumulator, Loadable):
 
                 self.mount_path = mount_path(mypath)
 
-                filelist = os.listdir(mypath)
+                if flat:
+                    filelist = []
+                    for dirpath, dirnames, filenames in walklevel(mypath, flat):
+                        filelist += [os.path.join("/", dirpath, d) for d in dirnames
+                                if dirpath.count(os.path.sep) - mypath.count(os.path.sep) == flat]
+                        filelist += [os.path.join("/", dirpath, f) for f in filenames]
+                    filenames = [os.path.relpath(name, mypath) for name in filelist]
+                else:
+                    filelist = os.listdir(mypath)
+                    filenames = [mypath + (mypath == '/' and fname or '/' + fname)
+                            for fname in filelist]
 
                 if self._cumulative_size_calculated:
                     # If self.content_loaded is true, this is not the first
@@ -220,8 +243,6 @@ class Directory(FileSystemObject, Accumulator, Loadable):
                 if self.is_link:
                     self.infostring = '->' + self.infostring
 
-                filenames = [mypath + (mypath == '/' and fname or '/' + fname)
-                        for fname in filelist]
                 yield
 
                 self.load_content_mtime = os.stat(mypath).st_mtime
@@ -249,14 +270,16 @@ class Directory(FileSystemObject, Accumulator, Loadable):
                         is_a_dir = False
                     if is_a_dir:
                         try:
-                            item = self.fm.get_directory(name)
+                            item = self.fm.get_directory(name,
+                                    basename_is_rel=basename_is_rel)
                             item.load_if_outdated()
                         except:
-                            item = Directory(name, preload=stats,
-                                    path_is_abs=True)
+                            item = Directory(name, preload=stats, path_is_abs=True,
+                                    basename_is_rel=basename_is_rel)
                             item.load()
                     else:
-                        item = File(name, preload=stats, path_is_abs=True)
+                        item = File(name, preload=stats, path_is_abs=True,
+                                    basename_is_rel=basename_is_rel)
                         item.load()
                         disk_usage += item.size
 
@@ -327,7 +350,7 @@ class Directory(FileSystemObject, Accumulator, Loadable):
                 schedule = True   # was: self.size > 30
 
             if self.load_generator is None:
-                self.load_generator = self.load_bit_by_bit()
+                self.load_generator = self.load_bit_by_bit(flat=self.flat)
 
                 if schedule and self.fm:
                     self.fm.loader.add(self)
diff --git a/ranger/container/fsobject.py b/ranger/container/fsobject.py
index dbcfcdca..6f206d0d 100644
--- a/ranger/container/fsobject.py
+++ b/ranger/container/fsobject.py
@@ -13,8 +13,8 @@ DOCUMENT_BASENAMES = ('bugs', 'bugs', 'changelog', 'copying', 'credits',
 BAD_INFO = '?'
 
 import re
-from os import lstat, stat
-from os.path import abspath, basename, dirname, realpath, splitext, extsep
+from os import lstat, stat, getcwd
+from os.path import abspath, basename, dirname, realpath, splitext, extsep, relpath
 from ranger.core.shared import FileManagerAware, SettingsAware
 from ranger.ext.shell_escape import shell_escape
 from ranger.ext.spawn import spawn
@@ -78,11 +78,17 @@ class FileSystemObject(FileManagerAware, SettingsAware):
     vcs_outdated = False
     vcs_enabled = False
 
-    def __init__(self, path, preload=None, path_is_abs=False):
+    basename_is_rel = False
+
+    def __init__(self, path, preload=None, path_is_abs=False, basename_is_rel=False):
         if not path_is_abs:
             path = abspath(path)
         self.path = path
-        self.basename = basename(path)
+        self.basename_is_rel = basename_is_rel
+        if not basename_is_rel:
+            self.basename = basename(path)
+        else:
+            self.basename = relpath(path, getcwd())
         self.basename_lower = self.basename.lower()
         self.extension = splitext(self.basename)[1].lstrip(extsep) or None
         self.dirname = dirname(path)
diff --git a/ranger/core/fm.py b/ranger/core/fm.py
index 2a9ce315..d567bf24 100644
--- a/ranger/core/fm.py
+++ b/ranger/core/fm.py
@@ -252,13 +252,17 @@ class FM(Actions, SignalDispatcher):
         """returns the path relative to rangers library directory"""
         return os.path.join(ranger.RANGERDIR, *paths)
 
-    def get_directory(self, path):
+    def get_directory(self, path, basename_is_rel = False):
         """Get the directory object at the given path"""
         path = os.path.abspath(path)
         try:
-            return self.directories[path]
+            directory = self.directories[path]
+            if directory.basename_is_rel != basename_is_rel:
+                del self.directories[path]
+                raise KeyError
+            return directory
         except KeyError:
-            obj = Directory(path)
+            obj = Directory(path, basename_is_rel = basename_is_rel)
             self.directories[path] = obj
             return obj