1
0
Fork 0

Update 2017-08-06

This commit is contained in:
Nguyễn Gia Phong 2017-08-06 00:36:31 +07:00
parent 04bb23545a
commit d721c7a5f9
6 changed files with 327 additions and 249 deletions

View File

@ -8,13 +8,15 @@
from ranger.api.commands import *
# A simple command for demonstration purposes follows.
#------------------------------------------------------------------------------
# -----------------------------------------------------------------------------
# You can import any python module as needed.
import os
# Any class that is a subclass of "Command" will be integrated into ranger as a
# command. Try typing ":my_edit<ENTER>" in ranger!
class my_edit(Command):
# The so-called doc-string of the class will be visible in the built-in
# help that is accessible by typing "?c" inside ranger.
@ -37,7 +39,7 @@ class my_edit(Command):
# reference to the currently selected file.
target_filename = self.fm.thisfile.path
# This is a generic function to print text in ranger.
# This is a generic function to print text in ranger.
self.fm.notify("Let's edit the file " + target_filename + "!")
# Using bad=True in fm.notify allows you to print error messages:
@ -52,7 +54,8 @@ class my_edit(Command):
# The tab method is called when you press tab, and should return a list of
# suggestions that the user will tab through.
def tab(self):
# tabnum is 1 for <TAB> and -1 for <S-TAB> by default
def tab(self, tabnum):
# This is a generic tab-completion function that iterates through the
# content of the current directory.
return self._tab_directory_content()

View File

@ -21,10 +21,12 @@
# ===================================================================
# Every class defined here which is a subclass of `Command' will be used as a
# command in ranger. Several methods are defined to interface with ranger:
# execute(): called when the command is executed.
# cancel(): called when closing the console.
# tab(): called when <TAB> is pressed.
# quick(): called after each keypress.
# execute(): called when the command is executed.
# cancel(): called when closing the console.
# tab(tabnum): called when <TAB> is pressed.
# quick(): called after each keypress.
#
# tab() argument tabnum is 1 for <TAB> and -1 for <S-TAB> by default
#
# The return values for tab() can be either:
# None: There is no tab completion
@ -83,6 +85,7 @@
from ranger.api.commands import *
class alias(Command):
""":alias <newcommand> <oldcommand>
@ -98,6 +101,16 @@ class alias(Command):
else:
self.fm.commands.alias(self.arg(1), self.rest(2))
class echo(Command):
""":echo <text>
Display the text in the statusbar.
"""
def execute(self):
self.fm.notify(self.rest(1))
class cd(Command):
""":cd [-r] <dirname>
@ -125,7 +138,7 @@ class cd(Command):
else:
self.fm.cd(destination)
def tab(self):
def tab(self, tabnum):
import os
from os.path import dirname, basename, expanduser, join
@ -133,7 +146,7 @@ class cd(Command):
rel_dest = self.rest(1)
bookmarks = [v.path for v in self.fm.bookmarks.dct.values()
if rel_dest in v.path ]
if rel_dest in v.path]
# expand the tilde into the user directory
if rel_dest.startswith('~'):
@ -153,7 +166,7 @@ class cd(Command):
# are we in the middle of the filename?
else:
_, dirnames, _ = next(os.walk(abs_dirname))
dirnames = [dn for dn in dirnames \
dirnames = [dn for dn in dirnames
if dn.startswith(rel_basename)]
except (OSError, StopIteration):
# os.walk found nothing
@ -182,7 +195,7 @@ class chain(Command):
Calls multiple commands at once, separated by semicolons.
"""
def execute(self):
for command in self.rest(1).split(";"):
for command in [s.strip() for s in self.rest(1).split(";")]:
self.fm.execute_console(command)
@ -197,14 +210,10 @@ class shell(Command):
flags = ''
command = self.rest(1)
if not command and 'p' in flags:
command = 'cat %f'
if command:
if '%' in command:
command = self.fm.substitute_macros(command, escape=True)
self.fm.execute_command(command, flags=flags)
def tab(self):
def tab(self, tabnum):
from ranger.ext.get_executables import get_executables
if self.arg(1) and self.arg(1)[0] == '-':
command = self.rest(2)
@ -215,7 +224,7 @@ class shell(Command):
try:
position_of_last_space = command.rindex(" ")
except ValueError:
return (start + program + ' ' for program \
return (start + program + ' ' for program
in get_executables() if program.startswith(command))
if position_of_last_space == len(command) - 1:
selection = self.fm.thistab.get_selection()
@ -225,20 +234,21 @@ class shell(Command):
return self.line + '%s '
else:
before_word, start_of_word = self.line.rsplit(' ', 1)
return (before_word + ' ' + file.shell_escaped_basename \
for file in self.fm.thisdir.files \
return (before_word + ' ' + file.shell_escaped_basename
for file in self.fm.thisdir.files or []
if file.shell_escaped_basename.startswith(start_of_word))
class open_with(Command):
def execute(self):
app, flags, mode = self._get_app_flags_mode(self.rest(1))
self.fm.execute_file(
files = [f for f in self.fm.thistab.get_selection()],
app = app,
flags = flags,
mode = mode)
files=[f for f in self.fm.thistab.get_selection()],
app=app,
flags=flags,
mode=mode)
def tab(self):
def tab(self, tabnum):
return self._tab_through_executables()
def _get_app_flags_mode(self, string):
@ -328,26 +338,32 @@ class set_(Command):
""":set <option name>=<python expression>
Gives an option a new value.
Use `:set <option>!` to toggle or cycle it, e.g. `:set flush_input!`
"""
name = 'set' # don't override the builtin set class
def execute(self):
name = self.arg(1)
name, value, _ = self.parse_setting_line()
self.fm.set_option_from_string(name, value)
name, value, _, toggle = self.parse_setting_line_v2()
if toggle:
self.fm.toggle_option(name)
else:
self.fm.set_option_from_string(name, value)
def tab(self):
def tab(self, tabnum):
from ranger.gui.colorscheme import get_all_colorschemes
name, value, name_done = self.parse_setting_line()
settings = self.fm.settings
if not name:
return sorted(self.firstpart + setting for setting in settings)
if not value and not name_done:
return (self.firstpart + setting for setting in settings \
return sorted(self.firstpart + setting for setting in settings
if setting.startswith(name))
if not value:
# Cycle through colorschemes when name, but no value is specified
if name == "colorscheme":
return (self.firstpart + colorscheme for colorscheme \
return sorted(self.firstpart + colorscheme for colorscheme
in get_all_colorschemes())
return self.firstpart + str(settings[name])
if bool in settings.types_of(name):
@ -357,16 +373,17 @@ class set_(Command):
return self.firstpart + 'False'
# Tab complete colorscheme values if incomplete value is present
if name == "colorscheme":
return (self.firstpart + colorscheme for colorscheme \
return sorted(self.firstpart + colorscheme for colorscheme
in get_all_colorschemes() if colorscheme.startswith(value))
class setlocal(set_):
""":setlocal path=<python string> <option name>=<python expression>
""":setlocal path=<regular expression> <option name>=<python expression>
Gives an option a new value.
"""
PATH_RE = re.compile(r'^\s*path="?(.*?)"?\s*$')
def execute(self):
import os.path
match = self.PATH_RE.match(self.arg(1))
@ -432,7 +449,7 @@ class default_linemode(Command):
for col in self.fm.ui.browser.columns:
col.need_redraw = True
def tab(self):
def tab(self, tabnum):
mode = self.arg(1)
return (self.arg(0) + " " + linemode
for linemode in self.fm.thisfile.linemode_dict.keys()
@ -476,20 +493,15 @@ class terminal(Command):
Spawns an "x-terminal-emulator" starting in the current directory.
"""
def execute(self):
import os
from ranger.ext.get_executables import get_executables
command = os.environ.get('TERMCMD', os.environ.get('TERM'))
if command not in get_executables():
command = 'x-terminal-emulator'
if command not in get_executables():
command = 'xterm'
self.fm.run(command, flags='f')
from ranger.ext.get_executables import get_term
self.fm.run(get_term(), flags='f')
class delete(Command):
""":delete
Tries to delete the selection.
Tries to delete the selection or the files passed in arguments (if any).
The arguments use a shell-like escaping.
"Selection" is defined as all the "marked files" (by default, you
can mark files with space or v). If there are no marked files,
@ -500,41 +512,49 @@ class delete(Command):
"""
allow_abbrev = False
escape_macros_for_shell = True
def execute(self):
import os
if self.rest(1):
self.fm.notify("Error: delete takes no arguments! It deletes "
"the selected file(s).", bad=True)
return
import shlex
from functools import partial
from ranger.container.file import File
cwd = self.fm.thisdir
cf = self.fm.thisfile
if not cwd or not cf:
self.fm.notify("Error: no file selected for deletion!", bad=True)
return
def is_directory_with_files(f):
import os.path
return (os.path.isdir(f) and not os.path.islink(f)
and len(os.listdir(f)) > 0)
if self.rest(1):
files = shlex.split(self.rest(1))
many_files = (len(files) > 1 or is_directory_with_files(files[0]))
else:
cwd = self.fm.thisdir
cf = self.fm.thisfile
if not cwd or not cf:
self.fm.notify("Error: no file selected for deletion!", bad=True)
return
# relative_path used for a user-friendly output in the confirmation.
files = [f.relative_path for f in self.fm.thistab.get_selection()]
many_files = (cwd.marked_items or is_directory_with_files(cf.path))
confirm = self.fm.settings.confirm_on_delete
many_files = (cwd.marked_items or (cf.is_directory and not cf.is_link \
and len(os.listdir(cf.path)) > 0))
if confirm != 'never' and (confirm != 'multiple' or many_files):
filename_list = files
self.fm.ui.console.ask("Confirm deletion of: %s (y/N)" %
', '.join(f.basename for f in self.fm.thistab.get_selection()),
self._question_callback, ('n', 'N', 'y', 'Y'))
', '.join(files),
partial(self._question_callback, files), ('n', 'N', 'y', 'Y'))
else:
# no need for a confirmation, just delete
for f in self.fm.tags.tags:
if str(f).startswith(self.fm.thisfile.path):
self.fm.tags.remove(f)
self.fm.delete()
self.fm.delete(files)
def _question_callback(self, answer):
def tab(self, tabnum):
return self._tab_directory_content()
def _question_callback(self, files, answer):
if answer == 'y' or answer == 'Y':
for f in self.fm.tags.tags:
if str(f).startswith(self.fm.thisfile.path):
self.fm.tags.remove(f)
self.fm.delete()
self.fm.delete(files)
class mark_tag(Command):
@ -547,8 +567,8 @@ class mark_tag(Command):
def execute(self):
cwd = self.fm.thisdir
tags = self.rest(1).replace(" ","")
if not self.fm.tags:
tags = self.rest(1).replace(" ", "")
if not self.fm.tags or not cwd.files:
return
for fileobj in cwd.files:
try:
@ -572,7 +592,7 @@ class console(Command):
try:
position = int(self.arg(1)[2:])
self.shift()
except:
except Exception:
pass
self.fm.open_console(self.rest(1), position=position)
@ -583,16 +603,17 @@ class load_copy_buffer(Command):
Load the copy buffer from confdir/copy_buffer
"""
copy_buffer_filename = 'copy_buffer'
def execute(self):
from ranger.container.file import File
from os.path import exists
try:
fname = self.fm.confpath(self.copy_buffer_filename)
f = open(fname, 'r')
except:
return self.fm.notify("Cannot open %s" % \
except Exception:
return self.fm.notify("Cannot open %s" %
(fname or self.copy_buffer_filename), bad=True)
self.fm.copy_buffer = set(File(g) \
self.fm.copy_buffer = set(File(g)
for g in f.read().split("\n") if exists(g))
f.close()
self.fm.ui.redraw_main_column()
@ -604,13 +625,14 @@ class save_copy_buffer(Command):
Save the copy buffer to confdir/copy_buffer
"""
copy_buffer_filename = 'copy_buffer'
def execute(self):
fname = None
try:
fname = self.fm.confpath(self.copy_buffer_filename)
f = open(fname, 'w')
except:
return self.fm.notify("Cannot open %s" % \
except Exception:
return self.fm.notify("Cannot open %s" %
(fname or self.copy_buffer_filename), bad=True)
f.write("\n".join(f.path for f in self.fm.copy_buffer))
f.close()
@ -641,7 +663,7 @@ class mkdir(Command):
else:
self.fm.notify("file/directory exists!", bad=True)
def tab(self):
def tab(self, tabnum):
return self._tab_directory_content()
@ -660,7 +682,7 @@ class touch(Command):
else:
self.fm.notify("file/directory exists!", bad=True)
def tab(self):
def tab(self, tabnum):
return self._tab_directory_content()
@ -676,7 +698,7 @@ class edit(Command):
else:
self.fm.edit_file(self.rest(1))
def tab(self):
def tab(self, tabnum):
return self._tab_directory_content()
@ -733,7 +755,7 @@ class rename(Command):
new_name = self.rest(1)
tagged = {}
old_name = self.fm.thisfile.basename
old_name = self.fm.thisfile.relative_path
for f in self.fm.tags.tags:
if str(f).startswith(self.fm.thisfile.path):
tagged[f] = self.fm.tags.tags[f]
@ -742,7 +764,7 @@ class rename(Command):
if not new_name:
return self.fm.notify('Syntax: rename <newname>', bad=True)
if new_name == self.fm.thisfile.basename:
if new_name == old_name:
return
if access(new_name, os.F_OK):
@ -750,15 +772,24 @@ class rename(Command):
if self.fm.rename(self.fm.thisfile, new_name):
f = File(new_name)
# Update bookmarks that were pointing on the previous name
obsoletebookmarks = [b for b in self.fm.bookmarks
if b[1].path == self.fm.thisfile]
if obsoletebookmarks:
for key, _ in obsoletebookmarks:
self.fm.bookmarks[key] = f
self.fm.bookmarks.update_if_outdated()
self.fm.thisdir.pointed_obj = f
self.fm.thisfile = f
for t in tagged:
self.fm.tags.tags[t.replace(old_name,new_name)] = tagged[t]
self.fm.tags.tags[t.replace(old_name, new_name)] = tagged[t]
self.fm.tags.dump()
def tab(self):
def tab(self, tabnum):
return self._tab_directory_content()
class rename_append(Command):
""":rename_append
@ -767,10 +798,12 @@ class rename_append(Command):
def execute(self):
cf = self.fm.thisfile
if cf.basename.find('.') != 0 and cf.basename.rfind('.') != -1 and not cf.is_directory:
self.fm.open_console('rename ' + cf.basename, position=(7 + cf.basename.rfind('.')))
path = cf.relative_path.replace("%", "%%")
if path.find('.') != 0 and path.rfind('.') != -1 and not cf.is_directory:
self.fm.open_console('rename ' + path, position=(7 + path.rfind('.')))
else:
self.fm.open_console('rename ' + cf.basename)
self.fm.open_console('rename ' + path)
class chmod(Command):
""":chmod <octal number>
@ -807,7 +840,7 @@ class chmod(Command):
# reloading directory. maybe its better to reload the selected
# files only.
self.fm.thisdir.load_content()
except:
except Exception:
pass
@ -852,7 +885,7 @@ class bulkrename(Command):
script_lines = []
script_lines.append("# This file will be executed when you close the editor.\n")
script_lines.append("# Please double-check everything, clear the file to abort.\n")
script_lines.extend("mv -vi -- %s %s\n" % (esc(old), esc(new)) \
script_lines.extend("mv -vi -- %s %s\n" % (esc(old), esc(new))
for old, new in zip(filenames, new_filenames) if old != new)
script_content = "".join(script_lines)
if py3:
@ -889,6 +922,7 @@ class bulkrename(Command):
else:
fm.notify("files have not been retagged")
class relink(Command):
""":relink <newpath>
@ -905,7 +939,7 @@ class relink(Command):
return self.fm.notify('Syntax: relink <newpath>', bad=True)
if not cf.is_link:
return self.fm.notify('%s is not a symlink!' % cf.basename, bad=True)
return self.fm.notify('%s is not a symlink!' % cf.relative_path, bad=True)
if new_path == os.readlink(cf.path):
return
@ -920,9 +954,9 @@ class relink(Command):
self.fm.thisdir.pointed_obj = cf
self.fm.thisfile = cf
def tab(self):
def tab(self, tabnum):
if not self.rest(1):
return self.line+os.readlink(self.fm.thisfile.path)
return self.line + os.readlink(self.fm.thisfile.path)
else:
return self._tab_directory_content()
@ -933,6 +967,7 @@ class help_(Command):
Display ranger's manual page.
"""
name = 'help'
def execute(self):
def callback(answer):
if answer == "q":
@ -1090,6 +1125,7 @@ class scout(Command):
-m = mark the matching files after pressing enter
-M = unmark the matching files after pressing enter
-p = permanent filter: hide non-matching files after pressing enter
-r = interpret pattern as a regular expression pattern
-s = smart case; like -i unless pattern contains upper case letters
-t = apply filter and search pattern as you type
-v = inverts the match
@ -1127,14 +1163,14 @@ class scout(Command):
self.fm.thistab.last_search = regex
self.fm.set_search_method(order="search")
if self.MARK in flags or self.UNMARK in flags:
if (self.MARK in flags or self.UNMARK in flags) and thisdir.files:
value = flags.find(self.MARK) > flags.find(self.UNMARK)
if self.FILTER in flags:
for f in thisdir.files:
thisdir.mark_item(f, value)
else:
for f in thisdir.files:
if regex.search(f.basename):
if regex.search(f.relative_path):
thisdir.mark_item(f, value)
if self.PERM_FILTER in flags:
@ -1176,8 +1212,8 @@ class scout(Command):
return True
return False
def tab(self):
self._count(move=True, offset=1)
def tab(self, tabnum):
self._count(move=True, offset=tabnum)
def _build_regex(self):
if self._regex is not None:
@ -1215,13 +1251,13 @@ class scout(Command):
regex = "^(?:(?!%s).)*$" % regex
# Compile Regular Expression
options = re.LOCALE | re.UNICODE
options = re.UNICODE
if self.IGNORE_CASE in flags or self.SMART_CASE in flags and \
pattern.islower():
options |= re.IGNORECASE
try:
self._regex = re.compile(regex, options)
except:
except Exception:
self._regex = re.compile("")
return self._regex
@ -1230,7 +1266,7 @@ class scout(Command):
cwd = self.fm.thisdir
pattern = self.pattern
if not pattern:
if not pattern or not cwd.files:
return 0
if pattern == '.':
return 0
@ -1242,7 +1278,7 @@ class scout(Command):
i = offset
regex = self._build_regex()
for fsobj in deq:
if regex.search(fsobj.basename):
if regex.search(fsobj.relative_path):
count += 1
if move and count == 1:
cwd.move(to=(cwd.pointer + i) % len(cwd.files))
@ -1295,104 +1331,6 @@ class grep(Command):
self.fm.execute_command(action, flags='p')
# Version control commands
# --------------------------------
class stage(Command):
"""
:stage
Stage selected files for the corresponding version control system
"""
def execute(self):
from ranger.ext.vcs import VcsError
filelist = [f.path for f in self.fm.thistab.get_selection()]
self.fm.thisdir.vcs_outdated = True
# for f in self.fm.thistab.get_selection():
# f.vcs_outdated = True
try:
self.fm.thisdir.vcs.add(filelist)
except VcsError:
self.fm.notify("Could not stage files.")
self.fm.reload_cwd()
class unstage(Command):
"""
:unstage
Unstage selected files for the corresponding version control system
"""
def execute(self):
from ranger.ext.vcs import VcsError
filelist = [f.path for f in self.fm.thistab.get_selection()]
self.fm.thisdir.vcs_outdated = True
# for f in self.fm.thistab.get_selection():
# f.vcs_outdated = True
try:
self.fm.thisdir.vcs.reset(filelist)
except VcsError:
self.fm.notify("Could not unstage files.")
self.fm.reload_cwd()
class diff(Command):
"""
:diff
Displays a diff of selected files against the last committed version
"""
def execute(self):
from ranger.ext.vcs import VcsError
import tempfile
L = self.fm.thistab.get_selection()
if len(L) == 0: return
filelist = [f.path for f in L]
vcs = L[0].vcs
diff = vcs.get_raw_diff(filelist=filelist)
if len(diff.strip()) > 0:
tmp = tempfile.NamedTemporaryFile()
tmp.write(diff.encode('utf-8'))
tmp.flush()
pager = os.environ.get('PAGER', ranger.DEFAULT_PAGER)
self.fm.run([pager, tmp.name])
else:
raise Exception("diff is empty")
class log(Command):
"""
:log
Displays the log of the current repo or files
"""
def execute(self):
from ranger.ext.vcs import VcsError
import tempfile
L = self.fm.thistab.get_selection()
if len(L) == 0: return
filelist = [f.path for f in L]
vcs = L[0].vcs
log = vcs.get_raw_log(filelist=filelist)
tmp = tempfile.NamedTemporaryFile()
tmp.write(log.encode('utf-8'))
tmp.flush()
pager = os.environ.get('PAGER', ranger.DEFAULT_PAGER)
self.fm.run([pager, tmp.name])
class flat(Command):
"""
:flat <level>
@ -1415,10 +1353,53 @@ class flat(Command):
self.fm.thisdir.flat = level
self.fm.thisdir.load_content()
# Version control commands
# --------------------------------
class stage(Command):
"""
:stage
Stage selected files for the corresponding version control system
"""
def execute(self):
from ranger.ext.vcs import VcsError
if self.fm.thisdir.vcs and self.fm.thisdir.vcs.track:
filelist = [f.path for f in self.fm.thistab.get_selection()]
try:
self.fm.thisdir.vcs.action_add(filelist)
except VcsError as error:
self.fm.notify('Unable to stage files: {0:s}'.format(str(error)))
self.fm.ui.vcsthread.process(self.fm.thisdir)
else:
self.fm.notify('Unable to stage files: Not in repository')
class unstage(Command):
"""
:unstage
Unstage selected files for the corresponding version control system
"""
def execute(self):
from ranger.ext.vcs import VcsError
if self.fm.thisdir.vcs and self.fm.thisdir.vcs.track:
filelist = [f.path for f in self.fm.thistab.get_selection()]
try:
self.fm.thisdir.vcs.action_reset(filelist)
except VcsError as error:
self.fm.notify('Unable to unstage files: {0:s}'.format(str(error)))
self.fm.ui.vcsthread.process(self.fm.thisdir)
else:
self.fm.notify('Unable to unstage files: Not in repository')
# Metadata commands
# --------------------------------
class prompt_metadata(Command):
"""
:prompt_metadata <key1> [<key2> [<key3> ...]]
@ -1428,6 +1409,7 @@ class prompt_metadata(Command):
_command_name = "meta"
_console_chain = None
def execute(self):
prompt_metadata._console_chain = self.args[1:]
self._process_command_stack()
@ -1467,7 +1449,7 @@ class meta(prompt_metadata):
self.fm.metadata.set_metadata(f.path, update_dict)
self._process_command_stack()
def tab(self):
def tab(self, tabnum):
key = self.arg(1)
metadata = self.fm.metadata.get_metadata(self.fm.thisfile.path)
if key in metadata and metadata[key]:

View File

@ -1,3 +1,4 @@
# ===================================================================
# This file contains the default startup commands for ranger.
# To change them, it is recommended to create the file
# ~/.config/ranger/rc.conf and add your custom commands there.
@ -12,8 +13,18 @@
# Each line is a command that will be run before the user interface
# is initialized. As a result, you can not use commands which rely
# on the UI such as :delete or :mark.
# ===================================================================
# Options
# ===================================================================
# == Options
# ===================================================================
# Which viewmode should be used? Possible values are:
# miller: Use miller columns which show multiple levels of the hierarchy
# multipane: Midnight-commander like multipane view showing all tabs next
# to each other
set viewmode miller
#set viewmode multipane
# How many columns are there, and what are their relative widths?
set column_ratios 1,1
@ -27,7 +38,7 @@ set show_hidden false
# Ask for a confirmation when running the "delete" command?
# Valid values are "always", "never", "multiple" (default)
# With "multiple", ranger will ask only if you delete multiple files at once.
set confirm_on_delete multiple
set confirm_on_delete always
# Which script is used to generate file previews?
# ranger ships with scope.sh, a script that calls external programs (see
@ -35,7 +46,7 @@ set confirm_on_delete multiple
set preview_script ~/.config/ranger/scope.sh
# Use the external preview script or display simple plain text or image previews?
set use_preview_script false
set use_preview_script true
# Automatically count files in the directory, even before entering them?
set automatically_count_files true
@ -68,10 +79,18 @@ set preview_images true
# Preview images in full color using iTerm2 image previews
# (http://iterm2.com/images.html). This requires using iTerm2 compiled
# with image preview support.
#
# * urxvt:
# Preview images in full color using urxvt image backgrounds. This
# requires using urxvt compiled with pixbuf support.
#
# * urxvt-full:
# The same as urxvt but utilizing not only the preview pane but the
# whole terminal window.
set preview_images_method w3m
# Use a unicode "..." character to mark cut-off filenames?
set unicode_ellipsis true
set unicode_ellipsis false
# Show dotfiles in the bookmark preview box?
set show_hidden_bookmarks true
@ -132,12 +151,12 @@ set max_console_history_size 50
# Try to keep so much space between the top/bottom border when scrolling:
set scroll_offset 8
# Flush the input after each key hit? (Noticable when ranger lags)
# Flush the input after each key hit? (Noticeable when ranger lags)
set flushinput true
# Padding on the right when there's no preview?
# This allows you to click into the space to run the file.
set padding_right true
set padding_right false
# Save bookmarks (used with mX and `X) instantly?
# This helps to synchronize bookmarks between multiple ranger
@ -187,13 +206,23 @@ set idle_delay 2000
# check all directories above the current one as well?
set metadata_deep_search false
# Local Options
# Clear all existing filters when leaving a directory
set clear_filters_on_dir_change false
# Disable displaying line numbers in main column
set line_numbers true
# ===================================================================
# == Local Options
# ===================================================================
# You can set local options that only affect a single directory.
# Examples:
# setlocal path=~/downloads sort mtime
# Command Aliases in the Console
# ===================================================================
# == Command Aliases in the Console
# ===================================================================
alias e edit
alias q quit
@ -210,7 +239,9 @@ alias search scout -rs
alias search_inc scout -rts
alias travel scout -aefiklst
# Define keys for the browser
# ===================================================================
# == Define keys for the browser
# ===================================================================
# Basic
map Q quit!
@ -222,6 +253,7 @@ map <C-r> reset
map <C-l> redraw_window
map <C-c> abort
map <esc> change_mode normal
map ~ set viewmode!
map i display_file
map ? help
@ -235,14 +267,16 @@ map ! console shell%space
map @ console -p6 shell %%s
map # console shell -p%space
map s console shell%space
map r chain draw_possible_programs; console open_with%space
map r chain draw_possible_programs; console open_with%%space
map f console find%space
map cd console cd%space
# Change the line mode
map Mf linemode filename
map Mi linemode fileinfo
map Mm linemode mtime
map Mp linemode permissions
map Ms linemode sizemtime
map Mt linemode metatitle
# Tagging / Marking
@ -329,11 +363,13 @@ map = chmod
map cw console rename%space
map a rename_append
map A eval fm.open_console('rename ' + fm.thisfile.basename)
map I eval fm.open_console('rename ' + fm.thisfile.basename, position=7)
map A eval fm.open_console('rename ' + fm.thisfile.relative_path.replace("%", "%%"))
map I eval fm.open_console('rename ' + fm.thisfile.relative_path.replace("%", "%%"), position=7)
map pp paste
map po paste overwrite=True
map pP paste append=True
map pO paste overwrite=True append=True
map pl paste_symlink relative=False
map pL paste_symlink relative=True
map phl paste_hardlink
@ -345,11 +381,13 @@ map dd cut
map ud uncut
map da cut mode=add
map dr cut mode=remove
map dt cut mode=toggle
map yy copy
map uy uncut
map ya copy mode=add
map yr copy mode=remove
map yt copy mode=toggle
# Temporary workarounds
map dgg eval fm.cut(dirarg=dict(to=0), narg=quantifier)
@ -395,7 +433,7 @@ map <a-8> tab_open 8
map <a-9> tab_open 9
# Sorting
map or toggle_option sort_reverse
map or set sort_reverse!
map oz set sort=random
map os chain set sort=size; set sort_reverse=False
map ob chain set sort=basename; set sort_reverse=False
@ -418,17 +456,18 @@ map oE chain set sort=extension; set sort_reverse=True
map dc get_cumulative_size
# Settings
map zc toggle_option collapse_preview
map zd toggle_option sort_directories_first
map zh toggle_option show_hidden
map <C-h> toggle_option show_hidden
map zi toggle_option flushinput
map zm toggle_option mouse_enabled
map zp toggle_option preview_files
map zP toggle_option preview_directories
map zs toggle_option sort_case_insensitive
map zu toggle_option autoupdate_cumulative_size
map zv toggle_option use_preview_script
map zc set collapse_preview!
map zd set sort_directories_first!
map zh set show_hidden!
map <C-h> set show_hidden!
map zI set flushinput!
map zi set preview_images!
map zm set mouse_enabled!
map zp set preview_files!
map zP set preview_directories!
map zs set sort_case_insensitive!
map zu set autoupdate_cumulative_size!
map zv set use_preview_script!
map zf console filter%space
# Bookmarks
@ -453,7 +492,9 @@ eval for arg in "rwxXst": cmd("map -o{0} shell -f chmod o-{0} %s".format(arg))
eval for arg in "rwxXst": cmd("map -a{0} shell -f chmod a-{0} %s".format(arg))
eval for arg in "rwxXst": cmd("map -{0} shell -f chmod u-{0} %s".format(arg))
# Define keys for the console
# ===================================================================
# == Define keys for the console
# ===================================================================
# Note: Unmapped keys are passed directly to the console.
# Basic
@ -473,11 +514,14 @@ cmap <left> eval fm.ui.console.move(left=1)
cmap <right> eval fm.ui.console.move(right=1)
cmap <home> eval fm.ui.console.move(right=0, absolute=True)
cmap <end> eval fm.ui.console.move(right=-1, absolute=True)
cmap <a-left> eval fm.ui.console.move_word(left=1)
cmap <a-right> eval fm.ui.console.move_word(right=1)
# Line Editing
cmap <backspace> eval fm.ui.console.delete(-1)
cmap <delete> eval fm.ui.console.delete(0)
cmap <C-w> eval fm.ui.console.delete_word()
cmap <A-d> eval fm.ui.console.delete_word(backward=False)
cmap <C-k> eval fm.ui.console.delete_rest(1)
cmap <C-u> eval fm.ui.console.delete_rest(-1)
cmap <C-y> eval fm.ui.console.paste()
@ -499,7 +543,9 @@ copycmap <backspace> <backspace2>
# This special expression allows typing in numerals:
cmap <allow_quantifiers> false
# Pager Keybindings
# ===================================================================
# == Pager Keybindings
# ===================================================================
# Movement
pmap <down> pager_move down=1
@ -530,7 +576,9 @@ pmap <ESC> pager_close
copypmap <ESC> q Q i <F3>
pmap E edit_file
# Taskview Keybindings
# ===================================================================
# == Taskview Keybindings
# ===================================================================
# Movement
tmap <up> taskview_move up=1

View File

@ -57,10 +57,12 @@
ext x?html?, has surf, X, flag f = surf -- file://"$1"
ext x?html?, has vimprobable, X, flag f = vimprobable -- "$@"
ext x?html?, has vimprobable2, X, flag f = vimprobable2 -- "$@"
ext x?html?, has qutebrowser, X, flag f = qutebrowser -- "$@"
ext x?html?, has dwb, X, flag f = dwb -- "$@"
ext x?html?, has jumanji, X, flag f = jumanji -- "$@"
ext x?html?, has luakit, X, flag f = luakit -- "$@"
ext x?html?, has uzbl, X, flag f = uzbl -- "$@"
ext x?html?, has uzbl-tabbed, X, flag f = uzbl-tabbed -- "$@"
ext x?html?, has uzbl-browser, X, flag f = uzbl-browser -- "$@"
ext x?html?, has uzbl-core, X, flag f = uzbl-core -- "$@"
ext x?html?, has midori, X, flag f = midori -- "$@"
@ -83,8 +85,8 @@ ext x?html?, has w3m, terminal = w3m "$@"
# Define the "editor" for text files as first action
mime ^text, label editor = $EDITOR -- "$@"
mime ^text, label pager = "$PAGER" -- "$@"
!mime ^text, label editor, ext xml|csv|tex|py|pl|rb|js|sh|php = $EDITOR -- "$@"
!mime ^text, label pager, ext xml|csv|tex|py|pl|rb|js|sh|php = "$PAGER" -- "$@"
!mime ^text, label editor, ext xml|json|csv|tex|py|pl|rb|js|sh|php = $EDITOR -- "$@"
!mime ^text, label pager, ext xml|json|csv|tex|py|pl|rb|js|sh|php = "$PAGER" -- "$@"
ext 1 = man "$1"
ext s[wmf]c, has zsnes, X = zsnes "$1"
@ -96,7 +98,7 @@ name ^[mM]akefile$ = make
#--------------------------------------------
# Code
#-------------------------------------------
ext py = python3 -- "$1"
ext py = python -- "$1"
ext pl = perl -- "$1"
ext rb = ruby -- "$1"
ext js = node -- "$1"
@ -106,9 +108,9 @@ ext php = php -- "$1"
#--------------------------------------------
# Audio without X
#-------------------------------------------
mime ^audio|ogg$, terminal, has mplayer = mplayer -- "$@"
mime ^audio|ogg$, terminal, has mplayer2 = mplayer2 -- "$@"
mime ^audio|ogg$, terminal, has mpv = mpv -- "$@"
mime ^audio|ogg$, terminal, has mplayer2 = mplayer2 -- "$@"
mime ^audio|ogg$, terminal, has mplayer = mplayer -- "$@"
ext midi?, terminal, has wildmidi = wildmidi -- "$@"
#--------------------------------------------
@ -138,7 +140,8 @@ mime ^video, terminal, !X, has mplayer = mplayer -- "$@"
#-------------------------------------------
ext pdf, has llpp, X, flag f = llpp "$@"
ext pdf, has zathura, X, flag f = zathura -- "$@"
ext pdf, has mupdf, X, flag f = mupdf -- "$@"
ext pdf, has mupdf, X, flag f = mupdf "$@"
ext pdf, has mupdf-x11,X, flag f = mupdf-x11 "$@"
ext pdf, has apvlv, X, flag f = apvlv -- "$@"
ext pdf, has xpdf, X, flag f = xpdf -- "$@"
ext pdf, has evince, X, flag f = evince -- "$@"
@ -147,7 +150,7 @@ ext pdf, has okular, X, flag f = okular -- "$@"
ext pdf, has epdfview, X, flag f = epdfview -- "$@"
ext pdf, has qpdfview, X, flag f = qpdfview "$@"
#ext docx?, has catdoc, terminal = catdoc -- "$@" | "$PAGER"
ext docx?, has catdoc, terminal = catdoc -- "$@" | "$PAGER"
ext sxc|xlsx?|xlt|xlw|gnm|gnumeric, has gnumeric, X, flag f = gnumeric -- "$@"
ext sxc|xlsx?|xlt|xlw|gnm|gnumeric, has kspread, X, flag f = kspread -- "$@"
@ -155,13 +158,17 @@ ext pptx?|od[dfgpst]|docx?|sxc|xlsx?|xlt|xlw|gnm|gnumeric, has libreoffice, X, f
ext pptx?|od[dfgpst]|docx?|sxc|xlsx?|xlt|xlw|gnm|gnumeric, has soffice, X, flag f = soffice "$@"
ext pptx?|od[dfgpst]|docx?|sxc|xlsx?|xlt|xlw|gnm|gnumeric, has ooffice, X, flag f = ooffice "$@"
ext djvu, has zathura,X, flag f = zathura -- "$@"
ext djvu, has evince, X, flag f = evince -- "$@"
ext djvu, has atril, X, flag f = atril -- "$@"
#-------------------------------------------
# Image Viewing:
#-------------------------------------------
mime ^image, has viewnior, X, flag f = viewnior -- "$@"
mime ^image/svg, has inkscape, X, flag f = inkscape -- "$@"
mime ^image/svg, has display, X, flag f = display -- "$@"
mime ^image, has pqiv, X, flag f = pqiv -- "$@"
mime ^image, has sxiv, X, flag f = sxiv -- "$@"
mime ^image, has feh, X, flag f = feh -- "$@"
mime ^image, has mirage, X, flag f = mirage -- "$@"
@ -174,8 +181,11 @@ ext xcf, X, flag f = gimp -- "$@"
#-------------------------------------------
# Archives
#-------------------------------------------
# avoid password prompt by providing empty password
ext 7z, has 7z = 7z -p l "$@" | "$PAGER"
# This requires atool
ext 7z|ace|ar|arc|bz2?|cab|cpio|cpt|deb|dgc|dmg|gz, has als = als -- "$@" | "$PAGER"
ext ace|ar|arc|bz2?|cab|cpio|cpt|deb|dgc|dmg|gz, has als = als -- "$@" | "$PAGER"
ext iso|jar|msi|pkg|rar|shar|tar|tgz|xar|xpi|xz|zip, has als = als -- "$@" | "$PAGER"
ext 7z|ace|ar|arc|bz2?|cab|cpio|cpt|deb|dgc|dmg|gz, has aunpack = aunpack -- "$@"
ext iso|jar|msi|pkg|rar|shar|tar|tgz|xar|xpi|xz|zip, has aunpack = aunpack -- "$@"
@ -187,12 +197,15 @@ ext tar|gz, has tar = tar vvxf "$@"
#-------------------------------------------
# Misc
#-------------------------------------------
label wallpaper, number 11, mime ^image, X = feh --bg-scale "$1"
label wallpaper, number 12, mime ^image, X = feh --bg-tile "$1"
label wallpaper, number 13, mime ^image, X = feh --bg-center "$1"
label wallpaper, number 14, mime ^image, X = feh --bg-fill "$1"
label wallpaper, number 11, mime ^image, has feh, X = feh --bg-scale "$1"
label wallpaper, number 12, mime ^image, has feh, X = feh --bg-tile "$1"
label wallpaper, number 13, mime ^image, has feh, X = feh --bg-center "$1"
label wallpaper, number 14, mime ^image, has feh, X = feh --bg-fill "$1"
# Define the editor for non-text files + pager as last action
!mime ^text, !ext xml|csv|tex|py|pl|rb|js|sh|php = ask
label editor, !mime ^text, !ext xml|csv|tex|py|pl|rb|js|sh|php = $EDITOR -- "$@"
label pager, !mime ^text, !ext xml|csv|tex|py|pl|rb|js|sh|php = "$PAGER" -- "$@"
!mime ^text, !ext xml|json|csv|tex|py|pl|rb|js|sh|php = ask
label editor, !mime ^text, !ext xml|json|csv|tex|py|pl|rb|js|sh|php = $EDITOR -- "$@"
label pager, !mime ^text, !ext xml|json|csv|tex|py|pl|rb|js|sh|php = "$PAGER" -- "$@"
# The very last action, so that it's never triggered accidentally, is to execute a program:
mime application/x-executable = "$1"

View File

@ -17,18 +17,20 @@
# 4 | fix height | success. Don't reload when height changes
# 5 | fix both | success. Don't ever reload
# 6 | image | success. display the image $cached points to as an image preview
# 7 | image | success. display the file directly as an image
# Meaningful aliases for arguments:
path="$1" # Full path of the selected file
width="$2" # Width of the preview pane (number of fitting characters)
height="$3" # Height of the preview pane (number of fitting characters)
cached="$4" # Path that should be used to cache image previews
path="$1" # Full path of the selected file
width="$2" # Width of the preview pane (number of fitting characters)
height="$3" # Height of the preview pane (number of fitting characters)
cached="$4" # Path that should be used to cache image previews
preview_images="$5" # "True" if image previews are enabled, "False" otherwise.
maxln=200 # Stop after $maxln lines. Can be used like ls | head -n $maxln
# Find out something about the file:
mimetype=$(file --mime-type -Lb "$path")
extension=$(/bin/echo -E "${path##*.}" | tr "[:upper:]" "[:lower:]")
extension=$(/bin/echo "${path##*.}" | awk '{print tolower($0)}')
# Functions:
# runs a command and saves its output into $output. Useful if you need
@ -36,24 +38,45 @@ extension=$(/bin/echo -E "${path##*.}" | tr "[:upper:]" "[:lower:]")
try() { output=$(eval '"$@"'); }
# writes the output of the previously used "try" command
dump() { /bin/echo -E "$output"; }
dump() { /bin/echo "$output"; }
# a common post-processing function used after most commands
trim() { head -n "$maxln"; }
# wraps highlight to treat exit code 141 (killed by SIGPIPE) as success
highlight() { command highlight "$@"; test $? = 0 -o $? = 141; }
safepipe() { "$@"; test $? = 0 -o $? = 141; }
# Image previews, if enabled in ranger.
if [ "$preview_images" = "True" ]; then
case "$mimetype" in
# Image previews for SVG files, disabled by default.
###image/svg+xml)
### convert "$path" "$cached" && exit 6 || exit 1;;
# Image previews for image files. w3mimgdisplay will be called for all
# image files (unless overriden as above), but might fail for
# unsupported types.
image/*)
exit 7;;
# Image preview for video, disabled by default.:
###video/*)
### ffmpegthumbnailer -i "$path" -o "$cached" -s 0 && exit 6 || exit 1;;
esac
fi
case "$extension" in
# Archive extensions:
7z|a|ace|alz|arc|arj|bz|bz2|cab|cpio|deb|gz|jar|lha|lz|lzh|lzma|lzo|\
a|ace|alz|arc|arj|bz|bz2|cab|cpio|deb|gz|jar|lha|lz|lzh|lzma|lzo|\
rpm|rz|t7z|tar|tbz|tbz2|tgz|tlz|txz|tZ|tzo|war|xpi|xz|Z|zip)
try als "$path" && { dump | trim; exit 0; }
try acat "$path" && { dump | trim; exit 3; }
try bsdtar -lf "$path" && { dump | trim; exit 0; }
exit 1;;
rar)
# avoid password prompt by providing empty password
try unrar -p- lt "$path" && { dump | trim; exit 0; } || exit 1;;
7z)
# avoid password prompt by providing empty password
try 7z -p l "$path" && { dump | trim; exit 0; } || exit 1;;
# PDF documents:
pdf)
try pdftotext -l 10 -nopgbrk -q "$path" - && \
@ -61,6 +84,9 @@ case "$extension" in
# BitTorrent Files
torrent)
try transmission-show "$path" && { dump | trim; exit 5; } || exit 1;;
# ODT Files
odt|ods|odp|sxw)
try odt2txt "$path" && { dump | trim; exit 5; } || exit 1;;
# HTML Pages:
htm|html|xhtml)
try w3m -dump "$path" && { dump | trim | fmt -s -w $width; exit 4; }
@ -72,13 +98,19 @@ esac
case "$mimetype" in
# Syntax highlight for text files:
text/* | */xml)
try highlight --out-format=ansi "$path" && { dump | trim; exit 5; } || exit 2;;
if [ "$(tput colors)" -ge 256 ]; then
pygmentize_format=terminal256
highlight_format=xterm256
else
pygmentize_format=terminal
highlight_format=ansi
fi
try safepipe highlight --out-format=${highlight_format} "$path" && { dump | trim; exit 5; }
try safepipe pygmentize -f ${pygmentize_format} "$path" && { dump | trim; exit 5; }
exit 2;;
# Ascii-previews of images:
image/*)
img2txt --gamma=0.6 --width="$width" "$path" && exit 4 || exit 1;;
# Image preview for videos, disabled by default:
# video/*)
# ffmpegthumbnailer -i "$path" -o "$cached" -s 0 && exit 6 || exit 1;;
# Display information about media files:
video/* | audio/*)
exiftool "$path" && exit 5