diff options
-rw-r--r-- | ranger/colorschemes/default.py | 10 | ||||
-rw-r--r-- | ranger/core/actions.py | 18 | ||||
-rw-r--r-- | ranger/defaults/commands.py | 2 | ||||
-rw-r--r-- | ranger/fsobject/__init__.py | 2 | ||||
-rw-r--r-- | ranger/fsobject/fsobject.py | 81 | ||||
-rw-r--r-- | ranger/gui/context.py | 4 | ||||
-rw-r--r-- | ranger/gui/widgets/browsercolumn.py | 41 | ||||
-rw-r--r-- | ranger/gui/widgets/statusbar.py | 18 | ||||
-rw-r--r-- | ranger/gui/widgets/titlebar.py | 2 | ||||
-rw-r--r-- | ranger/help/console.py | 2 | ||||
-rw-r--r-- | ranger/help/movement.py | 2 |
11 files changed, 107 insertions, 75 deletions
diff --git a/ranger/colorschemes/default.py b/ranger/colorschemes/default.py index ca8456e7..317e8258 100644 --- a/ranger/colorschemes/default.py +++ b/ranger/colorschemes/default.py @@ -49,8 +49,11 @@ class Default(ColorScheme): fg = green if context.socket: fg = magenta - if context.fifo: + attr |= bold + if context.fifo or context.device: fg = yellow + if context.device: + attr |= bold if context.link: fg = context.good and cyan or magenta if context.tag_marker and not context.selected: @@ -68,6 +71,11 @@ class Default(ColorScheme): if context.marked: attr |= bold fg = yellow + if context.badinfo: + if attr & reverse: + bg = magenta + else: + fg = magenta elif context.in_titlebar: attr |= bold diff --git a/ranger/core/actions.py b/ranger/core/actions.py index b320396a..2fd7d46d 100644 --- a/ranger/core/actions.py +++ b/ranger/core/actions.py @@ -15,14 +15,18 @@ import os import shutil +from os.path import join, isdir +from os import symlink, getcwd from inspect import cleandoc import ranger from ranger.ext.direction import Direction -from ranger.shared import FileManagerAware, EnvironmentAware, SettingsAware from ranger import fsobject +from ranger.shared import FileManagerAware, EnvironmentAware, SettingsAware from ranger.gui.widgets import console_mode as cmode from ranger.fsobject import File +from ranger.ext import shutil_generatorized as shutil_g +from ranger.fsobject.loader import LoadableObject class Actions(FileManagerAware, EnvironmentAware, SettingsAware): search_method = 'ctime' @@ -569,14 +573,7 @@ class Actions(FileManagerAware, EnvironmentAware, SettingsAware): self.ui.browser.main_column.request_redraw() def paste_symlink(self): - from os import symlink, getcwd - from os.path import join - copied_files = self.env.copy - - if not copied_files: - return - for f in copied_files: try: symlink(f.path, join(getcwd(), f.basename)) @@ -585,9 +582,6 @@ class Actions(FileManagerAware, EnvironmentAware, SettingsAware): def paste(self, overwrite=False): """Paste the selected items into the current directory""" - from os.path import join, isdir - from ranger.ext import shutil_generatorized as shutil_g - from ranger.fsobject.loader import LoadableObject copied_files = tuple(self.env.copy) if not copied_files: @@ -643,7 +637,7 @@ class Actions(FileManagerAware, EnvironmentAware, SettingsAware): self.env.copy -= set(selected) if selected: for f in selected: - if os.path.isdir(f.path) and not os.path.islink(f.path): + if isdir(f.path) and not os.path.islink(f.path): try: shutil.rmtree(f.path) except OSError as err: diff --git a/ranger/defaults/commands.py b/ranger/defaults/commands.py index 03fa1634..f04c4889 100644 --- a/ranger/defaults/commands.py +++ b/ranger/defaults/commands.py @@ -332,7 +332,7 @@ class delete(Command): cwd = self.fm.env.cwd cf = self.fm.env.cf - if cwd.marked_items or (cf.is_directory and not cf.islink \ + if cwd.marked_items or (cf.is_directory and not cf.is_link \ and len(os.listdir(cf.path)) > 0): # better ask for a confirmation, when attempting to # delete multiple files or a non-empty directory. diff --git a/ranger/fsobject/__init__.py b/ranger/fsobject/__init__.py index 5f727c87..6796f252 100644 --- a/ranger/fsobject/__init__.py +++ b/ranger/fsobject/__init__.py @@ -21,7 +21,7 @@ T_DIRECTORY = 'directory' T_UNKNOWN = 'unknown' T_NONEXISTANT = 'nonexistant' -BAD_INFO = None +BAD_INFO = '?' class NotLoadedYet(Exception): pass diff --git a/ranger/fsobject/fsobject.py b/ranger/fsobject/fsobject.py index 1ab3addd..94729b9a 100644 --- a/ranger/fsobject/fsobject.py +++ b/ranger/fsobject/fsobject.py @@ -16,11 +16,18 @@ CONTAINER_EXTENSIONS = 'rar zip tar gz bz bz2 tgz 7z iso cab'.split() DOCUMENT_EXTENSIONS = 'pdf doc ppt odt'.split() DOCUMENT_BASENAMES = 'README TODO LICENSE COPYING INSTALL'.split() - -import time +DOCUMENT_EXTENSIONS = () +DOCUMENT_BASENAMES = () + +import stat +import os +from time import time +from subprocess import Popen, PIPE +from os.path import abspath, basename, dirname, realpath from . import T_FILE, T_DIRECTORY, T_UNKNOWN, T_NONEXISTANT, BAD_INFO from ranger.shared import MimeTypeAware, FileManagerAware from ranger.ext.shell_escape import shell_escape +from ranger.ext.human_readable import human_readable class FileSystemObject(MimeTypeAware, FileManagerAware): is_file = False @@ -40,7 +47,10 @@ class FileSystemObject(MimeTypeAware, FileManagerAware): tagged = False loaded = False runnable = False - islink = False + is_link = False + is_device = False + is_socket = False + is_fifo = False readlink = None stat = None infostring = None @@ -62,20 +72,17 @@ class FileSystemObject(MimeTypeAware, FileManagerAware): def __init__(self, path): MimeTypeAware.__init__(self) - if type(self) == FileSystemObject: - raise TypeError("Cannot initialize abstract class FileSystemObject") - - from os.path import abspath, basename, dirname, realpath path = abspath(path) self.path = path self.basename = basename(path) self.basename_lower = self.basename.lower() self.dirname = dirname(path) - self.realpath = realpath(path) + self.realpath = self.path try: - self.extension = self.basename[self.basename.rindex('.') + 1:].lower() + lastdot = self.basename.rindex('.') + 1 + self.extension = self.basename[lastdot:].lower() except ValueError: self.extension = None @@ -94,10 +101,9 @@ class FileSystemObject(MimeTypeAware, FileManagerAware): @property def filetype(self): if self._filetype is None: - import subprocess try: - got = subprocess.Popen(["file", '-Lb', '--mime-type',\ - self.path], stdout=subprocess.PIPE).communicate()[0] + got = Popen(["file", '-Lb', '--mime-type', self.path], + stdout=PIPE).communicate()[0] except OSError: self._filetype = '' else: @@ -113,13 +119,13 @@ class FileSystemObject(MimeTypeAware, FileManagerAware): def use(self): """mark the filesystem-object as used at the current time""" - self.last_used = time.time() + self.last_used = time() def is_older_than(self, seconds): """returns whether this object wasn't use()d in the last n seconds""" if seconds < 0: return True - return self.last_used + seconds < time.time() + return self.last_used + seconds < time() def set_mimetype(self): """assign attributes such as self.video according to the mimetype""" @@ -155,9 +161,6 @@ class FileSystemObject(MimeTypeAware, FileManagerAware): reads useful information about the filesystem-object from the filesystem and caches it for later use """ - import os - import stat - from ranger.ext.human_readable import human_readable self.loaded = True @@ -165,10 +168,21 @@ class FileSystemObject(MimeTypeAware, FileManagerAware): self.stat = os.lstat(self.path) except OSError: self.stat = None - self.islink = False + self.is_link = False self.accessible = False else: - self.islink = stat.S_ISLNK(self.stat.st_mode) + self.is_link = stat.S_ISLNK(self.stat.st_mode) + if self.is_link: + try: # try to resolve the link + self.readlink = os.readlink(self.path) + self.realpath = realpath(self.path) + self.stat = os.stat(self.path) + except: # it failed, so it must be a broken link + pass + mode = self.stat.st_mode + self.is_device = bool(stat.S_ISCHR(mode) or stat.S_ISBLK(mode)) + self.is_socket = bool(stat.S_ISSOCK(mode)) + self.is_fifo = bool(stat.S_ISFIFO(mode)) self.accessible = True if self.accessible and os.access(self.path, os.F_OK): @@ -191,10 +205,17 @@ class FileSystemObject(MimeTypeAware, FileManagerAware): self.infostring = ' ' + human_readable(self.stat.st_size) else: self.type = T_UNKNOWN - self.infostring = None + if self.is_device: + self.infostring = 'dev' + elif self.is_fifo: + self.infostring = 'fifo' + elif self.is_socket: + self.infostring = 'sock' + else: + self.infostring = BAD_INFO else: - if self.islink: + if self.is_link: self.infostring = '->' else: self.infostring = None @@ -202,18 +223,14 @@ class FileSystemObject(MimeTypeAware, FileManagerAware): self.exists = False self.runnable = False - if self.islink: - self.readlink = os.readlink(self.path) - def get_permission_string(self): if self.permissions is not None: return self.permissions - if self.accessible is False: - return '----------' - - import stat - mode = self.stat.st_mode + try: + mode = self.stat.st_mode + except: + return '----??----' if stat.S_ISDIR(mode): perms = ['d'] @@ -250,9 +267,8 @@ class FileSystemObject(MimeTypeAware, FileManagerAware): Calls load() if the currently cached information is outdated or nonexistant. """ - if self.load_once(): return True - - import os + if self.load_once(): + return True try: real_mtime = os.lstat(self.path).st_mtime except OSError: @@ -261,7 +277,6 @@ class FileSystemObject(MimeTypeAware, FileManagerAware): cached_mtime = self.stat.st_mtime else: cached_mtime = 0 - if real_mtime != cached_mtime: self.load() return True diff --git a/ranger/gui/context.py b/ranger/gui/context.py index d4c1c94d..1e127a2e 100644 --- a/ranger/gui/context.py +++ b/ranger/gui/context.py @@ -13,11 +13,11 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. -CONTEXT_KEYS = ['reset', 'error', +CONTEXT_KEYS = ['reset', 'error', 'badinfo', 'in_browser', 'in_statusbar', 'in_titlebar', 'in_console', 'in_pager', 'in_taskview', 'directory', 'file', 'hostname', - 'executable', 'media', 'link', 'fifo', 'socket', + 'executable', 'media', 'link', 'fifo', 'socket', 'device', 'video', 'audio', 'image', 'media', 'document', 'container', 'selected', 'empty', 'main_column', 'message', 'background', 'good', 'bad', diff --git a/ranger/gui/widgets/browsercolumn.py b/ranger/gui/widgets/browsercolumn.py index 8cf8990c..61c74e63 100644 --- a/ranger/gui/widgets/browsercolumn.py +++ b/ranger/gui/widgets/browsercolumn.py @@ -20,6 +20,7 @@ from time import time from . import Widget from .pager import Pager +from ranger.fsobject import BAD_INFO # Don't even try to preview files which mach this regular expression: PREVIEW_BLACKLIST = re.compile(r""" @@ -95,20 +96,21 @@ class BrowserColumn(Pager): pass elif self.target.type is T_DIRECTORY: - index = self.scroll_begin + event.y - self.y - - if event.pressed(1): - if not self.main_column: - self.fm.enter_dir(self.target.path) - - if index < len(self.target): - self.fm.move(to=index) - elif event.pressed(3): - try: - clicked_file = self.target.files[index] - self.fm.enter_dir(clicked_file.path) - except: - pass + if self.target.accessible and self.target.content_loaded: + index = self.scroll_begin + event.y - self.y + + if event.pressed(1): + if not self.main_column: + self.fm.enter_dir(self.target.path) + + if index < len(self.target): + self.fm.move(to=index) + elif event.pressed(3): + try: + clicked_file = self.target.files[index] + self.fm.enter_dir(clicked_file.path) + except: + pass else: if self.level > 0: @@ -173,6 +175,7 @@ class BrowserColumn(Pager): and target.is_file \ and target.accessible \ and target.stat \ + and not target.is_device \ and not target.stat.st_mode & stat.S_IFIFO): return False @@ -250,6 +253,7 @@ class BrowserColumn(Pager): except IndexError: break + bad_info_color = None this_color = base_color + list(drawn.mimetype_tuple) text = drawn.basename tagged = self.fm.tags and drawn.realpath in self.fm.tags @@ -280,11 +284,13 @@ class BrowserColumn(Pager): this_color.append('fifo') if stat.S_ISSOCK(mode): this_color.append('socket') + if drawn.is_device: + this_color.append('device') if self.env.copy and drawn in self.env.copy: this_color.append('cut' if self.env.cut else 'copied') - if drawn.islink: + if drawn.is_link: this_color.append('link') this_color.append(drawn.exists and 'good' or 'bad') @@ -302,6 +308,8 @@ class BrowserColumn(Pager): and self.settings.display_size_in_main_column: info = drawn.infostring x = self.wid - 1 - len(info) + if info is BAD_INFO: + bad_info_color = (x, len(str(info))) if x > self.x: self.win.addstr(line, x, str(info) + ' ') except: @@ -310,6 +318,9 @@ class BrowserColumn(Pager): pass self.color_at(line, 0, self.wid, this_color) + if bad_info_color: + start, wid = bad_info_color + self.color_at(line, start, wid, this_color, 'badinfo') if self.main_column and tagged and self.wid > 2: this_color.append('tag_marker') diff --git a/ranger/gui/widgets/statusbar.py b/ranger/gui/widgets/statusbar.py index caf5786e..bff3d8ad 100644 --- a/ranger/gui/widgets/statusbar.py +++ b/ranger/gui/widgets/statusbar.py @@ -145,23 +145,27 @@ class StatusBar(Widget): target = self.column.target.pointed_obj else: target = self.env.at_level(0).pointed_obj - if target is None or not target.accessible: + try: + stat = target.stat + except: + return + if stat is None: return perms = target.get_permission_string() - how = getuid() == target.stat.st_uid and 'good' or 'bad' + how = getuid() == stat.st_uid and 'good' or 'bad' left.add(perms, 'permissions', how) - left.add_space() - left.add(str(target.stat.st_nlink), 'nlink') + left.add(str(stat.st_nlink), 'nlink') left.add_space() left.add(self._get_owner(target), 'owner') left.add_space() left.add(self._get_group(target), 'group') - if target.islink: + if target.is_link: how = target.exists and 'good' or 'bad' - left.add(' -> ' + target.readlink, 'link', how) + dest = target.readlink if target.readlink is not None else '?' + left.add(' -> ' + dest, 'link', how) else: if self.settings.display_size_in_status_bar and target.infostring: left.add(target.infostring) @@ -169,7 +173,7 @@ class StatusBar(Widget): left.add_space() left.add(strftime(self.timeformat, - localtime(target.stat.st_mtime)), 'mtime') + localtime(stat.st_mtime)), 'mtime') def _get_owner(self, target): uid = target.stat.st_uid diff --git a/ranger/gui/widgets/titlebar.py b/ranger/gui/widgets/titlebar.py index b815a07e..a949df05 100644 --- a/ranger/gui/widgets/titlebar.py +++ b/ranger/gui/widgets/titlebar.py @@ -118,7 +118,7 @@ class TitleBar(Widget): bar.add('~/', 'directory', fixed=True) for path in pathway: - if path.islink: + if path.is_link: clr = 'link' else: clr = 'directory' diff --git a/ranger/help/console.py b/ranger/help/console.py index 3a4428f3..76ce9f59 100644 --- a/ranger/help/console.py +++ b/ranger/help/console.py @@ -149,7 +149,7 @@ the flag "-OO" which removes all docstrings.) ============================================================================== 3.4. The Open Console -Open this console by pressing "!" +Open this console by pressing "!" or "s" The Open Console allows you to execute shell commands: !vim * will run vim and open all files in the directory. diff --git a/ranger/help/movement.py b/ranger/help/movement.py index 4ea2b0c3..f6a70eb1 100644 --- a/ranger/help/movement.py +++ b/ranger/help/movement.py @@ -77,7 +77,7 @@ These keys work like in vim: i inspect the content of the file E edit the file - s open a shell, starting in the current directory + S open a shell, starting in the current directory Marking files allows you to use operations on multiple files at once. If there are any marked files in this directory, "yy" will copy them instead |