From 65791ad7cb60d75e435c987ce56bf96633c8f3f8 Mon Sep 17 00:00:00 2001 From: David Chen Date: Tue, 14 May 2019 15:10:33 -0700 Subject: [PATCH] xmodmap. (ranger in progress) --- .Xmodmap | 248 ++++++ i3/config | 4 + ranger/commands.py | 65 ++ ranger/commands_full.py | 1836 +++++++++++++++++++++++++++++++++++++++ ranger/keys.py | 10 + ranger/rc.conf | 1 + ranger/rc1.conf | 729 ++++++++++++++++ ranger/rifle.conf | 256 ++++++ ranger/scope.sh | 216 +++++ 9 files changed, 3365 insertions(+) create mode 100644 .Xmodmap create mode 100644 ranger/commands.py create mode 100644 ranger/commands_full.py create mode 100644 ranger/keys.py create mode 100644 ranger/rc.conf create mode 100644 ranger/rc1.conf create mode 100644 ranger/rifle.conf create mode 100755 ranger/scope.sh diff --git a/.Xmodmap b/.Xmodmap new file mode 100644 index 0000000..71485b4 --- /dev/null +++ b/.Xmodmap @@ -0,0 +1,248 @@ +keycode 8 = +keycode 9 = Escape NoSymbol Escape +keycode 10 = 1 exclam 1 exclam exclamdown onesuperior exclamdown +keycode 11 = 2 at 2 at masculine twosuperior masculine +keycode 12 = 3 numbersign 3 numbersign ordfeminine threesuperior ordfeminine +keycode 13 = 4 dollar 4 dollar cent sterling cent +keycode 14 = 5 percent 5 percent EuroSign yen EuroSign +keycode 15 = 6 asciicircum 6 asciicircum hstroke Hstroke hstroke +keycode 16 = 7 ampersand 7 ampersand eth ETH eth +keycode 17 = 8 asterisk 8 asterisk thorn THORN thorn +keycode 18 = 9 parenleft 9 parenleft leftsinglequotemark leftdoublequotemark leftsinglequotemark +keycode 19 = 0 parenright 0 parenright rightsinglequotemark rightdoublequotemark rightsinglequotemark +keycode 20 = minus underscore minus underscore endash emdash endash +keycode 21 = equal plus equal plus multiply division multiply +keycode 22 = BackSpace BackSpace BackSpace BackSpace +keycode 23 = Tab ISO_Left_Tab Tab ISO_Left_Tab +keycode 24 = q Q q Q adiaeresis Adiaeresis adiaeresis +keycode 25 = w W w W aring Aring aring +keycode 26 = f F f F atilde Atilde atilde +keycode 27 = p P p P oslash Oslash oslash +keycode 28 = g G g G dead_ogonek asciitilde dead_ogonek +keycode 29 = j J j J dstroke Dstroke dstroke +keycode 30 = l L l L lstroke Lstroke lstroke +keycode 31 = u U u U uacute Uacute uacute +keycode 32 = y Y y Y udiaeresis Udiaeresis udiaeresis +keycode 33 = semicolon colon semicolon colon odiaeresis Odiaeresis odiaeresis +keycode 34 = bracketleft braceleft bracketleft braceleft guillemotleft U2039 guillemotleft +keycode 35 = bracketright braceright bracketright braceright guillemotright U203A guillemotright +keycode 36 = Return NoSymbol Return +keycode 64 = Control_L NoSymbol Control_L +keycode 38 = a A a A aacute Aacute aacute +keycode 39 = r R r R dead_grave asciitilde dead_grave +keycode 40 = s S s S ssharp U1E9E ssharp +keycode 41 = t T t T dead_acute dead_doubleacute dead_acute +keycode 42 = d D d D dead_diaeresis asciitilde dead_diaeresis +keycode 43 = h H h H dead_caron asciitilde dead_caron +keycode 44 = n N n N ntilde Ntilde ntilde +keycode 45 = e E e E eacute Eacute eacute +keycode 46 = i I i I iacute Iacute iacute +keycode 47 = o O o O oacute Oacute oacute +keycode 48 = apostrophe quotedbl apostrophe quotedbl otilde Otilde otilde +keycode 49 = grave asciitilde grave asciitilde dead_tilde asciitilde dead_tilde +keycode 50 = Shift_L NoSymbol Shift_L +keycode 51 = backslash bar backslash bar asciitilde asciitilde asciitilde +keycode 52 = z Z z Z ae AE ae +keycode 53 = x X x X dead_circumflex asciitilde dead_circumflex +keycode 54 = c C c C ccedilla Ccedilla ccedilla +keycode 55 = v V v V oe OE oe +keycode 56 = b B b B dead_breve asciitilde dead_breve +keycode 57 = k K k K dead_abovering asciitilde dead_abovering +keycode 58 = m M m M dead_macron asciitilde dead_macron +keycode 59 = comma less comma less dead_cedilla asciitilde dead_cedilla +keycode 60 = period greater period greater dead_abovedot asciitilde dead_abovedot +keycode 61 = slash question slash question questiondown asciitilde questiondown +keycode 62 = Shift_R NoSymbol Shift_R +keycode 63 = KP_Multiply KP_Multiply KP_Multiply KP_Multiply KP_Multiply KP_Multiply XF86ClearGrab +keycode 37 = Alt_L Meta_L Alt_L Meta_L +keycode 65 = space space space space space nobreakspace space +keycode 66 = Escape NoSymbol Escape +keycode 67 = F1 F1 F1 F1 F1 F1 XF86Switch_VT_1 +keycode 68 = F2 F2 F2 F2 F2 F2 XF86Switch_VT_2 +keycode 69 = F3 F3 F3 F3 F3 F3 XF86Switch_VT_3 +keycode 70 = F4 F4 F4 F4 F4 F4 XF86Switch_VT_4 +keycode 71 = F5 F5 F5 F5 F5 F5 XF86Switch_VT_5 +keycode 72 = F6 F6 F6 F6 F6 F6 XF86Switch_VT_6 +keycode 73 = F7 F7 F7 F7 F7 F7 XF86Switch_VT_7 +keycode 74 = F8 F8 F8 F8 F8 F8 XF86Switch_VT_8 +keycode 75 = F9 F9 F9 F9 F9 F9 XF86Switch_VT_9 +keycode 76 = F10 F10 F10 F10 F10 F10 XF86Switch_VT_10 +keycode 77 = Num_Lock NoSymbol Num_Lock +keycode 78 = Scroll_Lock NoSymbol Scroll_Lock +keycode 79 = KP_Home KP_7 KP_Home KP_7 +keycode 80 = KP_Up KP_8 KP_Up KP_8 +keycode 81 = KP_Prior KP_9 KP_Prior KP_9 +keycode 82 = KP_Subtract KP_Subtract KP_Subtract KP_Subtract KP_Subtract KP_Subtract XF86Prev_VMode +keycode 83 = KP_Left KP_4 KP_Left KP_4 +keycode 84 = KP_Begin KP_5 KP_Begin KP_5 +keycode 85 = KP_Right KP_6 KP_Right KP_6 +keycode 86 = KP_Add KP_Add KP_Add KP_Add KP_Add KP_Add XF86Next_VMode +keycode 87 = KP_End KP_1 KP_End KP_1 +keycode 88 = KP_Down KP_2 KP_Down KP_2 +keycode 89 = KP_Next KP_3 KP_Next KP_3 +keycode 90 = KP_Insert KP_0 KP_Insert KP_0 +keycode 91 = KP_Delete KP_Decimal KP_Delete KP_Decimal +keycode 92 = ISO_Level3_Shift NoSymbol ISO_Level3_Shift +keycode 93 = +keycode 94 = minus underscore minus underscore endash emdash endash +keycode 95 = F11 F11 F11 F11 F11 F11 XF86Switch_VT_11 +keycode 96 = F12 F12 F12 F12 F12 F12 XF86Switch_VT_12 +keycode 97 = +keycode 98 = Katakana NoSymbol Katakana +keycode 99 = Hiragana NoSymbol Hiragana +keycode 100 = Henkan_Mode NoSymbol Henkan_Mode +keycode 101 = Hiragana_Katakana NoSymbol Hiragana_Katakana +keycode 102 = Muhenkan NoSymbol Muhenkan +keycode 103 = +keycode 104 = KP_Enter NoSymbol KP_Enter +keycode 105 = Control_R NoSymbol Control_R +keycode 106 = KP_Divide KP_Divide KP_Divide KP_Divide KP_Divide KP_Divide XF86Ungrab +keycode 107 = Print Sys_Req Print Sys_Req +keycode 108 = Super_L NoSymbol Super_L +keycode 109 = Linefeed NoSymbol Linefeed +keycode 110 = Home NoSymbol Home +keycode 111 = Up NoSymbol Up +keycode 112 = Prior NoSymbol Prior +keycode 113 = Left NoSymbol Left +keycode 114 = Right NoSymbol Right +keycode 115 = End NoSymbol End +keycode 116 = Down NoSymbol Down +keycode 117 = Next NoSymbol Next +keycode 118 = Insert NoSymbol Insert +keycode 119 = Delete NoSymbol Delete +keycode 120 = +keycode 121 = XF86AudioMute NoSymbol XF86AudioMute +keycode 122 = XF86AudioLowerVolume NoSymbol XF86AudioLowerVolume +keycode 123 = XF86AudioRaiseVolume NoSymbol XF86AudioRaiseVolume +keycode 124 = XF86PowerOff NoSymbol XF86PowerOff +keycode 125 = KP_Equal NoSymbol KP_Equal +keycode 126 = plusminus NoSymbol plusminus +keycode 127 = Pause Break Pause Break +keycode 128 = XF86LaunchA NoSymbol XF86LaunchA +keycode 129 = KP_Decimal KP_Decimal KP_Decimal KP_Decimal +keycode 130 = Hangul NoSymbol Hangul +keycode 131 = Hangul_Hanja NoSymbol Hangul_Hanja +keycode 132 = +keycode 133 = Super_L NoSymbol Super_L +keycode 108 = Super_R NoSymbol Super_R +keycode 135 = Menu NoSymbol Menu +keycode 136 = Cancel NoSymbol Cancel +keycode 137 = Redo NoSymbol Redo +keycode 138 = SunProps NoSymbol SunProps +keycode 139 = Undo NoSymbol Undo +keycode 140 = SunFront NoSymbol SunFront +keycode 141 = XF86Copy NoSymbol XF86Copy +keycode 142 = XF86Open NoSymbol XF86Open +keycode 143 = XF86Paste NoSymbol XF86Paste +keycode 144 = Find NoSymbol Find +keycode 145 = XF86Cut NoSymbol XF86Cut +keycode 146 = Help NoSymbol Help +keycode 147 = XF86MenuKB NoSymbol XF86MenuKB +keycode 148 = XF86Calculator NoSymbol XF86Calculator +keycode 149 = +keycode 150 = XF86Sleep NoSymbol XF86Sleep +keycode 151 = XF86WakeUp NoSymbol XF86WakeUp +keycode 152 = XF86Explorer NoSymbol XF86Explorer +keycode 153 = XF86Send NoSymbol XF86Send +keycode 154 = +keycode 155 = XF86Xfer NoSymbol XF86Xfer +keycode 156 = XF86Launch1 NoSymbol XF86Launch1 +keycode 157 = XF86Launch2 NoSymbol XF86Launch2 +keycode 158 = XF86WWW NoSymbol XF86WWW +keycode 159 = XF86DOS NoSymbol XF86DOS +keycode 160 = XF86ScreenSaver NoSymbol XF86ScreenSaver +keycode 161 = XF86RotateWindows NoSymbol XF86RotateWindows +keycode 162 = XF86TaskPane NoSymbol XF86TaskPane +keycode 163 = XF86Mail NoSymbol XF86Mail +keycode 164 = XF86Favorites NoSymbol XF86Favorites +keycode 165 = XF86MyComputer NoSymbol XF86MyComputer +keycode 166 = XF86Back NoSymbol XF86Back +keycode 167 = XF86Forward NoSymbol XF86Forward +keycode 168 = +keycode 169 = XF86Eject NoSymbol XF86Eject +keycode 170 = XF86Eject XF86Eject XF86Eject XF86Eject +keycode 171 = XF86AudioNext NoSymbol XF86AudioNext +keycode 172 = XF86AudioPlay XF86AudioPause XF86AudioPlay XF86AudioPause +keycode 173 = XF86AudioPrev NoSymbol XF86AudioPrev +keycode 174 = XF86AudioStop XF86Eject XF86AudioStop XF86Eject +keycode 175 = XF86AudioRecord NoSymbol XF86AudioRecord +keycode 176 = XF86AudioRewind NoSymbol XF86AudioRewind +keycode 177 = XF86Phone NoSymbol XF86Phone +keycode 178 = +keycode 179 = XF86Tools NoSymbol XF86Tools +keycode 180 = XF86HomePage NoSymbol XF86HomePage +keycode 181 = XF86Reload NoSymbol XF86Reload +keycode 182 = XF86Close NoSymbol XF86Close +keycode 183 = +keycode 184 = +keycode 185 = XF86ScrollUp NoSymbol XF86ScrollUp +keycode 186 = XF86ScrollDown NoSymbol XF86ScrollDown +keycode 187 = parenleft NoSymbol parenleft +keycode 188 = parenright NoSymbol parenright +keycode 189 = XF86New NoSymbol XF86New +keycode 190 = Redo NoSymbol Redo +keycode 191 = XF86Tools NoSymbol XF86Tools +keycode 192 = XF86Launch5 NoSymbol XF86Launch5 +keycode 193 = XF86Launch6 NoSymbol XF86Launch6 +keycode 194 = XF86Launch7 NoSymbol XF86Launch7 +keycode 195 = XF86Launch8 NoSymbol XF86Launch8 +keycode 196 = XF86Launch9 NoSymbol XF86Launch9 +keycode 197 = +keycode 198 = XF86AudioMicMute NoSymbol XF86AudioMicMute +keycode 199 = XF86TouchpadToggle NoSymbol XF86TouchpadToggle +keycode 200 = XF86TouchpadOn NoSymbol XF86TouchpadOn +keycode 201 = XF86TouchpadOff NoSymbol XF86TouchpadOff +keycode 202 = +keycode 203 = Mode_switch NoSymbol Mode_switch +keycode 204 = NoSymbol Alt_L NoSymbol Alt_L +keycode 205 = NoSymbol Meta_L NoSymbol Meta_L +keycode 206 = NoSymbol Super_L NoSymbol Super_L +keycode 207 = NoSymbol Hyper_L NoSymbol Hyper_L +keycode 208 = XF86AudioPlay NoSymbol XF86AudioPlay +keycode 209 = XF86AudioPause NoSymbol XF86AudioPause +keycode 210 = XF86Launch3 NoSymbol XF86Launch3 +keycode 211 = XF86Launch4 NoSymbol XF86Launch4 +keycode 212 = XF86LaunchB NoSymbol XF86LaunchB +keycode 213 = XF86Suspend NoSymbol XF86Suspend +keycode 214 = XF86Close NoSymbol XF86Close +keycode 215 = XF86AudioPlay NoSymbol XF86AudioPlay +keycode 216 = XF86AudioForward NoSymbol XF86AudioForward +keycode 217 = +keycode 218 = Print NoSymbol Print +keycode 219 = +keycode 220 = XF86WebCam NoSymbol XF86WebCam +keycode 221 = +keycode 222 = +keycode 223 = XF86Mail NoSymbol XF86Mail +keycode 224 = XF86Messenger NoSymbol XF86Messenger +keycode 225 = XF86Search NoSymbol XF86Search +keycode 226 = XF86Go NoSymbol XF86Go +keycode 227 = XF86Finance NoSymbol XF86Finance +keycode 228 = XF86Game NoSymbol XF86Game +keycode 229 = XF86Shop NoSymbol XF86Shop +keycode 230 = +keycode 231 = Cancel NoSymbol Cancel +keycode 232 = XF86MonBrightnessDown NoSymbol XF86MonBrightnessDown +keycode 233 = XF86MonBrightnessUp NoSymbol XF86MonBrightnessUp +keycode 234 = XF86AudioMedia NoSymbol XF86AudioMedia +keycode 235 = XF86Display NoSymbol XF86Display +keycode 236 = XF86KbdLightOnOff NoSymbol XF86KbdLightOnOff +keycode 237 = XF86KbdBrightnessDown NoSymbol XF86KbdBrightnessDown +keycode 238 = XF86KbdBrightnessUp NoSymbol XF86KbdBrightnessUp +keycode 239 = XF86Send NoSymbol XF86Send +keycode 240 = XF86Reply NoSymbol XF86Reply +keycode 241 = XF86MailForward NoSymbol XF86MailForward +keycode 242 = XF86Save NoSymbol XF86Save +keycode 243 = XF86Documents NoSymbol XF86Documents +keycode 244 = XF86Battery NoSymbol XF86Battery +keycode 245 = XF86Bluetooth NoSymbol XF86Bluetooth +keycode 246 = XF86WLAN NoSymbol XF86WLAN +keycode 247 = +keycode 248 = +keycode 249 = +keycode 250 = +keycode 251 = +keycode 252 = +keycode 253 = +keycode 254 = XF86WWAN NoSymbol XF86WWAN +keycode 255 = XF86RFKill NoSymbol XF86RFKill diff --git a/i3/config b/i3/config index e04bbeb..e0b6841 100644 --- a/i3/config +++ b/i3/config @@ -40,6 +40,10 @@ bindsym $mod+Return exec i3-sensible-terminal # kill focused window bindsym $mod+Shift+q kill +# Open browser +bindsym $mod+b exec chromium + + # start dmenu (a program launcher) bindsym $mod+s exec dmenu_run # There also is the (new) i3-dmenu-desktop which only displays applications diff --git a/ranger/commands.py b/ranger/commands.py new file mode 100644 index 0000000..edd7e6b --- /dev/null +++ b/ranger/commands.py @@ -0,0 +1,65 @@ +# This is a sample commands.py. You can add your own commands here. +# +# Please refer to commands_full.py for all the default commands and a complete +# documentation. Do NOT add them all here, or you may end up with defunct +# commands when upgrading ranger. + +# A simple command for demonstration purposes follows. +# ----------------------------------------------------------------------------- + +from __future__ import (absolute_import, division, print_function) + +# You can import any python module as needed. +import os + +# You always need to import ranger.api.commands here to get the Command class: +from ranger.api.commands import Command + + +# Any class that is a subclass of "Command" will be integrated into ranger as a +# command. Try typing ":my_edit" 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. + """:my_edit + + A sample command for demonstration purposes that opens a file in an editor. + """ + + # The execute method is called when you run this command in ranger. + def execute(self): + # self.arg(1) is the first (space-separated) argument to the function. + # This way you can write ":my_edit somefilename". + if self.arg(1): + # self.rest(1) contains self.arg(1) and everything that follows + target_filename = self.rest(1) + else: + # self.fm is a ranger.core.filemanager.FileManager object and gives + # you access to internals of ranger. + # self.fm.thisfile is a ranger.container.file.File object and is a + # reference to the currently selected file. + target_filename = self.fm.thisfile.path + + # 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: + if not os.path.exists(target_filename): + self.fm.notify("The given file does not exist!", bad=True) + return + + # This executes a function from ranger.core.acitons, a module with a + # variety of subroutines that can help you construct commands. + # Check out the source, or run "pydoc ranger.core.actions" for a list. + self.fm.edit_file(target_filename) + + # The tab method is called when you press tab, and should return a list of + # suggestions that the user will tab through. + # tabnum is 1 for and -1 for 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() + + + diff --git a/ranger/commands_full.py b/ranger/commands_full.py new file mode 100644 index 0000000..d177203 --- /dev/null +++ b/ranger/commands_full.py @@ -0,0 +1,1836 @@ +# -*- coding: utf-8 -*- +# This file is part of ranger, the console file manager. +# This configuration file is licensed under the same terms as ranger. +# =================================================================== +# +# NOTE: If you copied this file to /etc/ranger/commands_full.py or +# ~/.config/ranger/commands_full.py, then it will NOT be loaded by ranger, +# and only serve as a reference. +# +# =================================================================== +# This file contains ranger's commands. +# It's all in python; lines beginning with # are comments. +# +# Note that additional commands are automatically generated from the methods +# of the class ranger.core.actions.Actions. +# +# You can customize commands in the files /etc/ranger/commands.py (system-wide) +# and ~/.config/ranger/commands.py (per user). +# They have the same syntax as this file. In fact, you can just copy this +# file to ~/.config/ranger/commands_full.py with +# `ranger --copy-config=commands_full' and make your modifications, don't +# forget to rename it to commands.py. You can also use +# `ranger --copy-config=commands' to copy a short sample commands.py that +# has everything you need to get started. +# But make sure you update your configs when you update ranger. +# +# =================================================================== +# 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(tabnum): called when is pressed. +# quick(): called after each keypress. +# +# tab() argument tabnum is 1 for and -1 for by default +# +# The return values for tab() can be either: +# None: There is no tab completion +# A string: Change the console to this string +# A list/tuple/generator: cycle through every item in it +# +# The return value for quick() can be: +# False: Nothing happens +# True: Execute the command afterwards +# +# The return value for execute() and cancel() doesn't matter. +# +# =================================================================== +# Commands have certain attributes and methods that facilitate parsing of +# the arguments: +# +# self.line: The whole line that was written in the console. +# self.args: A list of all (space-separated) arguments to the command. +# self.quantifier: If this command was mapped to the key "X" and +# the user pressed 6X, self.quantifier will be 6. +# self.arg(n): The n-th argument, or an empty string if it doesn't exist. +# self.rest(n): The n-th argument plus everything that followed. For example, +# if the command was "search foo bar a b c", rest(2) will be "bar a b c" +# self.start(n): Anything before the n-th argument. For example, if the +# command was "search foo bar a b c", start(2) will be "search foo" +# +# =================================================================== +# And this is a little reference for common ranger functions and objects: +# +# self.fm: A reference to the "fm" object which contains most information +# about ranger. +# self.fm.notify(string): Print the given string on the screen. +# self.fm.notify(string, bad=True): Print the given string in RED. +# self.fm.reload_cwd(): Reload the current working directory. +# self.fm.thisdir: The current working directory. (A File object.) +# self.fm.thisfile: The current file. (A File object too.) +# self.fm.thistab.get_selection(): A list of all selected files. +# self.fm.execute_console(string): Execute the string as a ranger command. +# self.fm.open_console(string): Open the console with the given string +# already typed in for you. +# self.fm.move(direction): Moves the cursor in the given direction, which +# can be something like down=3, up=5, right=1, left=1, to=6, ... +# +# File objects (for example self.fm.thisfile) have these useful attributes and +# methods: +# +# tfile.path: The path to the file. +# tfile.basename: The base name only. +# tfile.load_content(): Force a loading of the directories content (which +# obviously works with directories only) +# tfile.is_directory: True/False depending on whether it's a directory. +# +# For advanced commands it is unavoidable to dive a bit into the source code +# of ranger. +# =================================================================== + +from __future__ import (absolute_import, division, print_function) + +from collections import deque +import os +import re + +from ranger.api.commands import Command + + +class alias(Command): + """:alias + + Copies the oldcommand as newcommand. + """ + + context = 'browser' + resolve_macros = False + + def execute(self): + if not self.arg(1) or not self.arg(2): + self.fm.notify('Syntax: alias ', bad=True) + return + + self.fm.commands.alias(self.arg(1), self.rest(2)) + + +class echo(Command): + """:echo + + Display the text in the statusbar. + """ + + def execute(self): + self.fm.notify(self.rest(1)) + + +class cd(Command): + """:cd [-r] + + The cd command changes the directory. + If the path is a file, selects that file. + The command 'cd -' is equivalent to typing ``. + Using the option "-r" will get you to the real path. + """ + + def execute(self): + if self.arg(1) == '-r': + self.shift() + destination = os.path.realpath(self.rest(1)) + if os.path.isfile(destination): + self.fm.select_file(destination) + return + else: + destination = self.rest(1) + + if not destination: + destination = '~' + + if destination == '-': + self.fm.enter_bookmark('`') + else: + self.fm.cd(destination) + + def _tab_args(self): + # dest must be rest because path could contain spaces + if self.arg(1) == '-r': + start = self.start(2) + dest = self.rest(2) + else: + start = self.start(1) + dest = self.rest(1) + + if dest: + head, tail = os.path.split(os.path.expanduser(dest)) + if head: + dest_exp = os.path.join(os.path.normpath(head), tail) + else: + dest_exp = tail + else: + dest_exp = '' + return (start, dest_exp, os.path.join(self.fm.thisdir.path, dest_exp), + dest.endswith(os.path.sep)) + + @staticmethod + def _tab_paths(dest, dest_abs, ends_with_sep): + if not dest: + try: + return next(os.walk(dest_abs))[1], dest_abs + except (OSError, StopIteration): + return [], '' + + if ends_with_sep: + try: + return [os.path.join(dest, path) for path in next(os.walk(dest_abs))[1]], '' + except (OSError, StopIteration): + return [], '' + + return None, None + + def _tab_match(self, path_user, path_file): + if self.fm.settings.cd_tab_case == 'insensitive': + path_user = path_user.lower() + path_file = path_file.lower() + elif self.fm.settings.cd_tab_case == 'smart' and path_user.islower(): + path_file = path_file.lower() + return path_file.startswith(path_user) + + def _tab_normal(self, dest, dest_abs): + dest_dir = os.path.dirname(dest) + dest_base = os.path.basename(dest) + + try: + dirnames = next(os.walk(os.path.dirname(dest_abs)))[1] + except (OSError, StopIteration): + return [], '' + + return [os.path.join(dest_dir, d) for d in dirnames if self._tab_match(dest_base, d)], '' + + def _tab_fuzzy_match(self, basepath, tokens): + """ Find directories matching tokens recursively """ + if not tokens: + tokens = [''] + paths = [basepath] + while True: + token = tokens.pop() + matches = [] + for path in paths: + try: + directories = next(os.walk(path))[1] + except (OSError, StopIteration): + continue + matches += [os.path.join(path, d) for d in directories + if self._tab_match(token, d)] + if not tokens or not matches: + return matches + paths = matches + + return None + + def _tab_fuzzy(self, dest, dest_abs): + tokens = [] + basepath = dest_abs + while True: + basepath_old = basepath + basepath, token = os.path.split(basepath) + if basepath == basepath_old: + break + if os.path.isdir(basepath_old) and not token.startswith('.'): + basepath = basepath_old + break + tokens.append(token) + + paths = self._tab_fuzzy_match(basepath, tokens) + if not os.path.isabs(dest): + paths_rel = basepath + paths = [os.path.relpath(path, paths_rel) for path in paths] + else: + paths_rel = '' + return paths, paths_rel + + def tab(self, tabnum): + from os.path import sep + + start, dest, dest_abs, ends_with_sep = self._tab_args() + + paths, paths_rel = self._tab_paths(dest, dest_abs, ends_with_sep) + if paths is None: + if self.fm.settings.cd_tab_fuzzy: + paths, paths_rel = self._tab_fuzzy(dest, dest_abs) + else: + paths, paths_rel = self._tab_normal(dest, dest_abs) + + paths.sort() + + if self.fm.settings.cd_bookmarks: + paths[0:0] = [ + os.path.relpath(v.path, paths_rel) if paths_rel else v.path + for v in self.fm.bookmarks.dct.values() for path in paths + if v.path.startswith(os.path.join(paths_rel, path) + sep) + ] + + if not paths: + return None + if len(paths) == 1: + return start + paths[0] + sep + return [start + dirname for dirname in paths] + + +class chain(Command): + """:chain ; ; ... + + Calls multiple commands at once, separated by semicolons. + """ + + def execute(self): + if not self.rest(1).strip(): + self.fm.notify('Syntax: chain ; ; ...', bad=True) + return + for command in [s.strip() for s in self.rest(1).split(";")]: + self.fm.execute_console(command) + + +class shell(Command): + escape_macros_for_shell = True + + def execute(self): + if self.arg(1) and self.arg(1)[0] == '-': + flags = self.arg(1)[1:] + command = self.rest(2) + else: + flags = '' + command = self.rest(1) + + if command: + self.fm.execute_command(command, flags=flags) + + 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) + else: + command = self.rest(1) + start = self.line[0:len(self.line) - len(command)] + + try: + position_of_last_space = command.rindex(" ") + except ValueError: + 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() + if len(selection) == 1: + return self.line + selection[0].shell_escaped_basename + ' ' + return self.line + '%s ' + + before_word, start_of_word = self.line.rsplit(' ', 1) + 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) + + def tab(self, tabnum): + return self._tab_through_executables() + + def _get_app_flags_mode(self, string): # pylint: disable=too-many-branches,too-many-statements + """Extracts the application, flags and mode from a string. + + examples: + "mplayer f 1" => ("mplayer", "f", 1) + "atool 4" => ("atool", "", 4) + "p" => ("", "p", 0) + "" => None + """ + + app = '' + flags = '' + mode = 0 + split = string.split() + + if len(split) == 1: + part = split[0] + if self._is_app(part): + app = part + elif self._is_flags(part): + flags = part + elif self._is_mode(part): + mode = part + + elif len(split) == 2: + part0 = split[0] + part1 = split[1] + + if self._is_app(part0): + app = part0 + if self._is_flags(part1): + flags = part1 + elif self._is_mode(part1): + mode = part1 + elif self._is_flags(part0): + flags = part0 + if self._is_mode(part1): + mode = part1 + elif self._is_mode(part0): + mode = part0 + if self._is_flags(part1): + flags = part1 + + elif len(split) >= 3: + part0 = split[0] + part1 = split[1] + part2 = split[2] + + if self._is_app(part0): + app = part0 + if self._is_flags(part1): + flags = part1 + if self._is_mode(part2): + mode = part2 + elif self._is_mode(part1): + mode = part1 + if self._is_flags(part2): + flags = part2 + elif self._is_flags(part0): + flags = part0 + if self._is_mode(part1): + mode = part1 + elif self._is_mode(part0): + mode = part0 + if self._is_flags(part1): + flags = part1 + + return app, flags, int(mode) + + def _is_app(self, arg): + return not self._is_flags(arg) and not arg.isdigit() + + @staticmethod + def _is_flags(arg): + from ranger.core.runner import ALLOWED_FLAGS + return all(x in ALLOWED_FLAGS for x in arg) + + @staticmethod + def _is_mode(arg): + return all(x in '0123456789' for x in arg) + + +class set_(Command): + """:set