From 518cda572449aa16f2cfdbc7690a5ad030f145b5 Mon Sep 17 00:00:00 2001 From: Milan Svoboda Date: Sat, 22 Nov 2014 08:53:21 +0100 Subject: fixes to flat command --- ranger/container/directory.py | 71 ++++++++++++++++++++++--------------- ranger/container/fsobject.py | 16 +++++---- ranger/core/fm.py | 10 ++---- ranger/gui/widgets/browsercolumn.py | 2 +- ranger/gui/widgets/titlebar.py | 2 +- 5 files changed, 57 insertions(+), 44 deletions(-) diff --git a/ranger/container/directory.py b/ranger/container/directory.py index c6987a76..506d1052 100644 --- a/ranger/container/directory.py +++ b/ranger/container/directory.py @@ -20,7 +20,7 @@ from ranger.container.settings import LocalSettings def sort_by_basename(path): """returns path.basename (for sorting)""" - return path.basename + return path.drawn_basename def sort_by_basename_icase(path): """returns case-insensitive path.basename (for sorting)""" @@ -45,6 +45,24 @@ def accept_file(fname, directory, hidden_filter, name_filter): return False return True +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[:] + +def mtimelevel(path, level): + mtime = os.stat(path).st_mtime + for dirpath, dirnames, filenames in walklevel(path, level): + dirlist = [os.path.join("/", dirpath, d) for d in dirnames + if level == -1 or dirpath.count(os.path.sep) - path.count(os.path.sep) <= level] + mtime = max(mtime, max([-1] + [os.stat(d).st_mtime for d in dirlist])) + return mtime + class Directory(FileSystemObject, Accumulator, Loadable): is_directory = True enterable = False @@ -183,7 +201,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, flat=0): + def load_bit_by_bit(self): """An iterator that loads a part on every next() call Returns a generator which load a part of the directory @@ -194,17 +212,7 @@ 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[:] + basename_is_rel_to = self.path if self.flat else None try: if self.runnable: @@ -213,17 +221,20 @@ class Directory(FileSystemObject, Accumulator, Loadable): self.mount_path = mount_path(mypath) - if flat: + if self.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] + for dirpath, dirnames, filenames in walklevel(mypath, self.flat): + dirlist = [os.path.join("/", dirpath, d) for d in dirnames + if self.flat == -1 or dirpath.count(os.path.sep) - mypath.count(os.path.sep) <= self.flat] + filelist += dirlist filelist += [os.path.join("/", dirpath, f) for f in filenames] - filenames = [os.path.relpath(name, mypath) for name in filelist] + filenames = filelist + self.load_content_mtime = mtimelevel(mypath, self.flat) else: filelist = os.listdir(mypath) filenames = [mypath + (mypath == '/' and fname or '/' + fname) for fname in filelist] + self.load_content_mtime = os.stat(mypath).st_mtime if self._cumulative_size_calculated: # If self.content_loaded is true, this is not the first @@ -245,8 +256,6 @@ class Directory(FileSystemObject, Accumulator, Loadable): yield - self.load_content_mtime = os.stat(mypath).st_mtime - marked_paths = [obj.path for obj in self.marked_items] files = [] @@ -270,16 +279,19 @@ class Directory(FileSystemObject, Accumulator, Loadable): is_a_dir = False if is_a_dir: try: - item = self.fm.get_directory(name, - basename_is_rel=basename_is_rel) - item.load_if_outdated() + if self.flat: + item = Directory(name, preload=stats, path_is_abs=True, + basename_is_rel_to=basename_is_rel_to) + item.load() + else: + item = self.fm.get_directory(name) + item.load_if_outdated() except: - item = Directory(name, preload=stats, path_is_abs=True, - basename_is_rel=basename_is_rel) + item = Directory(name, preload=stats, path_is_abs=True) item.load() else: item = File(name, preload=stats, path_is_abs=True, - basename_is_rel=basename_is_rel) + basename_is_rel_to=basename_is_rel_to) item.load() disk_usage += item.size @@ -350,7 +362,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(flat=self.flat) + self.load_generator = self.load_bit_by_bit() if schedule and self.fm: self.fm.loader.add(self) @@ -530,7 +542,10 @@ class Directory(FileSystemObject, Accumulator, Loadable): return True try: - real_mtime = os.stat(self.path).st_mtime + if self.flat: + real_mtime = mtimelevel(self.path, self.flat) + else: + real_mtime = os.stat(self.path).st_mtime except OSError: real_mtime = None return False diff --git a/ranger/container/fsobject.py b/ranger/container/fsobject.py index 6f206d0d..ef1938ff 100644 --- a/ranger/container/fsobject.py +++ b/ranger/container/fsobject.py @@ -78,18 +78,20 @@ class FileSystemObject(FileManagerAware, SettingsAware): vcs_outdated = False vcs_enabled = False - basename_is_rel = False + basename_is_rel_to = None - 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_to=None): if not path_is_abs: path = abspath(path) self.path = path - self.basename_is_rel = basename_is_rel - if not basename_is_rel: + self.basename_is_rel_to = basename_is_rel_to + if basename_is_rel_to == None: self.basename = basename(path) + self.drawn_basename = self.basename else: - self.basename = relpath(path, getcwd()) - self.basename_lower = self.basename.lower() + self.basename = basename(path) + self.drawn_basename = relpath(path, basename_is_rel_to) + self.basename_lower = self.drawn_basename.lower() self.extension = splitext(self.basename)[1].lstrip(extsep) or None self.dirname = dirname(path) self.preload = preload @@ -118,7 +120,7 @@ class FileSystemObject(FileManagerAware, SettingsAware): @lazy_property def basename_natural(self): return [c if i % 3 == 1 else (int(c) if c else 0) for i, c in \ - enumerate(_extract_number_re.split(self.basename))] + enumerate(_extract_number_re.split(self.drawn_basename))] @lazy_property def basename_natural_lower(self): diff --git a/ranger/core/fm.py b/ranger/core/fm.py index d567bf24..2a9ce315 100644 --- a/ranger/core/fm.py +++ b/ranger/core/fm.py @@ -252,17 +252,13 @@ class FM(Actions, SignalDispatcher): """returns the path relative to rangers library directory""" return os.path.join(ranger.RANGERDIR, *paths) - def get_directory(self, path, basename_is_rel = False): + def get_directory(self, path): """Get the directory object at the given path""" path = os.path.abspath(path) try: - directory = self.directories[path] - if directory.basename_is_rel != basename_is_rel: - del self.directories[path] - raise KeyError - return directory + return self.directories[path] except KeyError: - obj = Directory(path, basename_is_rel = basename_is_rel) + obj = Directory(path) self.directories[path] = obj return obj diff --git a/ranger/gui/widgets/browsercolumn.py b/ranger/gui/widgets/browsercolumn.py index 0edb9c8d..55601130 100644 --- a/ranger/gui/widgets/browsercolumn.py +++ b/ranger/gui/widgets/browsercolumn.py @@ -257,7 +257,7 @@ class BrowserColumn(Pager): self.color_reset() continue - text = drawn.basename + text = drawn.drawn_basename if drawn.marked and (self.main_column or \ self.settings.display_tags_in_all_columns): text = " " + text diff --git a/ranger/gui/widgets/titlebar.py b/ranger/gui/widgets/titlebar.py index fa10a744..25edd5e4 100644 --- a/ranger/gui/widgets/titlebar.py +++ b/ranger/gui/widgets/titlebar.py @@ -117,7 +117,7 @@ class TitleBar(Widget): if self.fm.thisfile is not None and \ self.settings.show_selection_in_titlebar: - bar.add(self.fm.thisfile.basename, 'file') + bar.add(self.fm.thisfile.drawn_basename, 'file') def _get_right_part(self, bar): # TODO: fix that pressed keys are cut off when chaining CTRL keys -- cgit 1.4.1-2-gfad0 From 9f7001379a88666ad07c7d04a5164ef802499481 Mon Sep 17 00:00:00 2001 From: Milan Svoboda Date: Sat, 22 Nov 2014 09:14:03 +0100 Subject: follow symlinks to directories if flat is not -1 --- ranger/container/directory.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ranger/container/directory.py b/ranger/container/directory.py index 506d1052..f0cb4067 100644 --- a/ranger/container/directory.py +++ b/ranger/container/directory.py @@ -47,9 +47,10 @@ def accept_file(fname, directory, hidden_filter, name_filter): def walklevel(some_dir, level): some_dir = some_dir.rstrip(os.path.sep) + followlinks = True if level > 0 else False assert os.path.isdir(some_dir) num_sep = some_dir.count(os.path.sep) - for root, dirs, files in os.walk(some_dir): + for root, dirs, files in os.walk(some_dir, followlinks=followlinks): yield root, dirs, files num_sep_this = root.count(os.path.sep) if level != -1 and num_sep + level <= num_sep_this: -- cgit 1.4.1-2-gfad0 From fd808da18aff05c8b7e1bd2c15a8cdfb1ee7ba28 Mon Sep 17 00:00:00 2001 From: Milan Svoboda Date: Sun, 23 Nov 2014 15:21:58 +0100 Subject: move self.flat branch out of try block --- ranger/container/directory.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/ranger/container/directory.py b/ranger/container/directory.py index f0cb4067..2f1e5e11 100644 --- a/ranger/container/directory.py +++ b/ranger/container/directory.py @@ -279,17 +279,17 @@ class Directory(FileSystemObject, Accumulator, Loadable): stats = None is_a_dir = False if is_a_dir: - try: - if self.flat: - item = Directory(name, preload=stats, path_is_abs=True, - basename_is_rel_to=basename_is_rel_to) - item.load() - else: + if self.flat: + item = Directory(name, preload=stats, path_is_abs=True, + basename_is_rel_to=basename_is_rel_to) + item.load() + else: + try: item = self.fm.get_directory(name) item.load_if_outdated() - except: - item = Directory(name, preload=stats, path_is_abs=True) - item.load() + except: + item = Directory(name, preload=stats, path_is_abs=True) + item.load() else: item = File(name, preload=stats, path_is_abs=True, basename_is_rel_to=basename_is_rel_to) -- cgit 1.4.1-2-gfad0 From 2e7f35a52f0ab0d6402df26a59573218552518a4 Mon Sep 17 00:00:00 2001 From: Milan Svoboda Date: Tue, 25 Nov 2014 21:44:24 +0100 Subject: add documentation for flat command --- doc/ranger.pod | 7 +++++++ ranger/config/commands.py | 7 +++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/doc/ranger.pod b/doc/ranger.pod index 370bbb85..eb13d2b8 100644 --- a/doc/ranger.pod +++ b/doc/ranger.pod @@ -818,6 +818,7 @@ ranger. For your convenience, this is a list of the "public" commands including eval [-q] python_code filter [string] find pattern + flat level grep pattern load_copy_buffer map key command @@ -963,6 +964,12 @@ be run immediately. (Or entered, if it's a directory.) This command is based on the I command and supports all of its options. +=item flat level + +Flattens the directory view up to the specified level. Level -1 means infinite +level. Level 0 means standard view without flattened directory view. Level +values -2 and less are invalid. + =item grep I Looks for a string in all marked files or directories. diff --git a/ranger/config/commands.py b/ranger/config/commands.py index 953e2cc3..b0089e59 100644 --- a/ranger/config/commands.py +++ b/ranger/config/commands.py @@ -1266,9 +1266,10 @@ class flat(Command): """ :flat - Flattens the directory view up to level specified. + Flattens the directory view up to the specified level. + -1 fully flattened - 0 remove flattened view + 0 remove flattened view """ def execute(self): @@ -1277,6 +1278,8 @@ class flat(Command): level = int(level) except ValueError: level = self.quantifier + if level < -1: + self.fm.notify("Need an integer number (-1, 0, 1, ...)", bad=True) self.fm.thisdir.unload() self.fm.thisdir.flat = level self.fm.thisdir.load_content() -- cgit 1.4.1-2-gfad0