<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html><head><title>Python: module ranger.fsobject.file</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head><body bgcolor="#f0f0f8">
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="heading">
<tr bgcolor="#7799ee">
<td valign=bottom> <br>
<font color="#ffffff" face="helvetica, arial"> <br><big><big><strong><a href="ranger.html"><font color="#ffffff">ranger</font></a>.<a href="ranger.fsobject.html"><font color="#ffffff">fsobject</font></a>.file</strong></big></big></font></td
><td align=right valign=bottom
><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/home/hut/work/ranger/ranger/fsobject/file.py">/home/hut/work/ranger/ranger/fsobject/file.py</a></font></td></tr></table>
<p></p>
<p>
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
<tr bgcolor="#ee77aa">
<td colspan=3 valign=bottom> <br>
<font color="#ffffff" face="helvetica, arial"><big><strong>Classes</strong></big></font></td></tr>
<tr><td bgcolor="#ee77aa"><tt> </tt></td><td> </td>
<td width="100%"><dl>
<dt><font face="helvetica, arial"><a href="ranger.fsobject.fsobject.html#FileSystemObject">ranger.fsobject.fsobject.FileSystemObject</a>(<a href="ranger.shared.mimetype.html#MimeTypeAware">ranger.shared.mimetype.MimeTypeAware</a>, <a href="ranger.shared.html#FileManagerAware">ranger.shared.FileManagerAware</a>)
</font></dt><dd>
<dl>
<dt><font face="helvetica, arial"><a href="ranger.fsobject.file.html#File">File</a>
</font></dt></dl>
</dd>
</dl>
<p>
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
<tr bgcolor="#ffc8d8"pre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */# Copyright (C) 2009, 2010 Roman Zimbelmann <romanz@lavabit.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
import shutil
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.gui.widgets import console_mode as cmode
from ranger.fsobject import File
class Actions(FileManagerAware, EnvironmentAware, SettingsAware):
search_method = 'ctime'
search_forward = False
# --------------------------
# -- Backwards Compatibility
# --------------------------
# All methods defined here are just for backwards compatibility,
# allowing old configuration files to work with newer versions.
# You can delete them and they should change nothing if you use
# an up-to-date configuration file.
def dummy(self, *args, **keywords):
"""For backwards compatibility only."""
handle_mouse = resize = dummy
def move_left(self, narg=1):
"""Enter the parent directory"""
self.move(left=1, narg=narg)
def move_right(self, narg=None):
"""Enter the current directory or execute the current file"""
self.move(right=1, narg=narg)
def move_pointer(self, relative=0, absolute=None, narg=None):
"""Move the pointer down by <relative> or to <absolute>"""
dct = dict(down=relative, narg=narg)
if absolute is not None:
dct['to'] = absolute
self.move(**dct)
def move_pointer_by_pages(self, relative):
"""Move the pointer down by <relative> pages"""
self.move(down=relative, pages=True)
def move_pointer_by_percentage(self, relative=0, absolute=None, narg=None):
"""Move the pointer down to <absolute>%"""
self.move(to=absolute, percentage=True, narg=narg)
# --------------------------
# -- Basic Commands
# --------------------------
def exit(self):
"""Exit the program"""
raise SystemExit()
def reset(self):
"""Reset the filemanager, clearing the directory buffer"""
old_path = self.env.cwd.path
self.env.garbage_collect(-1)
self.enter_dir(old_path)
def reload_cwd(self):
try:
cwd = self.env.cwd
except:
pass
cwd.unload()
cwd.load_content()
def notify(self, text, duration=4, bad=False):
if isinstance(text, Exception):
if ranger.arg.debug:
raise
bad = True
text = str(text)
self.log.appendleft(text)
if hasattr(self.ui, 'notify'):
self.ui.notify(text, duration=duration, bad=bad)
hint = notify
def redraw_window(self):
"""Redraw the window"""
self.ui.redraw_window()
def open_console(self, mode=':', string=''):
"""Open the console if the current UI supports that"""
if hasattr(self.ui, 'open_console'):
self.ui.open_console(mode, string)
def execute_file(self, files, **kw):
"""Execute a file.
app is the name of a method in Applications, without the "app_"
flags is a string consisting of runner.ALLOWED_FLAGS
mode is a positive integer.
Both flags and mode specify how the program is run."""
if isinstance(files, set):
files = list(files)
elif type(files) not in (list, tuple):
files = [files]
return self.run(files=list(files), **kw)
# --------------------------
# -- Moving Around
# --------------------------
def move(self, narg=None, **kw):
"""
A universal movement method.
Accepts these parameters:
(int) down, (int) up, (int) left, (int) right, (int) to,
(bool) absolute, (bool) relative, (bool) pages,
(bool) percentage
to=X is translated to down=X, absolute=True
Example:
self.move(down=4, pages=True) # moves down by 4 pages.
self.move(to=2, pages=True) # moves to page 2.
self.move(to=1, percentage=True) # moves to 80%
"""
direction = Direction(kw)
if 'left' in direction or direction.left() > 0:
steps = direction.left()
if narg is not None:
steps *= narg
try:
directory = os.path.join(*(['..'] * steps))
except:
return
self.env.enter_dir(directory)
elif 'right' in direction:
mode = 0
if narg is not None:
mode = narg
cf = self.env.cf
selection = self.env.get_selection()
if not self.env.enter_dir(cf) and selection:
if self.execute_file(selection, mode=mode) is False:
self.open_console(cmode.OPEN_QUICK)
elif direction.vertical():
newpos = direction.move(
direction=direction.down(),
override=narg,
maximum=len(self.env.cwd),
current=self.env.cwd.pointer,
pagesize=self.ui.browser.hei)
self.env.cwd.move(to=newpos)
def history_go(self, relative):
"""Move back and forth in the history"""
self.env.history_go(relative)
def scroll(self, relative):
"""Scroll down by <relative> lines"""
if hasattr(self.ui, 'scroll'):
self.ui.scroll(relative)
self.env.cf = self.env.cwd.pointed_obj
def enter_dir(self, path, remember=False, history=True):
"""Enter the directory at the given path"""
if remember:
cwd = self.env.cwd
result = self.env.enter_dir(path, history=history)
self.bookmarks.remember(cwd)
return result
return self.env.enter_dir(path, history=history)
def cd(self, path, remember=True):
"""enter the directory at the given path, remember=True"""
self.enter_dir(path, remember=remember)
def traverse(self):
cf = self.env.cf
cwd = self.env.cwd
if cf is not None and cf.is_directory:
self.enter_dir(cf.path)
elif cwd.pointer >= len(cwd) - 1:
while True:
self.move(left=1)
cwd = self.env.cwd
if cwd.pointer < len(cwd) - 1:
break
if cwd.path == '/':
break
self.move(down=1)
self.traverse()
else:
self.move(down=1)
self.traverse()
# --------------------------
# -- Shortcuts / Wrappers
# --------------------------
def execute_command(self, cmd, **kw):
return self.run(cmd, **kw)
def edit_file(self, file=None):
"""Calls execute_file with the current file and app='editor'"""
if file is None:
file = self.env.cf
elif isinstance(file, str):
file = File(os.path.expanduser(file))
if file is None:
return
self.execute_file(file, app = 'editor')
def toggle_boolean_option(self, string):
"""Toggle a boolean option named <string>"""
if isinstance(self.env.settings[string], bool):
self.env.settings[string] ^= True
def set_option(self, optname, value):
"""Set the value of an option named <optname>"""
self.env.settings[optname] = value
def sort(self, func=None, reverse=None):
if reverse is not None:
self.env.settings['sort_reverse'] = bool(reverse)
if func is not None:
self.env.settings['sort'] = str(func)
def set_filter(self, fltr):
try:
self.env.cwd.filter = fltr
except:
pass
def mark(self, all=False, toggle=False, val=None, movedown=None, narg=1):
"""
A wrapper for the directory.mark_xyz functions.
Arguments:
all - change all files of the current directory at once?
toggle - toggle the marked-status?
val - mark or unmark?
"""
if self.env.cwd is None:
return
cwd = self.env.cwd
if not cwd.accessible:
return
if movedown is None:
movedown = not all
if val is None and toggle is False:
return
if all:
if toggle:
cwd.toggle_all_marks()
else:
cwd.mark_all(val)
else:
for i in range(cwd.pointer, min(cwd.pointer + narg, len(cwd))):
item = cwd.files[i]
if item is not None:
if toggle:
cwd.toggle_mark(item)
else:
cwd.mark_item(item, val)
if movedown:
self.move(down=narg)
if hasattr(self.ui, 'redraw_main_column'):
self.ui.redraw_main_column()
if hasattr(self.ui, 'status'):
self.ui.status.need_redraw = True
# --------------------------
# -- Searching
# --------------------------
def search(self, order=None, forward=True):
original_order = order
if self.search_forward:
direction = bool(forward)
else:
direction = not bool(forward)
if order is None:
order = self.search_method
else:
self.set_search_method(order=order)
if order in ('search', 'tag'):
if order == 'search':
arg = self.env.last_search
if arg is None:
return False
if hasattr(arg, 'search'):
fnc = lambda x: arg.search(x.basename)
else:
fnc = lambda x: arg in x.basename
elif order == 'tag':
fnc = lambda x: x.realpath in self.tags
return self.env.cwd.search_fnc(fnc=fnc, forward=forward)
elif order in ('size', 'mimetype', 'ctime'):
cwd = self.env.cwd
if original_order is not None or not cwd.cycle_list:
lst = list(cwd.files)
if order == 'size':
fnc = lambda item: -item.size
elif order == 'mimetype':
fnc = lambda item: item.mimetype
elif order == 'ctime':
fnc = lambda item: -int(item.stat and item.stat.st_ctime)
lst.sort(key=fnc)
cwd.set_cycle_list(lst)
return cwd.cycle(forward=None)
return cwd.cycle(forward=forward)
def set_search_method(self, order, forward=True):
if order in ('search', 'tag', 'size', 'mimetype', 'ctime'):
self.search_method = order
self.search_forward = forward
# --------------------------
# -- Tags
# --------------------------
# Tags are saved in ~/.ranger/tagged and simply mark if a
# file is important to you in any context.
def tag_toggle(self, movedown=None):
try:
toggle = self.tags.toggle
except AttributeError:
return
sel = self.env.get_selection()
toggle(*tuple(map(lambda x: x.realpath, sel)))
if movedown is None:
movedown = len(sel) == 1
if movedown:
self.move(down=1)
if hasattr(self.ui, 'redraw_main_column'):
self.ui.redraw_main_column()
def tag_remove(self, movedown=None):
try:
remove = self.tags.remove
except AttributeError:
return
sel = self.env.get_selection()
remove(*tuple(map(lambda x: x.realpath, sel)))
if movedown is None:
movedown = len(sel) == 1
if movedown:
self.move(down=1)
if hasattr(self.ui, 'redraw_main_column'):
self.ui.redraw_main_column()
# --------------------------
# -- Bookmarks
# --------------------------
# Using ranger.container.bookmarks.
def enter_bookmark(self, key):
"""Enter the bookmark with the name <key>"""
try:
destination = self.bookmarks[key]
cwd = self.env.cwd
if destination.path != cwd.path:
self.bookmarks.enter(key)
self.bookmarks.remember(cwd)
except KeyError:
pass
def set_bookmark(self, key):
"""Set the bookmark with the name <key> to the current directory"""
self.bookmarks[key] = self.env.cwd
def unset_bookmark(self, key):
"""Delete the bookmark with the name <key>"""
self.bookmarks.delete(key)
def draw_bookmarks(self):
self.ui.browser.draw_bookmarks = True
def hide_bookmarks(self):
self.ui.browser.draw_bookmarks = False
# --------------------------
# -- Pager
# --------------------------
# These commands open the built-in pager and set specific sources.
def display_command_help(self, console_widget):
if not hasattr(self.ui, 'open_pager'):
return
try:
command = console_widget._get_cmd_class()
except:
self.notify("Feature not available!", bad=True)
return
if not command:
self.notify("Command not found!", bad=True)
return
if not command.__doc__:
self.notify("Command has no docstring. Try using python without -OO",
bad=True)
return
pager = self.ui.open_pager()
lines = cleandoc(command.__doc__).split('\n')
pager.set_source(lines)
def display_help(self, topic='index', narg=None):
if not hasattr(self.ui, 'open_pager'):
return
from ranger.help import get_help, get_help_by_index
if narg is not None:
help_text = get_help_by_index(narg)
else:
help_text = get_help(topic)
pager = self.ui.open_pager()
pager.markup = 'help'
lines = help_text.split('\n')
pager.set_source(lines)
def display_log(self):
if not hasattr(self.ui, 'open_pager'):
return
pager = self.ui.open_pager()
if self.log:
pager.set_source(["Message Log:"] + list(self.log))
else:
pager.set_source(["Message Log:", "No messages!"])
def display_file(self):
if not hasattr(self.ui, 'open_embedded_pager'):
return
try:
f = open(self.env.cf.path, 'r')
except:
pass
else:
pager = self.ui.open_embedded_pager()
pager.set_source(f)
# --------------------------
# -- Tabs
# --------------------------
# This implementation of tabs is very simple and keeps track of
# directory paths only.
def tab_open(self, name, path=None):
do_emit_signal = name != self.current_tab
self.current_tab = name
if path or (name in self.tabs):
self.enter_dir(path or self.tabs[name])
else:
self._update_current_tab()
if do_emit_signal:
self.signal_emit('tab.change')
def tab_close(self, name=None):
if name is None:
name = self.current_tab
if name == self.current_tab:
direction = -1 if name == self._get_tab_list()[-1] else 1
previous = self.current_tab
self.tab_move(direction)
if previous == self.current_tab:
return # can't close last tab
if name in self.tabs:
del self.tabs[name]
def tab_move(self, offset):
assert isinstance(offset, int)
tablist = self._get_tab_list()
current_index = tablist.index(self.current_tab)
newtab = tablist[(current_index + offset) % len(tablist)]
if newtab != self.current_tab:
self.tab_open(newtab)
def tab_new(self):
for i in range(1, 10):
if not i in self.tabs:
self.tab_open(i)
break
def _get_tab_list(self):
assert len(self.tabs) > 0, "There must be >=1 tabs at all times"
return sorted(self.tabs)
def _update_current_tab(self):
self.tabs[self.current_tab] = self.env.cwd.path
# --------------------------
# -- File System Operations
# --------------------------
def uncut(self):
self.env.copy = set()
self.env.cut = False
self.ui.browser.main_column.request_redraw()
def copy(self, narg=None, dirarg=None):
"""Copy the selected items"""
cwd = self.env.cwd
if not narg and not dirarg:
selected = (f for f in self.env.get_selection() if f in cwd.files)
self.env.copy = set(selected)
self.env.cut = False
else:
direction = Direction(dirarg or {})
offset = 0
if not direction.vertical():
direction = Direction(down=1)
offset = -1
pos, selected = direction.select(
override=narg, lst=cwd.files, current=cwd.pointer,
pagesize=self.env.termsize[0], offset=offset)
self.env.copy = set(selected)
self.env.copy.add(self.env.cwd.pointed_obj)
self.env.cut = False
self.env.cwd.pointer = pos
self.env.cwd.correct_pointer()
self.env.copy.add(self.env.cwd.pointed_obj)
self.ui.browser.main_column.request_redraw()
def cut(self, narg=None, dirarg=None):
self.copy(narg=narg, dirarg=dirarg)
self.env.cut = True
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))
except Exception as x:
self.notify(x)
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:
return
original_path = self.env.cwd.path
try:
one_file = copied_files[0]
except:
one_file = None
if self.env.cut:
self.env.copy.clear()
self.env.cut = False
if len(copied_files) == 1:
descr = "moving: " + one_file.path
else:
descr = "moving files from: " + one_file.dirname
def generate():
for f in copied_files:
for _ in shutil_g.move(src=f.path,
dst=original_path,
overwrite=overwrite):
yield
cwd = self.env.get_directory(original_path)
cwd.load_content()
else:
if len(copied_files) == 1:
descr = "copying: " + one_file.path
else:
descr = "copying files from: " + one_file.dirname
def generate():
for f in self.env.copy:
if isdir(f.path):
for _ in shutil_g.copytree(src=f.path,
dst=join(self.env.cwd.path, f.basename),
symlinks=True,
overwrite=overwrite):
yield
else:
for _ in shutil_g.copy2(f.path, original_path,
symlinks=True,
overwrite=overwrite):
yield
cwd = self.env.get_directory(original_path)
cwd.load_content()
self.loader.add(LoadableObject(generate(), descr))
def delete(self):
self.notify("Deleting!", duration=1)
selected = self.env.get_selection()
self.env.copy -= set(selected)
if selected:
for f in selected:
if os.path.isdir(f.path) and not os.path.islink(f.path):
try:
shutil.rmtree(f.path)
except OSError as err:
self.notify(err)
else:
try:
os.remove(f.path)
except OSError as err:
self.notify(err)
self.env.ensure_correct_pointer()
def mkdir(self, name):
try:
os.mkdir(os.path.join(self.env.cwd.path, name))
except OSError as err:
self.notify(err)
def rename(self, src, dest):
if hasattr(src, 'path'):
src = src.path
try:
os.rename(src, dest)
except OSError as err:
self.notify(err)