commit 7cc272c5950f715fd921ce4ed6c555ff7dd9de10 Author: pika Date: Tue Apr 1 18:57:43 2025 +0200 batman diff --git a/README.md b/README.md new file mode 100644 index 0000000..23e0c75 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# i3 dotfiles + +The most simple desktop env i've ever used i think. Needs picom but this will be addet later diff --git a/dots/.Xresources b/dots/.Xresources new file mode 100755 index 0000000..32af16d --- /dev/null +++ b/dots/.Xresources @@ -0,0 +1,78 @@ +!! Colorscheme + +! special +*.foreground: #93a1a1 +*.background: #141c21 +*.cursorColor: #afbfbf + +! black +*.color0: #263640 +*.color8: #4a697d + +! red +*.color1: #d12f2c +*.color9: #fa3935 + +! green +*.color2: #819400 +*.color10: #a4bd00 + +! yellow +*.color3: #b08500 +*.color11: #d9a400 + +! blue +*.color4: #2587cc +*.color12: #2ca2f5 + +! magenta +*.color5: #696ebf +*.color13: #8086e8 + +! cyan +*.color6: #289c93 +*.color14: #33c5ba + +! white +*.color7: #bfbaac +*.color15: #fdf6e3 + +!! URxvt Appearance +URxvt.font: xft:SpaceMono:style=Regular:size=9 +URxvt.boldFont: xft:SpaceMono:style=Bold:size=9 +URxvt.italicFont: xft:SpaceMono:style=Italic:size=9 +URxvt.boldItalicfont: xft:SpaceMono:style=Bold Italic:size=9 +URxvt.letterSpace: -1 +URxvt.lineSpace: 0 +URxvt.geometry: 92x24 +URxvt.internalBorder: 24 +URxvt.cursorBlink: true +URxvt.cursorUnderline: false +URxvt.saveline: 2048 +URxvt.scrollBar: false +URxvt.scrollBar_right: false +URxvt.urgentOnBell: true +URxvt.depth: 24 +URxvt.iso14755: false + +!! Common Keybinds for Navigations +URxvt.keysym.Shift-Up: command:\033]720;1\007 +URxvt.keysym.Shift-Down: command:\033]721;1\007 +URxvt.keysym.Control-Up: \033[1;5A +URxvt.keysym.Control-Down: \033[1;5B +URxvt.keysym.Control-Right: \033[1;5C +URxvt.keysym.Control-Left: \033[1;5D + +!! Copy Paste & Other Extensions +URxvt.perl-ext-common: default,clipboard,url-select,keyboard-select +URxvt.copyCommand: xclip -i -selection clipboard +URxvt.pasteCommand: xclip -o -selection clipboard +URxvt.keysym.M-c: perl:clipboard:copy +URxvt.keysym.M-v: perl:clipboard:paste +URxvt.keysym.M-C-v: perl:clipboard:paste_escaped +URxvt.keysym.M-Escape: perl:keyboard-select:activate +URxvt.keysym.M-s: perl:keyboard-select:search +URxvt.keysym.M-u: perl:url-select:select_next +URxvt.urlLauncher: firefox +URxvt.underlineURLs: true +URxvt.urlButton: 1 diff --git a/dots/.config/dunst/dunstrc b/dots/.config/dunst/dunstrc new file mode 100755 index 0000000..c3e8620 --- /dev/null +++ b/dots/.config/dunst/dunstrc @@ -0,0 +1,54 @@ +[global] +monitor = 0 +follow = mouse +geometry = "320x120-28-28" +indicate_hidden = yes +shrink = no +separator_height = 0 +padding = 32 +horizontal_padding = 48 +frame_width = 4 +sort = no +idle_threshold = 120 +font = Poppins 9 +line_height = 4 +markup = full +format = %s\n%b +alignment = left +show_age_threshold = 60 +word_wrap = yes +ignore_newline = no +stack_duplicates = false +hide_duplicate_count = yes +show_indicators = no +icon_position = off +sticky_history = yes +history_length = 20 +browser = x-www-browser -new-tab +always_run_script = true +title = Dunst +class = Dunst + +[shortcuts] +close = ctrl+shift+space +close_all = ctrl+shift+space +history = ctrl+grave +context = ctrl+shift+period + +[urgency_low] +timeout = 4 +background = "#141c21" +foreground = "#93a1a1" +frame_color = "#819400" + +[urgency_normal] +timeout = 8 +background = "#141c21" +foreground = "#93a1a1" +frame_color = "#2587cc" + +[urgency_critical] +timeout = 0 +background = "#141c21" +foreground = "#93a1a1" +frame_color = "#d12f2c" diff --git a/dots/.config/i3/config b/dots/.config/i3/config new file mode 100755 index 0000000..42c4001 --- /dev/null +++ b/dots/.config/i3/config @@ -0,0 +1,153 @@ +# set modifier +set $win Mod4 +set $super Mod1 +# which should be ALT + +# set font +font pango:"JetBrainsMono Nerd Font" 9, Rubik Regular 9 + +# use mouse+$super to drag floating windows to their wanted position +floating_modifier $super + +# autostart +exec --no-startup-id hsetroot -center ~/.wallpaper.png + +# start a terminal +bindsym $super+Return exec i3-sensible-terminal +bindsym $super+t exec ghostty + +bindsym $win+r exec rofi -show drun -modi drun,filebrowser,run,window,ssh + +# start dmenu (a program launcher) +bindsym $super+d exec i3-dmenu-desktop --dmenu="dmenu -i -b \ +-fn 'Poppins:size=9' -nb '#141c21' -nf '#93a1a1' \ +-sb '#289c93' -sf '#141c21'" + +# common apps keybinds +bindsym Print exec scrot 'Cheese_%a-%d%b%y_%H.%M.png' -e 'xdg-open ~/$f' +bindsym $win+l exec i3lock -i ~/.lock.png +bindsym $super+c exec zen-browser +bindsym $super+e exec caja + +# change volume and brightness +bindsym XF86AudioRaiseVolume exec amixer -q set Master 5%+ +bindsym XF86AudioLowerVolume exec amixer -q set Master 5%- +bindsym XF86AudioMute exec amixer set Master toggle +bindsym XF86MonBrightnessUp exec brightnessctl set 5%+ +bindsym XF86MonBrightnessDown exec brightnessctl set 5%- + +# kill focused window +bindsym $super+q kill +bindsym $win+F4 kill + +# change focus +# bindsym $super+Left focus left +# bindsym $super+Down focus down +# bindsym $super+Up focus up +# bindsym $super+Right focus right + +# move focused window +# bindsym $super+Shift+Left move left +# bindsym $super+Shift+Down move down +# bindsym $super+Shift+Up move up +# bindsym $super+Shift+Right move right + +# change focus -- VIM +bindsym $super+h focus left +bindsym $super+j focus down +bindsym $super+k focus up +bindsym $super+l focus right + +# move focused window -- VIM +bindsym $super+Control+h move left +bindsym $super+Control+j move down +bindsym $super+Control+k move up +bindsym $super+Control+l move right + +# split in horizontal or vertical orientation +bindsym $win+h split h +bindsym $win+v split v + +# change split direction for already opened windows +bindsym $super+s layout toggle split + +# enter fullscreen mode for the focused container +bindsym $super+f fullscreen toggle + +# toggle tiling / floating +bindsym $super+Shift+f floating toggle + +# change focus between tiling / floating windows +bindsym $super+Shift+space focus mode_toggle + +# switch to workspace +bindsym $super+Shift+l workspace next +bindsym $super+Shift+h workspace prev +bindsym $super+1 workspace 1:I +bindsym $super+2 workspace 2:II +bindsym $super+3 workspace 3:III +bindsym $super+4 workspace 4:IV +bindsym $super+5 workspace 5:V +bindsym $super+6 workspace 6:VI + +# move focused container to workspace +bindsym $super+Shift+1 move container to workspace 1:I +bindsym $super+Shift+2 move container to workspace 2:II +bindsym $super+Shift+3 move container to workspace 3:III +bindsym $super+Shift+4 move container to workspace 4:IV +bindsym $super+Shift+5 move container to workspace 5:V +bindsym $super+Shift+6 move container to workspace 6:VI + +# restart i3 inplace (preserves your layout/session, can be used to upgrade i3) +bindsym $super+Shift+r exec "i3-msg restart" + +# exit i3 +bindsym $super+Shift+m exec "i3-nagbar -t warning -m 'Really, exit?' \ +-b 'Yes' 'i3-msg exit'" + +# resize window (you can also use the mouse for that) +mode "resize" { + bindsym h resize shrink width 5 px or 5 ppt + bindsym j resize grow height 5 px or 5 ppt + bindsym k resize shrink height 5 px or 5 ppt + bindsym l resize grow width 5 px or 5 ppt + bindsym Return mode "default" + } +bindsym $super+r mode "resize" + +# panel +bar { + status_command i3status + position top + workspace_min_width 24 + padding 2px 8px 2px 8px + strip_workspace_numbers yes + + colors { + background #141c21 + statusline #141c21 + separator #141c21 + + # colour of border, background, and text + focused_workspace #141c21 #d12f2c #93a1a1 + active_workspace #141c21 #141c21 #93a1a1 + inactive_workspace #141c21 #141c21 #93a1a1 + urgent_workspace #141c21 #b08500 #93a1a1 + } +} + +# colour of border, background, text, indicator, and child_border +client.focused #d12f2c #263640 #93a1a1 #696ebf #2587cc1 +client.focused_inactive #263640 #b08500 #93a1a1 #263640 #263640 +client.unfocused #263640 #b08500 #93a1a1 #263640 #263640 +client.urgent #263640 #b08500 #93a1a1 #263640 #263640 +client.placeholder #263640 #b08500 #93a1a1 #263640 #263640 +client.background #263640 + +# window rules, you can find the window class using xprop +for_window [class=Eog|Sxiv|feh|mpv|Vlc|File-roller|Xarchiver] floating enable +for_window [class=Eog|Sxiv|feh|mpv|Vlc|File-roller|Xarchiver] focus +for_window [class=".*"] border pixel 8 +hide_edge_borders smart +gaps inner 12 +smart_gaps on diff --git a/dots/.config/i3status/config b/dots/.config/i3status/config new file mode 100755 index 0000000..d43e4a0 --- /dev/null +++ b/dots/.config/i3status/config @@ -0,0 +1,53 @@ +general { + output_format = "i3bar" + colors = true + markup = pango + interval = 5 +} + +order += "load" +order += "cpu_temperature 0" +# order += "wireless wlp2s0" +order += "volume master" +# order += "battery 0" +order += "time" + +load { + format = " %5min Load " +} + +cpu_temperature 0 { + format = " %degrees °C " + path = "/sys/devices/platform/asus-ec-sensors/hwmon/hwmon4/temp2_input" +} + +wireless enp7s0 { + format_up = " %essid " + format_down = " Disconnected " +} + +volume master { + format = " %volume " + format_muted = " Muted " + device = "default" + mixer = "Master" + mixer_idx = 0 +} + +battery 0 { + last_full_capacity = true + format = " %status %percentage " + format_down = "No Battery" + status_chr = "" + status_bat = "" + status_unk = "" + status_full = "" + path = "/sys/class/power_supply/BAT%d/uevent" + low_threshold = 10 + integer_battery_capacity = true +} + +time { + format = " %b %d at %H:%M " +} + diff --git a/dots/.config/ranger/bookmarks b/dots/.config/ranger/bookmarks new file mode 100755 index 0000000..d635feb --- /dev/null +++ b/dots/.config/ranger/bookmarks @@ -0,0 +1,8 @@ +c:/home/addy/.config +o:/home/addy/.config/openbox +a:/media/addy/Media/anime +m:/media/addy/Media/movie +t:/media/addy/Media/tv-series +s:/media/addy/Media/musik +i:/home/addy/.fonts +':/home/liveuser/.config/i3status diff --git a/dots/.config/ranger/colorschemes/__init__.py b/dots/.config/ranger/colorschemes/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/dots/.config/ranger/colorschemes/__init__.pyo b/dots/.config/ranger/colorschemes/__init__.pyo new file mode 100755 index 0000000..419385e Binary files /dev/null and b/dots/.config/ranger/colorschemes/__init__.pyo differ diff --git a/dots/.config/ranger/colorschemes/__pycache__/__init__.cpython-312.pyc b/dots/.config/ranger/colorschemes/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..31af054 Binary files /dev/null and b/dots/.config/ranger/colorschemes/__pycache__/__init__.cpython-312.pyc differ diff --git a/dots/.config/ranger/colorschemes/__pycache__/__init__.cpython-37.opt-1.pyc b/dots/.config/ranger/colorschemes/__pycache__/__init__.cpython-37.opt-1.pyc new file mode 100755 index 0000000..2bb49d7 Binary files /dev/null and b/dots/.config/ranger/colorschemes/__pycache__/__init__.cpython-37.opt-1.pyc differ diff --git a/dots/.config/ranger/colorschemes/__pycache__/tofu.cpython-312.pyc b/dots/.config/ranger/colorschemes/__pycache__/tofu.cpython-312.pyc new file mode 100644 index 0000000..98ff726 Binary files /dev/null and b/dots/.config/ranger/colorschemes/__pycache__/tofu.cpython-312.pyc differ diff --git a/dots/.config/ranger/colorschemes/__pycache__/tofu.cpython-37.opt-1.pyc b/dots/.config/ranger/colorschemes/__pycache__/tofu.cpython-37.opt-1.pyc new file mode 100755 index 0000000..296d8be Binary files /dev/null and b/dots/.config/ranger/colorschemes/__pycache__/tofu.cpython-37.opt-1.pyc differ diff --git a/dots/.config/ranger/colorschemes/default.pyo b/dots/.config/ranger/colorschemes/default.pyo new file mode 100755 index 0000000..6e77a6c Binary files /dev/null and b/dots/.config/ranger/colorschemes/default.pyo differ diff --git a/dots/.config/ranger/colorschemes/tofu.py b/dots/.config/ranger/colorschemes/tofu.py new file mode 100755 index 0000000..3032383 --- /dev/null +++ b/dots/.config/ranger/colorschemes/tofu.py @@ -0,0 +1,44 @@ +from ranger.gui.color import * +from ranger.colorschemes.default import Default + +class Scheme(Default): + progress_bar_color = green + def use(self, context): + fg, bg, attr = Default.use(self, context) + + if context.directory and not context.marked and not context.link: + fg = blue + + if context.in_titlebar: + if context.hostname: + if context.good: + fg = cyan + elif context.bad: + fg = red + else: + fg = default + + if context.reset: + return default_colors + + if context.border: + fg = black + + if context.in_taskview: + fg = green + + if context.in_statusbar: + if context.permissions: + if context.good: + fg = magenta + elif context.bad: + fg = red + if context.message: + if context.good: + attr |= bold + fg = yellow + elif context.bad: + attr |= bold + fg = red + + return fg, bg, attr diff --git a/dots/.config/ranger/colorschemes/tofu.pyo b/dots/.config/ranger/colorschemes/tofu.pyo new file mode 100755 index 0000000..b59362b Binary files /dev/null and b/dots/.config/ranger/colorschemes/tofu.pyo differ diff --git a/dots/.config/ranger/commands.py b/dots/.config/ranger/commands.py new file mode 100755 index 0000000..97b7909 --- /dev/null +++ b/dots/.config/ranger/commands.py @@ -0,0 +1,62 @@ +# 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/dots/.config/ranger/commands_full.py b/dots/.config/ranger/commands_full.py new file mode 100755 index 0000000..d177203 --- /dev/null +++ b/dots/.config/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