diff options
-rw-r--r-- | README | 1 | ||||
-rw-r--r-- | ranger/core/actions.py | 13 | ||||
-rw-r--r-- | ranger/core/loader.py | 24 | ||||
-rw-r--r-- | ranger/defaults/keys.py | 3 | ||||
-rw-r--r-- | ranger/fsobject/directory.py | 27 | ||||
-rw-r--r-- | ranger/fsobject/fsobject.py | 14 | ||||
-rw-r--r-- | ranger/gui/ui.py | 2 | ||||
-rw-r--r-- | ranger/gui/widgets/console.py | 28 | ||||
-rw-r--r-- | ranger/gui/widgets/statusbar.py | 5 |
9 files changed, 88 insertions, 29 deletions
diff --git a/README b/README index 0f43f6bd..2b46411f 100644 --- a/README +++ b/README @@ -61,6 +61,7 @@ Dependencies Optional: * The "file" program * A pager ("less" by default) +* The python module "chardet", in case of encoding detection problems For scope.sh: (enhanced file previews) * img2txt (from caca-utils) for previewing images diff --git a/ranger/core/actions.py b/ranger/core/actions.py index 8a57330b..89bd9389 100644 --- a/ranger/core/actions.py +++ b/ranger/core/actions.py @@ -18,7 +18,7 @@ import re import shutil import string from os.path import join, isdir, realpath -from os import symlink, getcwd +from os import link, symlink, getcwd from inspect import cleandoc import ranger @@ -206,7 +206,7 @@ class Actions(FileManagerAware, EnvironmentAware, SettingsAware): if not self.env.enter_dir(cf) and selection: if self.execute_file(selection, mode=mode) is False: self.open_console('open_with ') - elif direction.vertical(): + elif direction.vertical() and cwd.files: newpos = direction.move( direction=direction.down(), override=narg, @@ -744,6 +744,13 @@ class Actions(FileManagerAware, EnvironmentAware, SettingsAware): except Exception as x: self.notify(x) + def paste_hardlink(self): + for f in self.env.copy: + try: + link(f.path, join(getcwd(), f.basename)) + except Exception as x: + self.notify(x) + def paste(self, overwrite=False): """Paste the selected items into the current directory""" copied_files = tuple(self.env.copy) @@ -795,7 +802,7 @@ class Actions(FileManagerAware, EnvironmentAware, SettingsAware): self.loader.add(obj) def delete(self): - self.notify("Deleting!", duration=1) + self.notify("Deleting!") selected = self.env.get_selection() self.env.copy -= set(selected) if selected: diff --git a/ranger/core/loader.py b/ranger/core/loader.py index 4341595c..7fd7dbab 100644 --- a/ranger/core/loader.py +++ b/ranger/core/loader.py @@ -23,7 +23,11 @@ import math import os import sys import select - +try: + import chardet + HAVE_CHARDET = True +except: + HAVE_CHARDET = False class Loadable(object): paused = False @@ -89,13 +93,13 @@ class CommandLoader(Loadable, SignalDispatcher, FileManagerAware): if rd == process.stderr: read = rd.readline() if py3: - read = read.decode('utf-8') + read = safeDecode(read) if read: self.fm.notify(read, bad=True) elif rd == process.stdout: read = rd.read(512) if py3: - read = read.decode('utf-8') + read = safeDecode(read) if read: self.stdout_buffer += read except select.error: @@ -103,12 +107,12 @@ class CommandLoader(Loadable, SignalDispatcher, FileManagerAware): if not self.silent: for l in process.stderr.readlines(): if py3: - l = l.decode('utf-8') + l = safeDecode(l) self.fm.notify(l, bad=True) if self.read: read = process.stdout.read() if py3: - read = read.decode('utf-8') + read = safeDecode(read) self.stdout_buffer += read self.finished = True self.signal_emit('after', process=process, loader=self) @@ -137,6 +141,16 @@ class CommandLoader(Loadable, SignalDispatcher, FileManagerAware): self.process.kill() +def safeDecode(string): + try: + return string.decode("utf-8") + except (UnicodeDecodeError): + if HAVE_CHARDET: + return string.decode(chardet.detect(str)["encoding"]) + else: + return "" + + class Loader(FileManagerAware): seconds_of_work_time = 0.03 throbber_chars = r'/-\|' diff --git a/ranger/defaults/keys.py b/ranger/defaults/keys.py index 782af310..ea98e4c5 100644 --- a/ranger/defaults/keys.py +++ b/ranger/defaults/keys.py @@ -180,6 +180,7 @@ map('pp', fm.paste()) map('po', fm.paste(overwrite=True)) map('pl', fm.paste_symlink(relative=False)) map('pL', fm.paste_symlink(relative=True)) +map('phl', fm.paste_hardlink()) map('p<bg>', fm.hint('press *p* to confirm pasting' \ ', *o*verwrite, create sym*l*inks, relative sym*L*inks')) @@ -194,7 +195,7 @@ map('du', fm.execute_console('shell -p du --max-depth=1 -h --apparent-size')) # -------------------------------------------------- toggle options map('z<bg>', fm.hint("[*cdfhimpPsv*] show_*h*idden *p*review_files "\ "*P*review_dirs *f*ilter flush*i*nput *m*ouse")) -map('zh', '<C-h>', '<backspace>', fm.toggle_boolean_option('show_hidden')) +map('zh', '<C-h>', fm.toggle_boolean_option('show_hidden')) map('zp', fm.toggle_boolean_option('preview_files')) map('zP', fm.toggle_boolean_option('preview_directories')) map('zv', fm.toggle_boolean_option('use_preview_script')) diff --git a/ranger/fsobject/directory.py b/ranger/fsobject/directory.py index 3c0f680d..7b8a7563 100644 --- a/ranger/fsobject/directory.py +++ b/ranger/fsobject/directory.py @@ -26,6 +26,7 @@ from ranger.ext.mount_path import mount_path from ranger.fsobject import BAD_INFO, File, FileSystemObject from ranger.core.shared import SettingsAware from ranger.ext.accumulator import Accumulator +from ranger.ext.lazy_property import lazy_property import ranger.fsobject def sort_by_basename(path): @@ -320,6 +321,32 @@ class Directory(FileSystemObject, Accumulator, Loadable, SettingsAware): else: self.correct_pointer() + @lazy_property + def size(self): + try: + size = len(os.listdir(self.path)) # bite me + except OSError: + self.infostring = '?' + self.accessible = False + return 0 + else: + self.infostring = ' %d' % size + self.accessible = True + self.runnable = True + return size + + @lazy_property + def infostring(self): + self.size # trigger the lazy property initializer + if self.is_link: + return '->' + self.infostring + return self.infostring + + @lazy_property + def runnable(self): + self.size # trigger the lazy property initializer + return self.runnable + def sort_if_outdated(self): """Sort the containing files if they are outdated""" if self.order_outdated: diff --git a/ranger/fsobject/fsobject.py b/ranger/fsobject/fsobject.py index bf71ac94..647b7604 100644 --- a/ranger/fsobject/fsobject.py +++ b/ranger/fsobject/fsobject.py @@ -231,20 +231,10 @@ class FileSystemObject(FileManagerAware): else: self.size = 0 self.infostring = '?' - elif self.is_directory: - try: - self.size = len(listdir(path)) # bite me - except OSError: - self.size = 0 - self.infostring = '?' - self.accessible = False - else: - self.infostring = ' %d' % self.size - self.accessible = True - self.runnable = True if is_link: - self.infostring = '->' + self.infostring self.is_link = True + if not self.is_directory: + self.infostring = '->' + self.infostring self.stat = new_stat diff --git a/ranger/gui/ui.py b/ranger/gui/ui.py index 2f27f11e..a2babed8 100644 --- a/ranger/gui/ui.py +++ b/ranger/gui/ui.py @@ -139,6 +139,8 @@ class UI(DisplayableContainer): if DisplayableContainer.press(self, key): return + self.status.clear_message() + self.env.keymanager.use_context('browser') self.env.key_append(key) kbuf = self.env.keybuffer diff --git a/ranger/gui/widgets/console.py b/ranger/gui/widgets/console.py index 9b1b0642..12f685d4 100644 --- a/ranger/gui/widgets/console.py +++ b/ranger/gui/widgets/console.py @@ -259,15 +259,29 @@ class Console(Widget): self.pos += len(self.copy) self.on_line_change() - def delete_word(self): + def delete_word(self, backward=True): if self.line: self.tab_deque = None - i = len(self.line) - 2 - while i >= 0 and re.match(r'[\w\d]', self.line[i], re.U): - i -= 1 - self.copy = self.line[i + 1:] - self.line = self.line[:i + 1] - self.pos = len(self.line) + if backward: + right_part = self.line[self.pos:] + i = self.pos - 2 + while i >= 0 and re.match(r'[\w\d]', self.line[i], re.U): + i -= 1 + self.copy = self.line[i + 1:self.pos] + self.line = self.line[:i + 1] + right_part + self.pos = i + 1 + else: + left_part = self.line[:self.pos] + i = self.pos + 1 + while i < len(self.line) and re.match(r'[\w\d]', self.line[i], re.U): + i += 1 + self.copy = self.line[self.pos:i] + if i >= len(self.line): + self.line = left_part + self.pos = len(self.line) + else: + self.line = left_part + self.line[i:] + self.pos = len(left_part) self.on_line_change() def delete(self, mod): diff --git a/ranger/gui/widgets/statusbar.py b/ranger/gui/widgets/statusbar.py index 2f3c67cf..b7ab123c 100644 --- a/ranger/gui/widgets/statusbar.py +++ b/ranger/gui/widgets/statusbar.py @@ -53,9 +53,12 @@ class StatusBar(Widget): def request_redraw(self): self.need_redraw = True - def notify(self, text, duration=4, bad=False): + def notify(self, text, duration=0, bad=False): self.msg = Message(text, duration, bad) + def clear_message(self): + self.msg = None + def draw(self): """Draw the statusbar""" |