all repos — dotfiles-extra @ d8e4339a351e8556ffe76d3c79be8c8fafa9cd66

extra configs that may be extraneous and/or may be platform specific

Initial commit of extra misc. dotfiles
x1phosura x1phosura@x1phosura.zone
Tue, 26 Dec 2023 00:26:00 -0800
commit

d8e4339a351e8556ffe76d3c79be8c8fafa9cd66

71 files changed, 13591 insertions(+), 0 deletions(-)

jump to
A .config/fluxbox/apps

@@ -0,0 +1,4 @@

+[app] (name=fbrun) + [Position] (WINCENTER) {0 0} + [Layer] {2} +[end]
A .config/fluxbox/init

@@ -0,0 +1,76 @@

+session.screen0.menu.alpha: 255 +session.screen0.window.focus.alpha: 255 +session.screen0.window.unfocus.alpha: 255 +session.screen0.tab.placement: TopLeft +session.screen0.tab.width: 64 +session.screen0.toolbar.maxOver: false +session.screen0.toolbar.widthPercent: 100 +session.screen0.toolbar.placement: BottomCenter +session.screen0.toolbar.height: 0 +session.screen0.toolbar.onhead: 1 +session.screen0.toolbar.tools: prevworkspace, workspacename, nextworkspace, iconbar, systemtray, clock +session.screen0.toolbar.visible: true +session.screen0.toolbar.autoHide: false +session.screen0.toolbar.alpha: 255 +session.screen0.toolbar.layer: Dock +session.screen0.clientMenu.usePixmap: true +session.screen0.slit.onhead: 0 +session.screen0.slit.maxOver: false +session.screen0.slit.autoHide: false +session.screen0.slit.placement: RightTop +session.screen0.slit.acceptKdeDockapps: true +session.screen0.slit.alpha: 255 +session.screen0.slit.layer: Dock +session.screen0.iconbar.iconTextPadding: 10 +session.screen0.iconbar.usePixmap: true +session.screen0.iconbar.iconWidth: 128 +session.screen0.iconbar.alignment: Relative +session.screen0.iconbar.mode: {static groups} (workspace) +session.screen0.tabs.usePixmap: true +session.screen0.tabs.maxOver: false +session.screen0.tabs.intitlebar: true +session.screen0.titlebar.left: Stick +session.screen0.titlebar.right: Minimize Maximize Close +session.screen0.workspaces: 4 +session.screen0.focusModel: MouseFocus +session.screen0.maxDisableResize: false +session.screen0.menuDelay: 200 +session.screen0.workspacewarping: true +session.screen0.windowPlacement: RowMinOverlapPlacement +session.screen0.tooltipDelay: 500 +session.screen0.colPlacementDirection: TopToBottom +session.screen0.maxDisableMove: false +session.screen0.maxIgnoreIncrement: true +session.screen0.opaqueMove: true +session.screen0.clickRaises: true +session.screen0.defaultDeco: NORMAL +session.screen0.rowPlacementDirection: LeftToRight +session.screen0.tabFocusModel: ClickToTabFocus +session.screen0.fullMaximization: false +session.screen0.focusSameHead: false +session.screen0.noFocusWhileTypingDelay: 0 +session.screen0.workspaceNames: Workspace 1,Workspace 2,Workspace 3,Workspace 4, +session.screen0.autoRaise: true +session.screen0.windowMenu: /home/x1phosura/.fluxbox/windowmenu +session.screen0.showwindowposition: false +session.screen0.focusNewWindows: true +session.screen0.strftimeFormat: %k:%M +session.screen0.allowRemoteActions: false +session.screen0.edgeSnapThreshold: 10 +session.forcePseudoTransparency: false +session.styleOverlay: /home/x1phosura/.fluxbox/overlay +session.styleFile: /usr/share/fluxbox/styles/green_tea +session.tabPadding: 0 +session.autoRaiseDelay: 250 +session.doubleClickInterval: 250 +session.cacheMax: 200 +session.tabsAttachArea: Window +session.configVersion: 13 +session.colorsPerChannel: 4 +session.cacheLife: 5 +session.appsFile: /home/x1phosura/.fluxbox/apps +session.menuFile: ~/.fluxbox/menu +session.ignoreBorder: false +session.keyFile: ~/.fluxbox/keys +session.menuSearch: itemstart +session.slitlistFile: /home/x1phosura/.fluxbox/slitlist
A .config/fluxbox/keys

@@ -0,0 +1,138 @@

+# click on the desktop to get menus +OnDesktop Mouse1 :HideMenus +OnDesktop Mouse2 :WorkspaceMenu +OnDesktop Mouse3 :RootMenu + +# scroll on the desktop to change workspaces +OnDesktop Mouse4 :PrevWorkspace +OnDesktop Mouse5 :NextWorkspace + +# scroll on the toolbar to change current window +OnToolbar Mouse4 :PrevWindow {static groups} (iconhidden=no) +OnToolbar Mouse5 :NextWindow {static groups} (iconhidden=no) + +# alt + left/right click to move/resize a window +OnWindow Mod1 Mouse1 :MacroCmd {Raise} {Focus} {StartMoving} +OnWindowBorder Move1 :StartMoving + +OnWindow Mod1 Mouse3 :MacroCmd {Raise} {Focus} {StartResizing NearestCorner} +OnLeftGrip Move1 :StartResizing bottomleft +OnRightGrip Move1 :StartResizing bottomright + +# alt + middle click to lower the window +OnWindow Mod1 Mouse2 :Lower + +# control-click a window's titlebar and drag to attach windows +OnTitlebar Control Mouse1 :StartTabbing + +# double click on the titlebar to shade +OnTitlebar Double Mouse1 :Shade + +# left click on the titlebar to move the window +OnTitlebar Mouse1 :MacroCmd {Raise} {Focus} {ActivateTab} +OnTitlebar Move1 :StartMoving + +# middle click on the titlebar to lower +OnTitlebar Mouse2 :Lower + +# right click on the titlebar for a menu of options +OnTitlebar Mouse3 :WindowMenu + +# alt-tab +Mod1 Tab :NextWindow {groups} (workspace=[current]) +Mod1 Shift Tab :PrevWindow {groups} (workspace=[current]) + +# cycle through tabs in the current window +Mod4 Tab :NextTab +Mod4 Shift Tab :PrevTab + +# go to a specific tab in the current window +Control F1 :Tab 1 +Control F2 :Tab 2 +Control F3 :Tab 3 +Control F4 :Tab 4 +Control F5 :Tab 5 +Control F6 :Tab 6 +Control F7 :Tab 7 +Control F8 :Tab 8 +Control F9 :Tab 9 +Control F10 :Tab 10 +Control F11 :Tab 11 +Control F12 :Tab 12 + +# open a terminal +Mod1 F1 :Exec xterm + +# open a dialog to run programs +Mod1 F2 :Exec fbrun + +# volume settings, using common keycodes +# if these don't work, use xev to find out your real keycodes +176 :Exec amixer sset Master,0 5%+ +174 :Exec amixer sset Master,0 5%- +160 :Exec amixer sset Master,0 toggle + +# current window commands +Mod1 F4 :Close +Mod1 F5 :Kill +Mod1 F9 :Minimize +Mod1 F10 :Maximize +Mod1 F11 :Fullscreen + +# open the window menu +Mod1 space :WindowMenu + +# exit fluxbox +Control Mod1 Delete :Exit + +# change to previous/next workspace +Control Mod1 Left :PrevWorkspace +Control Mod1 Right :NextWorkspace + +# send the current window to previous/next workspace +Mod4 Left :SendToPrevWorkspace +Mod4 Right :SendToNextWorkspace + +# send the current window and follow it to previous/next workspace +Control Mod4 Left :TakeToPrevWorkspace +Control Mod4 Right :TakeToNextWorkspace + +# change to a specific workspace +Mod4 1 :Workspace 1 +Mod4 2 :Workspace 2 +Mod4 3 :Workspace 3 +Mod4 4 :Workspace 4 +Mod4 5 :Workspace 5 +Mod4 6 :Workspace 6 +Mod4 7 :Workspace 7 +Mod4 8 :Workspace 8 +Mod4 9 :Workspace 9 +Mod4 0 :Workspace 10 + +# send the current window to a specific workspace +Mod4 F1 :SendToWorkspace 1 +Mod4 F2 :SendToWorkspace 2 +Mod4 F3 :SendToWorkspace 3 +Mod4 F4 :SendToWorkspace 4 +Mod4 F5 :SendToWorkspace 5 +Mod4 F6 :SendToWorkspace 6 +Mod4 F7 :SendToWorkspace 7 +Mod4 F8 :SendToWorkspace 8 +Mod4 F9 :SendToWorkspace 9 +Mod4 F10 :SendToWorkspace 10 +Mod4 F11 :SendToWorkspace 11 +Mod4 F12 :SendToWorkspace 12 + +# send the current window and change to a specific workspace +Control Mod4 F1 :TakeToWorkspace 1 +Control Mod4 F2 :TakeToWorkspace 2 +Control Mod4 F3 :TakeToWorkspace 3 +Control Mod4 F4 :TakeToWorkspace 4 +Control Mod4 F5 :TakeToWorkspace 5 +Control Mod4 F6 :TakeToWorkspace 6 +Control Mod4 F7 :TakeToWorkspace 7 +Control Mod4 F8 :TakeToWorkspace 8 +Control Mod4 F9 :TakeToWorkspace 9 +Control Mod4 F10 :TakeToWorkspace 10 +Control Mod4 F11 :TakeToWorkspace 11 +Control Mod4 F12 :TakeToWorkspace 12
A .config/fluxbox/lastwallpaper

@@ -0,0 +1,2 @@

+fbsetroot|-foreground #404040 -background #535353 -gradient flatgradientelliptic|style|:1.0 +$full $full|/home/x1phosura/Pictures/wallpapers/bob-01-1200x1000.png||:0.0
A .config/fluxbox/menu

@@ -0,0 +1,177 @@

+# Generated by fluxbox-generate_menu +# +# If you read this it means you want to edit this file manually, so here +# are some useful tips: +# +# - You can add your own menu-entries to ~/.fluxbox/usermenu +# +# - If you miss apps please let me know and I will add them for the next +# release. +# +# - The -r option prevents removing of empty menu entries and lines which +# makes things much more readable. +# +# - To prevent any other app from overwriting your menu +# you can change the menu name in ~/.fluxbox/init to: +# session.menuFile: ~/.fluxbox/my-menu +[begin] (Fluxbox-1.3.7) +[encoding] {UTF-8} + [exec] (alacritty) {alacritty} + [exec] (firefox) {firefox} + [exec] (Run) {fbrun} +[submenu] (Terminals) + [exec] (xterm) {xterm} + [exec] (urxvt) {urxvt} + [exec] (urxvtc) {urxvtc} + [exec] (konsole) {konsole} +[end] +[submenu] (Net) +[submenu] (Browsers) + [exec] (firefox) {firefox} + [exec] (seamonkey) {seamonkey} + [exec] (links-graphic) {links -driver x fluxbox.org} + [exec] (konqueror) {kfmclient openProfile webbrowsing} + [exec] (links) {urxvt -e links fluxbox.org} + [exec] (lynx) {urxvt -e lynx fluxbox.org} +[end] +[submenu] (IM) + [exec] (pidgin) {pidgin} +[end] +[submenu] (News) + [exec] (pan) {pan} + [exec] (slrn) {urxvt -e slrn} + [exec] (tin) {urxvt -e tin} +[end] +[submenu] (IRC) + [exec] (konversation) {konversation} + [exec] (irssi) {urxvt -e irssi} + [exec] (ninja) {urxvt -e ninja} +[end] +[submenu] (FTP) + [exec] (gftp) {gftp} + [exec] (ncftp) {urxvt -e ncftp} + [exec] (ftp) {urxvt -e ftp} + [exec] (lftp) {urxvt -e lftp} +[end] +[submenu] (Analyzers) + [exec] (xnmap) {xnmap} + [exec] (nmapfe) {nmapfe} +[end] + [exec] (x3270) {x3270} + [exec] (wpa_gui) {wpa_gui} +[end] +[submenu] (Editors) + [exec] (gvim) {gvim} + [exec] (xedit) {xedit} + [exec] (kwrite) {kwrite} + [exec] (kate) {kate} + [exec] (emacs) {emacs} + [exec] (evim) {evim} + [exec] (nano) {urxvt -e nano} + [exec] (vim) {urxvt -e vim} + [exec] (vi) {urxvt -e vi} + [exec] (jed) {urxvt -e jed} + [exec] (joe) {urxvt -e joe} + [exec] (emacs-nw) {urxvt -e emacs -nw} +[end] +[submenu] (Education) + [exec] (gnuplot) {urxvt -e gnuplot} +[end] +[submenu] (File utils) + [exec] (konqueror) {kfmclient openProfile filemanagement} + [exec] (krusader) {krusader} + [exec] (krename) {krename} + [exec] (mc) {urxvt -e mc} +[end] +[submenu] (Multimedia) +[submenu] (Graphics) + [exec] (gimp) {gimp} + [exec] (xpaint) {xpaint} + [exec] (xscreensaver-demo) {xscreensaver-demo} + [exec] (xlock) {xlock} + [exec] (krita) {krita} + [exec] (Mesa gears) {gears} +[end] +[submenu] (Audio) + [exec] (xmms) {xmms} + [exec] (kmix) {kmix} + [exec] (easytag) {easytag} + [exec] (audacious) {audacious} + [exec] (alsamixer) {urxvt -e alsamixer} +[end] +[submenu] (Video) + [exec] (xine) {xine} + [exec] (gmplayer) {gmplayer} +[end] +[submenu] (X-utils) + [exec] (xfontsel) {xfontsel} + [exec] (xman) {xman} + [exec] (xload) {xload} + [exec] (xbiff) {xbiff} + [exec] (editres) {editres} + [exec] (viewres) {viewres} + [exec] (xclock) {xclock} + [exec] (xmag) {xmag} + [exec] (wmagnify) {wmagnify} + [exec] (gkrellm) {gkrellm} + [exec] (Reload .Xdefaults) {xrdb -load $HOME/.Xdefaults} +[end] +[end] +[submenu] (Office) + [exec] (xclock) {xclock} + [exec] (xcalc) {xcalc} + [exec] (kcalc) {kcalc} + [exec] (xpdf) {xpdf} + [exec] (gv) {gv} + [exec] (xfig) {xfig} +[end] +[submenu] (Games) + [exec] (knights) {knights} + [exec] (eboard) {eboard} + [exec] (xboard) {xboard} + [exec] (xsnow) {xsnow} + [exec] (xeyes) {xeyes} +[end] +[submenu] (System Tools) +[submenu] (Burning) + [exec] (k3b) {k3b} +[end] + [exec] (top) {urxvt -e top} + [exec] (htop) {urxvt -e htop} +[end] +[submenu] (Fluxbox menu) + [config] (Configure) +[submenu] (System Styles) {Choose a style...} + [stylesdir] (/usr/share/fluxbox/styles) +[end] +[submenu] (User Styles) {Choose a style...} + [stylesdir] (~/.fluxbox/styles) +[end] + [workspaces] (Workspace List) +[submenu] (Tools) + [exec] (Window name) {xprop WM_CLASS|cut -d \" -f 2|xmessage -file - -center} + [exec] (Screenshot - JPG) {import screenshot.jpg && display -resize 50% screenshot.jpg} + [exec] (Screenshot - PNG) {import screenshot.png && display -resize 50% screenshot.png} + [exec] (Run) {fbrun} + [exec] (Regen Menu) {fluxbox-generate_menu} +[end] +[submenu] (Window Managers) + [restart] (mwm) {mwm} + [restart] (twm) {twm} + [restart] (compiz) {compiz} + [restart] (fvwm) {fvwm} + [restart] (xfce4) {startxfce4} + [restart] (fvwm2) {startfvwm2} + [restart] (blackbox) {startblackbox} + [restart] (windowmaker) {wmaker} +[end] + [exec] (Lock screen) {xlock} + [commanddialog] (Fluxbox Command) + [reconfig] (Reload config) + [restart] (Restart) + [exec] (About) {(fluxbox -v; fluxbox -info | sed 1d) | xmessage -file - -center} + [separator] + [exit] (Exit) +[end] +[endencoding] +[end]
A .config/fluxbox/overlay

@@ -0,0 +1,3 @@

+! The following line will prevent styles from setting the background. +background: fullscreen +background.pixmap: /home/x1phosura/Pictures/wallpapers/bob-01-1200x1000.png
A .config/fluxbox/set-wallpaper.sh

@@ -0,0 +1,1 @@

+fbsetbg -f ~/Pictures/wallpapers/got-slack-1024x768.png
A .config/fluxbox/startup

@@ -0,0 +1,31 @@

+#!/bin/sh +# +# fluxbox startup-script: +# +# Lines starting with a '#' are ignored. + +# Change your keymap: +xmodmap "/home/x1phosura/.Xmodmap" + +# Applications you want to run with fluxbox. +# MAKE SURE THAT APPS THAT KEEP RUNNING HAVE AN ''&'' AT THE END. +# +# unclutter -idle 2 & +# wmnd & +# wmsmixer -w & +# idesk & + +# Start DBUS session bus: +if [ -z "$DBUS_SESSION_BUS_ADDRESS" ]; then + eval $(dbus-launch --sh-syntax --exit-with-session) +fi + +# And last but not least we start fluxbox. +# Because it is the last app you have to run it with ''exec'' before it. + +exec fluxbox +# or if you want to keep a log: +# exec fluxbox -log "/home/x1phosura/.fluxbox/log" + +fbsetbg -f /home/x1phosura/Pictures/wallpapers/bob-01-1200x1000.png +
A .config/fluxbox/windowmenu

@@ -0,0 +1,15 @@

+[begin] + [shade] + [stick] + [maximize] + [iconify] + [raise] + [lower] + [settitledialog] + [sendto] + [layer] + [alpha] + [extramenus] + [separator] + [close] +[end]
A .config/nano/nanorc

@@ -0,0 +1,75 @@

+ + ##################### + ## My nanorc ## + ##################### + +# Note: this file works on NANO VERSION > 5.0. If you aren't using the latest +# nano, you're uncool, and you should quit being uncool and get yourself a new +# nano. I mean, seriously, it's FREE, you have no excuse! + +# Cheat Sheet (bc I'm actually vim user lol) +# For more, see (https://www.nano-editor.org/dist/latest/cheatsheet.html) +# Read in-editor help screen: Ctrl+g (open help guide) +# Save current buffer: Ctrl+S (obviously I guess, idk, I'm dumb and used to :w) +# Select text: Ctrl+^ (select, then you can copy/cut, Ctrl+^ again to unselect) +# Copy/cut selected text: Alt+^ (copy), Ctrl+K (cut) +# Paste text: Ctrl+U +# Delete text: Ctrl+Del (delete right word), Ctrl+Shift+Del (delete left word) +# Delete text (continued): Alt+Del (delete current line) +# Undo/redo: Alt+U (undo), Alt+E (redo) +# Go to top/bottom of file: Alt+\ (top of file), Alt+/ (bottom of file) +# (Un)comment line: Alt+3 (comment or uncomment current line) +# Fun Fact: Some Emacs navigation shortcuts Ctrl+P/N/F/B/E/A) actually work! +# TODO: add more hints + + +## Editor appearance/interface +set linenumbers +set titlecolor magenta,black +set statuscolor magenta +set keycolor magenta,black +set functioncolor magenta +set numbercolor magenta +set indicator # AKA "scrollbar" +set guidestripe 80 # vertical bar on right +set stripecolor black,magenta +unset emptyline +# unset whitespacedisplay # this setting doesn't exist, which is REALLY DUMB! + + +## Editor behavior +set autoindent +set softwrap +set tabsize 8 +#set tabstospaces # will automatically replace TAB w/ spaces, disabled +set mouse +set nonewlines # I usually add a '\n' anyway, nano's not my babysitter + + +## Syntax highlighting +include "/usr/share/nano/asm.nanorc" +include "/usr/share/nano/c.nanorc" +include "/usr/share/nano/css.nanorc" +include "/usr/share/nano/default.nanorc" +include "/usr/share/nano/elisp.nanorc" +include "/usr/share/nano/go.nanorc" +include "/usr/share/nano/guile.nanorc" +include "/usr/share/nano/html.nanorc" +include "/usr/share/nano/java.nanorc" +include "/usr/share/nano/javascript.nanorc" +include "/usr/share/nano/json.nanorc" +include "/usr/share/nano/lua.nanorc" +include "/usr/share/nano/makefile.nanorc" +include "/usr/share/nano/markdown.nanorc" +include "/usr/share/nano/nanorc.nanorc" +include "/usr/share/nano/patch.nanorc" +include "/usr/share/nano/perl.nanorc" +include "/usr/share/nano/php.nanorc" +include "/usr/share/nano/puthon.nanorc" +include "/usr/share/nano/ruby.nanorc" +include "/usr/share/nano/rust.nanorc" +include "/usr/share/nano/sh.nanorc" +include "/usr/share/nano/sql.nanorc" +include "/usr/share/nano/tex.nanorc" +include "/usr/share/nano/xml.nanorc" +include "/usr/share/nano/extra/fortran.nanorc" # MEME ALERT!!!
A .config/neofetch/config.conf

@@ -0,0 +1,764 @@

+# See this wiki page for more info: +# https://github.com/dylanaraps/neofetch/wiki/Customizing-Info +print_info() { + info title + info underline + + info "OS" distro + info "Host" model + info "Kernel" kernel + info "Uptime" uptime + info "Packages" packages + info "Shell" shell + info "Resolution" resolution + info "DE" de + info "WM" wm + info "WM Theme" wm_theme + info "Theme" theme + info "Icons" icons + info "Terminal" term + info "Terminal Font" term_font + info "CPU" cpu + info "GPU" gpu + info "Memory" memory + + # info "GPU Driver" gpu_driver # Linux/macOS only + # info "CPU Usage" cpu_usage + # info "Disk" disk + # info "Battery" battery + # info "Font" font + # info "Song" song + # [[ "$player" ]] && prin "Music Player" "$player" + # info "Local IP" local_ip + # info "Public IP" public_ip + # info "Users" users + # info "Locale" locale # This only works on glibc systems. + + info cols +} + + +# Kernel + + +# Shorten the output of the kernel function. +# +# Default: 'on' +# Values: 'on', 'off' +# Flag: --kernel_shorthand +# Supports: Everything except *BSDs (except PacBSD and PC-BSD) +# +# Example: +# on: '4.8.9-1-ARCH' +# off: 'Linux 4.8.9-1-ARCH' +kernel_shorthand="on" + + +# Distro + + +# Shorten the output of the distro function +# +# Default: 'off' +# Values: 'on', 'tiny', 'off' +# Flag: --distro_shorthand +# Supports: Everything except Windows and Haiku +distro_shorthand="off" + +# Show/Hide OS Architecture. +# Show 'x86_64', 'x86' and etc in 'Distro:' output. +# +# Default: 'on' +# Values: 'on', 'off' +# Flag: --os_arch +# +# Example: +# on: 'Arch Linux x86_64' +# off: 'Arch Linux' +os_arch="on" + + +# Uptime + + +# Shorten the output of the uptime function +# +# Default: 'on' +# Values: 'on', 'tiny', 'off' +# Flag: --uptime_shorthand +# +# Example: +# on: '2 days, 10 hours, 3 mins' +# tiny: '2d 10h 3m' +# off: '2 days, 10 hours, 3 minutes' +uptime_shorthand="on" + + +# Memory + + +# Show memory pecentage in output. +# +# Default: 'off' +# Values: 'on', 'off' +# Flag: --memory_percent +# +# Example: +# on: '1801MiB / 7881MiB (22%)' +# off: '1801MiB / 7881MiB' +memory_percent="off" + + +# Packages + + +# Show/Hide Package Manager names. +# +# Default: 'tiny' +# Values: 'on', 'tiny' 'off' +# Flag: --package_managers +# +# Example: +# on: '998 (pacman), 8 (flatpak), 4 (snap)' +# tiny: '908 (pacman, flatpak, snap)' +# off: '908' +package_managers="on" + + +# Shell + + +# Show the path to $SHELL +# +# Default: 'off' +# Values: 'on', 'off' +# Flag: --shell_path +# +# Example: +# on: '/bin/bash' +# off: 'bash' +shell_path="off" + +# Show $SHELL version +# +# Default: 'on' +# Values: 'on', 'off' +# Flag: --shell_version +# +# Example: +# on: 'bash 4.4.5' +# off: 'bash' +shell_version="on" + + +# CPU + + +# CPU speed type +# +# Default: 'bios_limit' +# Values: 'scaling_cur_freq', 'scaling_min_freq', 'scaling_max_freq', 'bios_limit'. +# Flag: --speed_type +# Supports: Linux with 'cpufreq' +# NOTE: Any file in '/sys/devices/system/cpu/cpu0/cpufreq' can be used as a value. +speed_type="bios_limit" + +# CPU speed shorthand +# +# Default: 'off' +# Values: 'on', 'off'. +# Flag: --speed_shorthand +# NOTE: This flag is not supported in systems with CPU speed less than 1 GHz +# +# Example: +# on: 'i7-6500U (4) @ 3.1GHz' +# off: 'i7-6500U (4) @ 3.100GHz' +speed_shorthand="off" + +# Enable/Disable CPU brand in output. +# +# Default: 'on' +# Values: 'on', 'off' +# Flag: --cpu_brand +# +# Example: +# on: 'Intel i7-6500U' +# off: 'i7-6500U (4)' +cpu_brand="on" + +# CPU Speed +# Hide/Show CPU speed. +# +# Default: 'on' +# Values: 'on', 'off' +# Flag: --cpu_speed +# +# Example: +# on: 'Intel i7-6500U (4) @ 3.1GHz' +# off: 'Intel i7-6500U (4)' +cpu_speed="on" + +# CPU Cores +# Display CPU cores in output +# +# Default: 'logical' +# Values: 'logical', 'physical', 'off' +# Flag: --cpu_cores +# Support: 'physical' doesn't work on BSD. +# +# Example: +# logical: 'Intel i7-6500U (4) @ 3.1GHz' (All virtual cores) +# physical: 'Intel i7-6500U (2) @ 3.1GHz' (All physical cores) +# off: 'Intel i7-6500U @ 3.1GHz' +cpu_cores="logical" + +# CPU Temperature +# Hide/Show CPU temperature. +# Note the temperature is added to the regular CPU function. +# +# Default: 'off' +# Values: 'C', 'F', 'off' +# Flag: --cpu_temp +# Supports: Linux, BSD +# NOTE: For FreeBSD and NetBSD-based systems, you'll need to enable +# coretemp kernel module. This only supports newer Intel processors. +# +# Example: +# C: 'Intel i7-6500U (4) @ 3.1GHz [27.2°C]' +# F: 'Intel i7-6500U (4) @ 3.1GHz [82.0°F]' +# off: 'Intel i7-6500U (4) @ 3.1GHz' +cpu_temp="off" + + +# GPU + + +# Enable/Disable GPU Brand +# +# Default: 'on' +# Values: 'on', 'off' +# Flag: --gpu_brand +# +# Example: +# on: 'AMD HD 7950' +# off: 'HD 7950' +gpu_brand="on" + +# Which GPU to display +# +# Default: 'all' +# Values: 'all', 'dedicated', 'integrated' +# Flag: --gpu_type +# Supports: Linux +# +# Example: +# all: +# GPU1: AMD HD 7950 +# GPU2: Intel Integrated Graphics +# +# dedicated: +# GPU1: AMD HD 7950 +# +# integrated: +# GPU1: Intel Integrated Graphics +gpu_type="all" + + +# Resolution + + +# Display refresh rate next to each monitor +# Default: 'off' +# Values: 'on', 'off' +# Flag: --refresh_rate +# Supports: Doesn't work on Windows. +# +# Example: +# on: '1920x1080 @ 60Hz' +# off: '1920x1080' +refresh_rate="off" + + +# Gtk Theme / Icons / Font + + +# Shorten output of GTK Theme / Icons / Font +# +# Default: 'off' +# Values: 'on', 'off' +# Flag: --gtk_shorthand +# +# Example: +# on: 'Numix, Adwaita' +# off: 'Numix [GTK2], Adwaita [GTK3]' +gtk_shorthand="off" + + +# Enable/Disable gtk2 Theme / Icons / Font +# +# Default: 'on' +# Values: 'on', 'off' +# Flag: --gtk2 +# +# Example: +# on: 'Numix [GTK2], Adwaita [GTK3]' +# off: 'Adwaita [GTK3]' +gtk2="on" + +# Enable/Disable gtk3 Theme / Icons / Font +# +# Default: 'on' +# Values: 'on', 'off' +# Flag: --gtk3 +# +# Example: +# on: 'Numix [GTK2], Adwaita [GTK3]' +# off: 'Numix [GTK2]' +gtk3="on" + + +# IP Address + + +# Website to ping for the public IP +# +# Default: 'http://ident.me' +# Values: 'url' +# Flag: --ip_host +public_ip_host="http://ident.me" + +# Public IP timeout. +# +# Default: '2' +# Values: 'int' +# Flag: --ip_timeout +public_ip_timeout=2 + + +# Disk + + +# Which disks to display. +# The values can be any /dev/sdXX, mount point or directory. +# NOTE: By default we only show the disk info for '/'. +# +# Default: '/' +# Values: '/', '/dev/sdXX', '/path/to/drive'. +# Flag: --disk_show +# +# Example: +# disk_show=('/' '/dev/sdb1'): +# 'Disk (/): 74G / 118G (66%)' +# 'Disk (/mnt/Videos): 823G / 893G (93%)' +# +# disk_show=('/'): +# 'Disk (/): 74G / 118G (66%)' +# +disk_show=('/') + +# Disk subtitle. +# What to append to the Disk subtitle. +# +# Default: 'mount' +# Values: 'mount', 'name', 'dir' +# Flag: --disk_subtitle +# +# Example: +# name: 'Disk (/dev/sda1): 74G / 118G (66%)' +# 'Disk (/dev/sdb2): 74G / 118G (66%)' +# +# mount: 'Disk (/): 74G / 118G (66%)' +# 'Disk (/mnt/Local Disk): 74G / 118G (66%)' +# 'Disk (/mnt/Videos): 74G / 118G (66%)' +# +# dir: 'Disk (/): 74G / 118G (66%)' +# 'Disk (Local Disk): 74G / 118G (66%)' +# 'Disk (Videos): 74G / 118G (66%)' +disk_subtitle="mount" + + +# Song + + +# Manually specify a music player. +# +# Default: 'auto' +# Values: 'auto', 'player-name' +# Flag: --music_player +# +# Available values for 'player-name': +# +# amarok +# audacious +# banshee +# bluemindo +# clementine +# cmus +# deadbeef +# deepin-music +# dragon +# elisa +# exaile +# gnome-music +# gmusicbrowser +# gogglesmm +# guayadeque +# iTunes +# juk +# lollypop +# mocp +# mopidy +# mpd +# netease-cloud-music +# pogo +# pragha +# qmmp +# quodlibet +# rhythmbox +# sayonara +# smplayer +# spotify +# strawberry +# tomahawk +# vlc +# xmms2d +# xnoise +# yarock +music_player="auto" + +# Format to display song information. +# +# Default: '%artist% - %album% - %title%' +# Values: '%artist%', '%album%', '%title%' +# Flag: --song_format +# +# Example: +# default: 'Song: Jet - Get Born - Sgt Major' +song_format="%artist% - %album% - %title%" + +# Print the Artist, Album and Title on separate lines +# +# Default: 'off' +# Values: 'on', 'off' +# Flag: --song_shorthand +# +# Example: +# on: 'Artist: The Fratellis' +# 'Album: Costello Music' +# 'Song: Chelsea Dagger' +# +# off: 'Song: The Fratellis - Costello Music - Chelsea Dagger' +song_shorthand="off" + +# 'mpc' arguments (specify a host, password etc). +# +# Default: '' +# Example: mpc_args=(-h HOST -P PASSWORD) +mpc_args=() + + +# Text Colors + + +# Text Colors +# +# Default: 'distro' +# Values: 'distro', 'num' 'num' 'num' 'num' 'num' 'num' +# Flag: --colors +# +# Each number represents a different part of the text in +# this order: 'title', '@', 'underline', 'subtitle', 'colon', 'info' +# +# Example: +# colors=(distro) - Text is colored based on Distro colors. +# colors=(4 6 1 8 8 6) - Text is colored in the order above. +colors=(distro) + + +# Text Options + + +# Toggle bold text +# +# Default: 'on' +# Values: 'on', 'off' +# Flag: --bold +bold="on" + +# Enable/Disable Underline +# +# Default: 'on' +# Values: 'on', 'off' +# Flag: --underline +underline_enabled="on" + +# Underline character +# +# Default: '-' +# Values: 'string' +# Flag: --underline_char +underline_char="-" + + +# Info Separator +# Replace the default separator with the specified string. +# +# Default: ':' +# Flag: --separator +# +# Example: +# separator="->": 'Shell-> bash' +# separator=" =": 'WM = dwm' +separator=":" + + +# Color Blocks + + +# Color block range +# The range of colors to print. +# +# Default: '0', '15' +# Values: 'num' +# Flag: --block_range +# +# Example: +# +# Display colors 0-7 in the blocks. (8 colors) +# neofetch --block_range 0 7 +# +# Display colors 0-15 in the blocks. (16 colors) +# neofetch --block_range 0 15 +block_range=(0 15) + +# Toggle color blocks +# +# Default: 'on' +# Values: 'on', 'off' +# Flag: --color_blocks +color_blocks="on" + +# Color block width in spaces +# +# Default: '3' +# Values: 'num' +# Flag: --block_width +block_width=3 + +# Color block height in lines +# +# Default: '1' +# Values: 'num' +# Flag: --block_height +block_height=1 + + +# Progress Bars + + +# Bar characters +# +# Default: '-', '=' +# Values: 'string', 'string' +# Flag: --bar_char +# +# Example: +# neofetch --bar_char 'elapsed' 'total' +# neofetch --bar_char '-' '=' +bar_char_elapsed="-" +bar_char_total="=" + +# Toggle Bar border +# +# Default: 'on' +# Values: 'on', 'off' +# Flag: --bar_border +bar_border="on" + +# Progress bar length in spaces +# Number of chars long to make the progress bars. +# +# Default: '15' +# Values: 'num' +# Flag: --bar_length +bar_length=15 + +# Progress bar colors +# When set to distro, uses your distro's logo colors. +# +# Default: 'distro', 'distro' +# Values: 'distro', 'num' +# Flag: --bar_colors +# +# Example: +# neofetch --bar_colors 3 4 +# neofetch --bar_colors distro 5 +bar_color_elapsed="distro" +bar_color_total="distro" + + +# Info display +# Display a bar with the info. +# +# Default: 'off' +# Values: 'bar', 'infobar', 'barinfo', 'off' +# Flags: --cpu_display +# --memory_display +# --battery_display +# --disk_display +# +# Example: +# bar: '[---=======]' +# infobar: 'info [---=======]' +# barinfo: '[---=======] info' +# off: 'info' +cpu_display="off" +memory_display="off" +battery_display="off" +disk_display="off" + + +# Backend Settings + + +# Image backend. +# +# Default: 'ascii' +# Values: 'ascii', 'caca', 'chafa', 'jp2a', 'iterm2', 'off', +# 'termpix', 'pixterm', 'tycat', 'w3m', 'kitty' +# Flag: --backend +image_backend="ascii" + +# Image Source +# +# Which image or ascii file to display. +# +# Default: 'auto' +# Values: 'auto', 'ascii', 'wallpaper', '/path/to/img', '/path/to/ascii', '/path/to/dir/' +# 'command output (neofetch --ascii "$(fortune | cowsay -W 30)")' +# Flag: --source +# +# NOTE: 'auto' will pick the best image source for whatever image backend is used. +# In ascii mode, distro ascii art will be used and in an image mode, your +# wallpaper will be used. +image_source="auto" + + +# Ascii Options + + +# Ascii distro +# Which distro's ascii art to display. +# +# Default: 'auto' +# Values: 'auto', 'distro_name' +# Flag: --ascii_distro +# +# NOTE: Arch and Ubuntu have 'old' logo variants. +# Change this to 'arch_old' or 'ubuntu_old' to use the old logos. +# NOTE: Ubuntu has flavor variants. +# Change this to 'Lubuntu', 'Xubuntu', 'Ubuntu-GNOME' or 'Ubuntu-Budgie' to use the flavors. +# NOTE: Arch, Crux and Gentoo have a smaller logo variant. +# Change this to 'arch_small', 'crux_small' or 'gentoo_small' to use the small logos. +ascii_distro="auto" + +# Ascii Colors +# +# Default: 'distro' +# Values: 'distro', 'num' 'num' 'num' 'num' 'num' 'num' +# Flag: --ascii_colors +# +# Example: +# ascii_colors=(distro) - Ascii is colored based on Distro colors. +# ascii_colors=(4 6 1 8 8 6) - Ascii is colored using these colors. +ascii_colors=(distro) + +# Bold ascii logo +# Whether or not to bold the ascii logo. +# +# Default: 'on' +# Values: 'on', 'off' +# Flag: --ascii_bold +ascii_bold="on" + + +# Image Options + + +# Image loop +# Setting this to on will make neofetch redraw the image constantly until +# Ctrl+C is pressed. This fixes display issues in some terminal emulators. +# +# Default: 'off' +# Values: 'on', 'off' +# Flag: --loop +image_loop="off" + +# Thumbnail directory +# +# Default: '~/.cache/thumbnails/neofetch' +# Values: 'dir' +thumbnail_dir="${XDG_CACHE_HOME:-${HOME}/.cache}/thumbnails/neofetch" + +# Crop mode +# +# Default: 'normal' +# Values: 'normal', 'fit', 'fill' +# Flag: --crop_mode +# +# See this wiki page to learn about the fit and fill options. +# https://github.com/dylanaraps/neofetch/wiki/What-is-Waifu-Crop%3F +crop_mode="normal" + +# Crop offset +# Note: Only affects 'normal' crop mode. +# +# Default: 'center' +# Values: 'northwest', 'north', 'northeast', 'west', 'center' +# 'east', 'southwest', 'south', 'southeast' +# Flag: --crop_offset +crop_offset="center" + +# Image size +# The image is half the terminal width by default. +# +# Default: 'auto' +# Values: 'auto', '00px', '00%', 'none' +# Flags: --image_size +# --size +image_size="auto" + +# Gap between image and text +# +# Default: '3' +# Values: 'num', '-num' +# Flag: --gap +gap=3 + +# Image offsets +# Only works with the w3m backend. +# +# Default: '0' +# Values: 'px' +# Flags: --xoffset +# --yoffset +yoffset=0 +xoffset=0 + +# Image background color +# Only works with the w3m backend. +# +# Default: '' +# Values: 'color', 'blue' +# Flag: --bg_color +background_color= + + +# Misc Options + +# Stdout mode +# Turn off all colors and disables image backend (ASCII/Image). +# Useful for piping into another command. +# Default: 'off' +# Values: 'on', 'off' +stdout="off"
A .config/radare2/radare2rc

@@ -0,0 +1,13 @@

+ +# x1phosura's radare2rc + + +# Show comments at right of disassembly if they fit in screen +e asm.cmt.right=true + +# Solarized theme +eco pink + +# Use UTF-8 to show cool arrows that do not look like crap :) +e scr.utf8 = true +
A .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<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. + """:my_edit <filename> + + 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<ENTER>". + 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 <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()
A .config/ranger/commands_full.py

@@ -0,0 +1,1769 @@

+# -*- 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 ~/.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 file ~/.config/ranger/commands.py. +# It has the same syntax as this file. In fact, you can just copy this +# file there with `ranger --copy-config=commands' and make your modifications. +# 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 <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 +# 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 <newcommand> <oldcommand> + + 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 <newcommand> <oldcommand>', bad=True) + return + + 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> + + The cd command changes the directory. + 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 <command1>; <command2>; ... + + Calls multiple commands at once, separated by semicolons. + """ + + def execute(self): + if not self.rest(1).strip(): + self.fm.notify('Syntax: chain <command1>; <command2>; ...', 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 <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, _, 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, tabnum): # pylint: disable=too-many-return-statements + 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 sorted(self.firstpart + setting for setting in settings + if setting.startswith(name)) + if not value: + value_completers = { + "colorscheme": + # Cycle through colorschemes when name, but no value is specified + lambda: sorted(self.firstpart + colorscheme for colorscheme + in get_all_colorschemes(self.fm)), + + "column_ratios": + lambda: self.firstpart + ",".join(map(str, settings[name])), + } + + def default_value_completer(): + return self.firstpart + str(settings[name]) + + return value_completers.get(name, default_value_completer)() + if bool in settings.types_of(name): + if 'true'.startswith(value.lower()): + return self.firstpart + 'True' + if 'false'.startswith(value.lower()): + return self.firstpart + 'False' + # Tab complete colorscheme values if incomplete value is present + if name == "colorscheme": + return sorted(self.firstpart + colorscheme for colorscheme + in get_all_colorschemes(self.fm) if colorscheme.startswith(value)) + return None + + +class setlocal(set_): + """:setlocal path=<regular expression> <option name>=<python expression> + + Gives an option a new value. + """ + PATH_RE_DQUOTED = re.compile(r'^setlocal\s+path="(.*?)"') + PATH_RE_SQUOTED = re.compile(r"^setlocal\s+path='(.*?)'") + PATH_RE_UNQUOTED = re.compile(r'^path=(.*?)$') + + def _re_shift(self, match): + if not match: + return None + path = os.path.expanduser(match.group(1)) + for _ in range(len(path.split())): + self.shift() + return path + + def execute(self): + path = self._re_shift(self.PATH_RE_DQUOTED.match(self.line)) + if path is None: + path = self._re_shift(self.PATH_RE_SQUOTED.match(self.line)) + if path is None: + path = self._re_shift(self.PATH_RE_UNQUOTED.match(self.arg(1))) + if path is None and self.fm.thisdir: + path = self.fm.thisdir.path + if not path: + return + + name, value, _ = self.parse_setting_line() + self.fm.set_option_from_string(name, value, localpath=path) + + +class setintag(set_): + """:setintag <tag or tags> <option name>=<option value> + + Sets an option for directories that are tagged with a specific tag. + """ + + def execute(self): + tags = self.arg(1) + self.shift() + name, value, _ = self.parse_setting_line() + self.fm.set_option_from_string(name, value, tags=tags) + + +class default_linemode(Command): + + def execute(self): + from ranger.container.fsobject import FileSystemObject + + if len(self.args) < 2: + self.fm.notify( + "Usage: default_linemode [path=<regexp> | tag=<tag(s)>] <linemode>", bad=True) + + # Extract options like "path=..." or "tag=..." from the command line + arg1 = self.arg(1) + method = "always" + argument = None + if arg1.startswith("path="): + method = "path" + argument = re.compile(arg1[5:]) + self.shift() + elif arg1.startswith("tag="): + method = "tag" + argument = arg1[4:] + self.shift() + + # Extract and validate the line mode from the command line + lmode = self.rest(1) + if lmode not in FileSystemObject.linemode_dict: + self.fm.notify( + "Invalid linemode: %s; should be %s" % ( + lmode, "/".join(FileSystemObject.linemode_dict)), + bad=True, + ) + + # Add the prepared entry to the fm.default_linemodes + entry = [method, argument, lmode] + self.fm.default_linemodes.appendleft(entry) + + # Redraw the columns + if self.fm.ui.browser: + for col in self.fm.ui.browser.columns: + col.need_redraw = True + + def tab(self, tabnum): + return (self.arg(0) + " " + lmode + for lmode in self.fm.thisfile.linemode_dict.keys() + if lmode.startswith(self.arg(1))) + + +class quit(Command): # pylint: disable=redefined-builtin + """:quit + + Closes the current tab, if there's only one tab. + Otherwise quits if there are no tasks in progress. + """ + def _exit_no_work(self): + if self.fm.loader.has_work(): + self.fm.notify('Not quitting: Tasks in progress: Use `quit!` to force quit') + else: + self.fm.exit() + + def execute(self): + if len(self.fm.tabs) >= 2: + self.fm.tab_close() + else: + self._exit_no_work() + + +class quit_bang(Command): + """:quit! + + Closes the current tab, if there's only one tab. + Otherwise force quits immediately. + """ + name = 'quit!' + allow_abbrev = False + + def execute(self): + if len(self.fm.tabs) >= 2: + self.fm.tab_close() + else: + self.fm.exit() + + +class quitall(Command): + """:quitall + + Quits if there are no tasks in progress. + """ + def _exit_no_work(self): + if self.fm.loader.has_work(): + self.fm.notify('Not quitting: Tasks in progress: Use `quitall!` to force quit') + else: + self.fm.exit() + + def execute(self): + self._exit_no_work() + + +class quitall_bang(Command): + """:quitall! + + Force quits immediately. + """ + name = 'quitall!' + allow_abbrev = False + + def execute(self): + self.fm.exit() + + +class terminal(Command): + """:terminal + + Spawns an "x-terminal-emulator" starting in the current directory. + """ + + def execute(self): + from ranger.ext.get_executables import get_term + self.fm.run(get_term(), flags='f') + + +class delete(Command): + """:delete + + 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, + use the "current file" (where the cursor is) + + When attempting to delete non-empty directories or multiple + marked files, it will require a confirmation. + """ + + allow_abbrev = False + escape_macros_for_shell = True + + def execute(self): + import shlex + from functools import partial + + def is_directory_with_files(path): + return os.path.isdir(path) and not os.path.islink(path) and len(os.listdir(path)) > 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 + tfile = self.fm.thisfile + if not cwd or not tfile: + 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(tfile.path)) + + confirm = self.fm.settings.confirm_on_delete + if confirm != 'never' and (confirm != 'multiple' or many_files): + self.fm.ui.console.ask( + "Confirm deletion of: %s (y/N)" % ', '.join(files), + partial(self._question_callback, files), + ('n', 'N', 'y', 'Y'), + ) + else: + # no need for a confirmation, just delete + self.fm.delete(files) + + def tab(self, tabnum): + return self._tab_directory_content() + + def _question_callback(self, files, answer): + if answer == 'y' or answer == 'Y': + self.fm.delete(files) + + +class jump_non(Command): + """:jump_non [-FLAGS...] + + Jumps to first non-directory if highlighted file is a directory and vice versa. + + Flags: + -r Jump in reverse order + -w Wrap around if reaching end of filelist + """ + def __init__(self, *args, **kwargs): + super(jump_non, self).__init__(*args, **kwargs) + + flags, _ = self.parse_flags() + self._flag_reverse = 'r' in flags + self._flag_wrap = 'w' in flags + + @staticmethod + def _non(fobj, is_directory): + return fobj.is_directory if not is_directory else not fobj.is_directory + + def execute(self): + tfile = self.fm.thisfile + passed = False + found_before = None + found_after = None + for fobj in self.fm.thisdir.files[::-1] if self._flag_reverse else self.fm.thisdir.files: + if fobj.path == tfile.path: + passed = True + continue + + if passed: + if self._non(fobj, tfile.is_directory): + found_after = fobj.path + break + elif not found_before and self._non(fobj, tfile.is_directory): + found_before = fobj.path + + if found_after: + self.fm.select_file(found_after) + elif self._flag_wrap and found_before: + self.fm.select_file(found_before) + + +class mark_tag(Command): + """:mark_tag [<tags>] + + Mark all tags that are tagged with either of the given tags. + When leaving out the tag argument, all tagged files are marked. + """ + do_mark = True + + def execute(self): + cwd = self.fm.thisdir + tags = self.rest(1).replace(" ", "") + if not self.fm.tags or not cwd.files: + return + for fileobj in cwd.files: + try: + tag = self.fm.tags.tags[fileobj.realpath] + except KeyError: + continue + if not tags or tag in tags: + cwd.mark_item(fileobj, val=self.do_mark) + self.fm.ui.status.need_redraw = True + self.fm.ui.need_redraw = True + + +class console(Command): + """:console <command> + + Open the console with the given command. + """ + + def execute(self): + position = None + if self.arg(1)[0:2] == '-p': + try: + position = int(self.arg(1)[2:]) + except ValueError: + pass + else: + self.shift() + self.fm.open_console(self.rest(1), position=position) + + +class load_copy_buffer(Command): + """:load_copy_buffer + + Load the copy buffer from datadir/copy_buffer + """ + copy_buffer_filename = 'copy_buffer' + + def execute(self): + import sys + from ranger.container.file import File + from os.path import exists + fname = self.fm.datapath(self.copy_buffer_filename) + unreadable = IOError if sys.version_info[0] < 3 else OSError + try: + fobj = open(fname, 'r') + except unreadable: + return self.fm.notify( + "Cannot open %s" % (fname or self.copy_buffer_filename), bad=True) + + self.fm.copy_buffer = set(File(g) + for g in fobj.read().split("\n") if exists(g)) + fobj.close() + self.fm.ui.redraw_main_column() + return None + + +class save_copy_buffer(Command): + """:save_copy_buffer + + Save the copy buffer to datadir/copy_buffer + """ + copy_buffer_filename = 'copy_buffer' + + def execute(self): + import sys + fname = None + fname = self.fm.datapath(self.copy_buffer_filename) + unwritable = IOError if sys.version_info[0] < 3 else OSError + try: + fobj = open(fname, 'w') + except unwritable: + return self.fm.notify("Cannot open %s" % + (fname or self.copy_buffer_filename), bad=True) + fobj.write("\n".join(fobj.path for fobj in self.fm.copy_buffer)) + fobj.close() + return None + + +class unmark_tag(mark_tag): + """:unmark_tag [<tags>] + + Unmark all tags that are tagged with either of the given tags. + When leaving out the tag argument, all tagged files are unmarked. + """ + do_mark = False + + +class mkdir(Command): + """:mkdir <dirname> + + Creates a directory with the name <dirname>. + """ + + def execute(self): + from os.path import join, expanduser, lexists + from os import makedirs + + dirname = join(self.fm.thisdir.path, expanduser(self.rest(1))) + if not lexists(dirname): + makedirs(dirname) + else: + self.fm.notify("file/directory exists!", bad=True) + + def tab(self, tabnum): + return self._tab_directory_content() + + +class touch(Command): + """:touch <fname> + + Creates a file with the name <fname>. + """ + + def execute(self): + from os.path import join, expanduser, lexists + + fname = join(self.fm.thisdir.path, expanduser(self.rest(1))) + if not lexists(fname): + open(fname, 'a').close() + else: + self.fm.notify("file/directory exists!", bad=True) + + def tab(self, tabnum): + return self._tab_directory_content() + + +class edit(Command): + """:edit <filename> + + Opens the specified file in vim + """ + + def execute(self): + if not self.arg(1): + self.fm.edit_file(self.fm.thisfile.path) + else: + self.fm.edit_file(self.rest(1)) + + def tab(self, tabnum): + return self._tab_directory_content() + + +class eval_(Command): + """:eval [-q] <python code> + + Evaluates the python code. + `fm' is a reference to the FM instance. + To display text, use the function `p'. + + Examples: + :eval fm + :eval len(fm.directories) + :eval p("Hello World!") + """ + name = 'eval' + resolve_macros = False + + def execute(self): + # The import is needed so eval() can access the ranger module + import ranger # NOQA pylint: disable=unused-import,unused-variable + if self.arg(1) == '-q': + code = self.rest(2) + quiet = True + else: + code = self.rest(1) + quiet = False + global cmd, fm, p, quantifier # pylint: disable=invalid-name,global-variable-undefined + fm = self.fm + cmd = self.fm.execute_console + p = fm.notify + quantifier = self.quantifier + try: + try: + result = eval(code) # pylint: disable=eval-used + except SyntaxError: + exec(code) # pylint: disable=exec-used + else: + if result and not quiet: + p(result) + except Exception as err: # pylint: disable=broad-except + fm.notify("The error `%s` was caused by evaluating the " + "following code: `%s`" % (err, code), bad=True) + + +class rename(Command): + """:rename <newname> + + Changes the name of the currently highlighted file to <newname> + """ + + def execute(self): + from ranger.container.file import File + from os import access + + new_name = self.rest(1) + + if not new_name: + return self.fm.notify('Syntax: rename <newname>', bad=True) + + if new_name == self.fm.thisfile.relative_path: + return None + + if access(new_name, os.F_OK): + return self.fm.notify("Can't rename: file already exists!", bad=True) + + if self.fm.rename(self.fm.thisfile, new_name): + file_new = File(new_name) + self.fm.bookmarks.update_path(self.fm.thisfile.path, file_new) + self.fm.tags.update_path(self.fm.thisfile.path, file_new.path) + self.fm.thisdir.pointed_obj = file_new + self.fm.thisfile = file_new + + return None + + def tab(self, tabnum): + return self._tab_directory_content() + + +class rename_append(Command): + """:rename_append [-FLAGS...] + + Opens the console with ":rename <current file>" with the cursor positioned + before the file extension. + + Flags: + -a Position before all extensions + -r Remove everything before extensions + """ + def __init__(self, *args, **kwargs): + super(rename_append, self).__init__(*args, **kwargs) + + flags, _ = self.parse_flags() + self._flag_ext_all = 'a' in flags + self._flag_remove = 'r' in flags + + def execute(self): + from ranger import MACRO_DELIMITER, MACRO_DELIMITER_ESC + + tfile = self.fm.thisfile + relpath = tfile.relative_path.replace(MACRO_DELIMITER, MACRO_DELIMITER_ESC) + basename = tfile.basename.replace(MACRO_DELIMITER, MACRO_DELIMITER_ESC) + + if basename.find('.') <= 0: + self.fm.open_console('rename ' + relpath) + return + + if self._flag_ext_all: + pos_ext = re.search(r'[^.]+', basename).end(0) + else: + pos_ext = basename.rindex('.') + pos = len(relpath) - len(basename) + pos_ext + + if self._flag_remove: + relpath = relpath[:-len(basename)] + basename[pos_ext:] + pos -= pos_ext + + self.fm.open_console('rename ' + relpath, position=(7 + pos)) + + +class chmod(Command): + """:chmod <octal number> + + Sets the permissions of the selection to the octal number. + + The octal number is between 0 and 777. The digits specify the + permissions for the user, the group and others. + + A 1 permits execution, a 2 permits writing, a 4 permits reading. + Add those numbers to combine them. So a 7 permits everything. + """ + + def execute(self): + mode_str = self.rest(1) + if not mode_str: + if not self.quantifier: + self.fm.notify("Syntax: chmod <octal number>", bad=True) + return + mode_str = str(self.quantifier) + + try: + mode = int(mode_str, 8) + if mode < 0 or mode > 0o777: + raise ValueError + except ValueError: + self.fm.notify("Need an octal number between 0 and 777!", bad=True) + return + + for fobj in self.fm.thistab.get_selection(): + try: + os.chmod(fobj.path, mode) + except OSError as ex: + self.fm.notify(ex) + + # reloading directory. maybe its better to reload the selected + # files only. + self.fm.thisdir.content_outdated = True + + +class bulkrename(Command): + """:bulkrename + + This command opens a list of selected files in an external editor. + After you edit and save the file, it will generate a shell script + which does bulk renaming according to the changes you did in the file. + + This shell script is opened in an editor for you to review. + After you close it, it will be executed. + """ + + def execute(self): # pylint: disable=too-many-locals,too-many-statements + import sys + import tempfile + from ranger.container.file import File + from ranger.ext.shell_escape import shell_escape as esc + py3 = sys.version_info[0] >= 3 + + # Create and edit the file list + filenames = [f.relative_path for f in self.fm.thistab.get_selection()] + listfile = tempfile.NamedTemporaryFile(delete=False) + listpath = listfile.name + + if py3: + listfile.write("\n".join(filenames).encode("utf-8")) + else: + listfile.write("\n".join(filenames)) + listfile.close() + self.fm.execute_file([File(listpath)], app='editor') + listfile = open(listpath, 'r') + new_filenames = listfile.read().split("\n") + listfile.close() + os.unlink(listpath) + if all(a == b for a, b in zip(filenames, new_filenames)): + self.fm.notify("No renaming to be done!") + return + + # Generate script + cmdfile = tempfile.NamedTemporaryFile() + 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)) + for old, new in zip(filenames, new_filenames) if old != new) + script_content = "".join(script_lines) + if py3: + cmdfile.write(script_content.encode("utf-8")) + else: + cmdfile.write(script_content) + cmdfile.flush() + + # Open the script and let the user review it, then check if the script + # was modified by the user + self.fm.execute_file([File(cmdfile.name)], app='editor') + cmdfile.seek(0) + script_was_edited = (script_content != cmdfile.read()) + + # Do the renaming + self.fm.run(['/bin/sh', cmdfile.name], flags='w') + cmdfile.close() + + # Retag the files, but only if the script wasn't changed during review, + # because only then we know which are the source and destination files. + if not script_was_edited: + tags_changed = False + for old, new in zip(filenames, new_filenames): + if old != new: + oldpath = self.fm.thisdir.path + '/' + old + newpath = self.fm.thisdir.path + '/' + new + if oldpath in self.fm.tags: + old_tag = self.fm.tags.tags[oldpath] + self.fm.tags.remove(oldpath) + self.fm.tags.tags[newpath] = old_tag + tags_changed = True + if tags_changed: + self.fm.tags.dump() + else: + fm.notify("files have not been retagged") + + +class relink(Command): + """:relink <newpath> + + Changes the linked path of the currently highlighted symlink to <newpath> + """ + + def execute(self): + new_path = self.rest(1) + tfile = self.fm.thisfile + + if not new_path: + return self.fm.notify('Syntax: relink <newpath>', bad=True) + + if not tfile.is_link: + return self.fm.notify('%s is not a symlink!' % tfile.relative_path, bad=True) + + if new_path == os.readlink(tfile.path): + return None + + try: + os.remove(tfile.path) + os.symlink(new_path, tfile.path) + except OSError as err: + self.fm.notify(err) + + self.fm.reset() + self.fm.thisdir.pointed_obj = tfile + self.fm.thisfile = tfile + + return None + + def tab(self, tabnum): + if not self.rest(1): + return self.line + os.readlink(self.fm.thisfile.path) + return self._tab_directory_content() + + +class help_(Command): + """:help + + Display ranger's manual page. + """ + name = 'help' + + def execute(self): + def callback(answer): + if answer == "q": + return + elif answer == "m": + self.fm.display_help() + elif answer == "c": + self.fm.dump_commands() + elif answer == "k": + self.fm.dump_keybindings() + elif answer == "s": + self.fm.dump_settings() + + self.fm.ui.console.ask( + "View [m]an page, [k]ey bindings, [c]ommands or [s]ettings? (press q to abort)", + callback, + list("mqkcs") + ) + + +class copymap(Command): + """:copymap <keys> <newkeys1> [<newkeys2>...] + + Copies a "browser" keybinding from <keys> to <newkeys> + """ + context = 'browser' + + def execute(self): + if not self.arg(1) or not self.arg(2): + return self.fm.notify("Not enough arguments", bad=True) + + for arg in self.args[2:]: + self.fm.ui.keymaps.copy(self.context, self.arg(1), arg) + + return None + + +class copypmap(copymap): + """:copypmap <keys> <newkeys1> [<newkeys2>...] + + Copies a "pager" keybinding from <keys> to <newkeys> + """ + context = 'pager' + + +class copycmap(copymap): + """:copycmap <keys> <newkeys1> [<newkeys2>...] + + Copies a "console" keybinding from <keys> to <newkeys> + """ + context = 'console' + + +class copytmap(copymap): + """:copycmap <keys> <newkeys1> [<newkeys2>...] + + Copies a "taskview" keybinding from <keys> to <newkeys> + """ + context = 'taskview' + + +class unmap(Command): + """:unmap <keys> [<keys2>, ...] + + Remove the given "browser" mappings + """ + context = 'browser' + + def execute(self): + for arg in self.args[1:]: + self.fm.ui.keymaps.unbind(self.context, arg) + + +class cunmap(unmap): + """:cunmap <keys> [<keys2>, ...] + + Remove the given "console" mappings + """ + context = 'browser' + + +class punmap(unmap): + """:punmap <keys> [<keys2>, ...] + + Remove the given "pager" mappings + """ + context = 'pager' + + +class tunmap(unmap): + """:tunmap <keys> [<keys2>, ...] + + Remove the given "taskview" mappings + """ + context = 'taskview' + + +class map_(Command): + """:map <keysequence> <command> + + Maps a command to a keysequence in the "browser" context. + + Example: + map j move down + map J move down 10 + """ + name = 'map' + context = 'browser' + resolve_macros = False + + def execute(self): + if not self.arg(1) or not self.arg(2): + self.fm.notify("Syntax: {0} <keysequence> <command>".format(self.get_name()), bad=True) + return + + self.fm.ui.keymaps.bind(self.context, self.arg(1), self.rest(2)) + + +class cmap(map_): + """:cmap <keysequence> <command> + + Maps a command to a keysequence in the "console" context. + + Example: + cmap <ESC> console_close + cmap <C-x> console_type test + """ + context = 'console' + + +class tmap(map_): + """:tmap <keysequence> <command> + + Maps a command to a keysequence in the "taskview" context. + """ + context = 'taskview' + + +class pmap(map_): + """:pmap <keysequence> <command> + + Maps a command to a keysequence in the "pager" context. + """ + context = 'pager' + + +class scout(Command): + """:scout [-FLAGS...] <pattern> + + Swiss army knife command for searching, traveling and filtering files. + + Flags: + -a Automatically open a file on unambiguous match + -e Open the selected file when pressing enter + -f Filter files that match the current search pattern + -g Interpret pattern as a glob pattern + -i Ignore the letter case of the files + -k Keep the console open when changing a directory with the command + -l Letter skipping; e.g. allow "rdme" to match the file "readme" + -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 + + Multiple flags can be combined. For example, ":scout -gpt" would create + a :filter-like command using globbing. + """ + # pylint: disable=bad-whitespace + AUTO_OPEN = 'a' + OPEN_ON_ENTER = 'e' + FILTER = 'f' + SM_GLOB = 'g' + IGNORE_CASE = 'i' + KEEP_OPEN = 'k' + SM_LETTERSKIP = 'l' + MARK = 'm' + UNMARK = 'M' + PERM_FILTER = 'p' + SM_REGEX = 'r' + SMART_CASE = 's' + AS_YOU_TYPE = 't' + INVERT = 'v' + # pylint: enable=bad-whitespace + + def __init__(self, *args, **kwargs): + super(scout, self).__init__(*args, **kwargs) + self._regex = None + self.flags, self.pattern = self.parse_flags() + + def execute(self): # pylint: disable=too-many-branches + thisdir = self.fm.thisdir + flags = self.flags + pattern = self.pattern + regex = self._build_regex() + count = self._count(move=True) + + self.fm.thistab.last_search = regex + self.fm.set_search_method(order="search") + + 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 fobj in thisdir.files: + thisdir.mark_item(fobj, value) + else: + for fobj in thisdir.files: + if regex.search(fobj.relative_path): + thisdir.mark_item(fobj, value) + + if self.PERM_FILTER in flags: + thisdir.filter = regex if pattern else None + + # clean up: + self.cancel() + + if self.OPEN_ON_ENTER in flags or \ + (self.AUTO_OPEN in flags and count == 1): + if pattern == '..': + self.fm.cd(pattern) + else: + self.fm.move(right=1) + + if self.KEEP_OPEN in flags and thisdir != self.fm.thisdir: + # reopen the console: + if not pattern: + self.fm.open_console(self.line) + else: + self.fm.open_console(self.line[0:-len(pattern)]) + + if self.quickly_executed and thisdir != self.fm.thisdir and pattern != "..": + self.fm.block_input(0.5) + + def cancel(self): + self.fm.thisdir.temporary_filter = None + self.fm.thisdir.refilter() + + def quick(self): + asyoutype = self.AS_YOU_TYPE in self.flags + if self.FILTER in self.flags: + self.fm.thisdir.temporary_filter = self._build_regex() + if self.PERM_FILTER in self.flags and asyoutype: + self.fm.thisdir.filter = self._build_regex() + if self.FILTER in self.flags or self.PERM_FILTER in self.flags: + self.fm.thisdir.refilter() + if self._count(move=asyoutype) == 1 and self.AUTO_OPEN in self.flags: + return True + return False + + def tab(self, tabnum): + self._count(move=True, offset=tabnum) + + def _build_regex(self): + if self._regex is not None: + return self._regex + + frmat = "%s" + flags = self.flags + pattern = self.pattern + + if pattern == ".": + return re.compile("") + + # Handle carets at start and dollar signs at end separately + if pattern.startswith('^'): + pattern = pattern[1:] + frmat = "^" + frmat + if pattern.endswith('$'): + pattern = pattern[:-1] + frmat += "$" + + # Apply one of the search methods + if self.SM_REGEX in flags: + regex = pattern + elif self.SM_GLOB in flags: + regex = re.escape(pattern).replace("\\*", ".*").replace("\\?", ".") + elif self.SM_LETTERSKIP in flags: + regex = ".*".join(re.escape(c) for c in pattern) + else: + regex = re.escape(pattern) + + regex = frmat % regex + + # Invert regular expression if necessary + if self.INVERT in flags: + regex = "^(?:(?!%s).)*$" % regex + + # Compile Regular Expression + # pylint: disable=no-member + options = re.UNICODE + if self.IGNORE_CASE in flags or self.SMART_CASE in flags and \ + pattern.islower(): + options |= re.IGNORECASE + # pylint: enable=no-member + try: + self._regex = re.compile(regex, options) + except re.error: + self._regex = re.compile("") + return self._regex + + def _count(self, move=False, offset=0): + count = 0 + cwd = self.fm.thisdir + pattern = self.pattern + + if not pattern or not cwd.files: + return 0 + if pattern == '.': + return 0 + if pattern == '..': + return 1 + + deq = deque(cwd.files) + deq.rotate(-cwd.pointer - offset) + i = offset + regex = self._build_regex() + for fsobj in deq: + if regex.search(fsobj.relative_path): + count += 1 + if move and count == 1: + cwd.move(to=(cwd.pointer + i) % len(cwd.files)) + self.fm.thisfile = cwd.pointed_obj + if count > 1: + return count + i += 1 + + return count == 1 + + +class narrow(Command): + """ + :narrow + + Show only the files selected right now. If no files are selected, + disable narrowing. + """ + def execute(self): + if self.fm.thisdir.marked_items: + selection = [f.basename for f in self.fm.thistab.get_selection()] + self.fm.thisdir.narrow_filter = selection + else: + self.fm.thisdir.narrow_filter = None + self.fm.thisdir.refilter() + + +class filter_inode_type(Command): + """ + :filter_inode_type [dfl] + + Displays only the files of specified inode type. Parameters + can be combined. + + d display directories + f display files + l display links + """ + + def execute(self): + if not self.arg(1): + self.fm.thisdir.inode_type_filter = "" + else: + self.fm.thisdir.inode_type_filter = self.arg(1) + self.fm.thisdir.refilter() + + +class grep(Command): + """:grep <string> + + Looks for a string in all marked files or directories + """ + + def execute(self): + if self.rest(1): + action = ['grep', '--line-number'] + action.extend(['-e', self.rest(1), '-r']) + action.extend(f.path for f in self.fm.thistab.get_selection()) + self.fm.execute_command(action, flags='p') + + +class flat(Command): + """ + :flat <level> + + Flattens the directory view up to the specified level. + + -1 fully flattened + 0 remove flattened view + """ + + def execute(self): + try: + level_str = self.rest(1) + level = int(level_str) + except ValueError: + level = self.quantifier + if level is None: + self.fm.notify("Syntax: flat <level>", bad=True) + return + if level < -1: + self.fm.notify("Need an integer number (-1, 0, 1, ...)", bad=True) + self.fm.thisdir.unload() + 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 ex: + self.fm.notify('Unable to stage files: {0}'.format(ex)) + 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 ex: + self.fm.notify('Unable to unstage files: {0}'.format(ex)) + 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> ...]] + + Prompt the user to input metadata for multiple keys in a row. + """ + + _command_name = "meta" + _console_chain = None + + def execute(self): + prompt_metadata._console_chain = self.args[1:] + self._process_command_stack() + + def _process_command_stack(self): + if prompt_metadata._console_chain: + key = prompt_metadata._console_chain.pop() + self._fill_console(key) + else: + for col in self.fm.ui.browser.columns: + col.need_redraw = True + + def _fill_console(self, key): + metadata = self.fm.metadata.get_metadata(self.fm.thisfile.path) + if key in metadata and metadata[key]: + existing_value = metadata[key] + else: + existing_value = "" + text = "%s %s %s" % (self._command_name, key, existing_value) + self.fm.open_console(text, position=len(text)) + + +class meta(prompt_metadata): + """ + :meta <key> [<value>] + + Change metadata of a file. Deletes the key if value is empty. + """ + + def execute(self): + key = self.arg(1) + update_dict = dict() + update_dict[key] = self.rest(2) + selection = self.fm.thistab.get_selection() + for fobj in selection: + self.fm.metadata.set_metadata(fobj.path, update_dict) + self._process_command_stack() + + 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]: + return [" ".join([self.arg(0), self.arg(1), metadata[key]])] + return [self.arg(0) + " " + k for k in sorted(metadata) + if k.startswith(self.arg(1))] + + +class linemode(default_linemode): + """ + :linemode <mode> + + Change what is displayed as a filename. + + - "mode" may be any of the defined linemodes (see: ranger.core.linemode). + "normal" is mapped to "filename". + """ + + def execute(self): + mode = self.arg(1) + + if mode == "normal": + from ranger.core.linemode import DEFAULT_LINEMODE + mode = DEFAULT_LINEMODE + + if mode not in self.fm.thisfile.linemode_dict: + self.fm.notify("Unhandled linemode: `%s'" % mode, bad=True) + return + + self.fm.thisdir.set_linemode_of_children(mode) + + # Ask the browsercolumns to redraw + for col in self.fm.ui.browser.columns: + col.need_redraw = True + + +class yank(Command): + """:yank [name|dir|path] + + Copies the file's name (default), directory or path into both the primary X + selection and the clipboard. + """ + + modes = { + '': 'basename', + 'name': 'basename', + 'dir': 'dirname', + 'path': 'path', + } + + def execute(self): + import subprocess + + def clipboards(): + from ranger.ext.get_executables import get_executables + clipboard_managers = { + 'xclip': [ + ['xclip'], + ['xclip', '-selection', 'clipboard'], + ], + 'xsel': [ + ['xsel'], + ['xsel', '-b'], + ], + 'pbcopy': [ + ['pbcopy'], + ], + } + ordered_managers = ['pbcopy', 'xclip', 'xsel'] + executables = get_executables() + for manager in ordered_managers: + if manager in executables: + return clipboard_managers[manager] + return [] + + clipboard_commands = clipboards() + + selection = self.get_selection_attr(self.modes[self.arg(1)]) + new_clipboard_contents = "\n".join(selection) + for command in clipboard_commands: + process = subprocess.Popen(command, universal_newlines=True, + stdin=subprocess.PIPE) + process.communicate(input=new_clipboard_contents) + + def get_selection_attr(self, attr): + return [getattr(item, attr) for item in + self.fm.thistab.get_selection()] + + def tab(self, tabnum): + return ( + self.start(1) + mode for mode + in sorted(self.modes.keys()) + if mode + )
A .config/ranger/rc.conf

@@ -0,0 +1,667 @@

+# =================================================================== +# 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. +# +# If you copy this whole file there, you may want to set the environment +# variable RANGER_LOAD_DEFAULT_RC to FALSE to avoid loading it twice. +# +# The purpose of this file is mainly to define keybindings and settings. +# For running more complex python code, please create a plugin in "plugins/" or +# a command in "commands.py". +# +# 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 +# =================================================================== + +# 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,3,4 + +# Which files should be hidden? (regular expression) +set hidden_filter ^\.|\.(?:pyc|pyo|bak|swp)$|^lost\+found$|^__(py)?cache__$ + +# Show hidden files? You can toggle this by typing 'zh' +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 + +# Use non-default path for file preview script? +# ranger ships with scope.sh, a script that calls external programs (see +# README.md for dependencies) to preview images, archives, etc. +#set preview_script ~/.config/ranger/scope.sh + +# Use the external preview script or display simple plain text or image previews? +set use_preview_script true + +# Automatically count files in the directory, even before entering them? +set automatically_count_files true + +# Open all images in this directory when running certain image viewers +# like feh or sxiv? You can still open selected files by marking them. +set open_all_images true + +# Be aware of version control systems and display information. +set vcs_aware true + +# State of the four backends git, hg, bzr, svn. The possible states are +# disabled, local (only show local info), enabled (show local and remote +# information). +set vcs_backend_git enabled +set vcs_backend_hg disabled +set vcs_backend_bzr disabled +set vcs_backend_svn disabled + +# Use one of the supported image preview protocols +set preview_images true + +# Set the preview image method. Supported methods: +# +# * w3m (default): +# Preview images in full color with the external command "w3mimgpreview"? +# This requires the console web browser "w3m" and a supported terminal. +# It has been successfully tested with "xterm" and "urxvt" without tmux. +# +# * iterm2: +# Preview images in full color using iTerm2 image previews +# (http://iterm2.com/images.html). This requires using iTerm2 compiled +# with image preview support. +# +# This feature relies on the dimensions of the terminal's font. By default, a +# width of 8 and height of 11 are used. To use other values, set the options +# iterm2_font_width and iterm2_font_height to the desired values. +# +# * 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 + +# Default iTerm2 font size (see: preview_images_method: iterm2) +set iterm2_font_width 8 +set iterm2_font_height 11 + +# Use a unicode "..." character to mark cut-off filenames? +set unicode_ellipsis false + +# Show dotfiles in the bookmark preview box? +set show_hidden_bookmarks true + +# Which colorscheme to use? These colorschemes are available by default: +# default, jungle, snow, solarized +set colorscheme default + +# Preview files on the rightmost column? +# And collapse (shrink) the last column if there is nothing to preview? +set preview_files true +set preview_directories true +set collapse_preview true + +# Save the console history on exit? +set save_console_history true + +# Draw the status bar on top of the browser window (default: bottom) +set status_bar_on_top false + +# Draw a progress bar in the status bar which displays the average state of all +# currently running tasks which support progress bars? +set draw_progress_bar_in_status_bar true + +# Draw borders around columns? +set draw_borders true + +# Display the directory name in tabs? +set dirname_in_tabs false + +# Enable the mouse support? +set mouse_enabled true + +# Display the file size in the main column or status bar? +set display_size_in_main_column true +set display_size_in_status_bar true + +# Display files tags in all columns or only in main column? +set display_tags_in_all_columns true + +# Set a title for the window? +set update_title false + +# Set the title to "ranger" in the tmux program? +set update_tmux_title false + +# Shorten the title if it gets long? The number defines how many +# directories are displayed at once, 0 turns off this feature. +set shorten_title 3 + +# Show hostname in titlebar? +set hostname_in_titlebar true + +# Abbreviate $HOME with ~ in the titlebar (first line) of ranger? +set tilde_in_titlebar false + +# How many directory-changes or console-commands should be kept in history? +set max_history_size 20 +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? (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 + +# Save bookmarks (used with mX and `X) instantly? +# This helps to synchronize bookmarks between multiple ranger +# instances but leads to *slight* performance loss. +# When false, bookmarks are saved when ranger is exited. +set autosave_bookmarks true + +# Save the "`" bookmark to disk. This can be used to switch to the last +# directory by typing "``". +set save_backtick_bookmark true + +# You can display the "real" cumulative size of directories by using the +# command :get_cumulative_size or typing "dc". The size is expensive to +# calculate and will not be updated automatically. You can choose +# to update it automatically though by turning on this option: +set autoupdate_cumulative_size false + +# Turning this on makes sense for screen readers: +set show_cursor false + +# One of: size, natural, basename, atime, ctime, mtime, type, random +set sort natural + +# Additional sorting options +set sort_reverse false +set sort_case_insensitive true +set sort_directories_first true +set sort_unicode false + +# Enable this if key combinations with the Alt Key don't work for you. +# (Especially on xterm) +set xterm_alt_key false + +# Whether to include bookmarks in cd command +set cd_bookmarks true + +# Changes case sensitivity for the cd command tab completion +set cd_tab_case sensitive + +# Use fuzzy tab completion with the "cd" command. For example, +# ":cd /u/lo/b<tab>" expands to ":cd /usr/local/bin". +set cd_tab_fuzzy false + +# Avoid previewing files larger than this size, in bytes. Use a value of 0 to +# disable this feature. +set preview_max_size 0 + +# Add the highlighted file to the path in the titlebar +set show_selection_in_titlebar true + +# The delay that ranger idly waits for user input, in milliseconds, with a +# resolution of 100ms. Lower delay reduces lag between directory updates but +# increases CPU load. +set idle_delay 2000 + +# When the metadata manager module looks for metadata, should it only look for +# a ".metadata.json" file in the current directory, or do a deep search and +# check all directories above the current one as well? +set metadata_deep_search false + +# 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 false + +# Start line numbers from 1 instead of 0 +set one_indexed false + +# Save tabs on exit +set save_tabs_on_exit false + +# Enable scroll wrapping - moving down while on the last item will wrap around to +# the top and vice versa. +set wrap_scroll false + +# Set the global_inode_type_filter to nothing. Possible options: d, f and l for +# directories, files and symlinks respectively. +set global_inode_type_filter + +# =================================================================== +# == Local Options +# =================================================================== +# You can set local options that only affect a single directory. + +# Examples: +# setlocal path=~/downloads sort mtime + +# =================================================================== +# == Command Aliases in the Console +# =================================================================== + +alias e edit +alias q quit +alias q! quit! +alias qa quitall +alias qa! quitall! +alias qall quitall +alias qall! quitall! +alias setl setlocal + +alias filter scout -prt +alias find scout -aeit +alias mark scout -mr +alias unmark scout -Mr +alias search scout -rs +alias search_inc scout -rts +alias travel scout -aefklst + +# =================================================================== +# == Define keys for the browser +# =================================================================== + +# Basic +map Q quitall +map q quit +copymap q ZZ ZQ + +map R reload_cwd +map F set freeze_files! +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 +map W display_log +map w taskview_open +map S shell $SHELL + +map : console +map ; console +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 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 +map t tag_toggle +map ut tag_remove +map "<any> tag_toggle tag=%any +map <Space> mark_files toggle=True +map v mark_files all=True toggle=True +map uv mark_files all=True val=False +map V toggle_visual_mode +map uV toggle_visual_mode reverse=True + +# For the nostalgics: Midnight Commander bindings +map <F1> help +map <F2> rename_append +map <F3> display_file +map <F4> edit +map <F5> copy +map <F6> cut +map <F7> console mkdir%space +map <F8> console delete +map <F10> exit + +# In case you work on a keyboard with dvorak layout +map <UP> move up=1 +map <DOWN> move down=1 +map <LEFT> move left=1 +map <RIGHT> move right=1 +map <HOME> move to=0 +map <END> move to=-1 +map <PAGEDOWN> move down=1 pages=True +map <PAGEUP> move up=1 pages=True +map <CR> move right=1 +#map <DELETE> console delete +map <INSERT> console touch%space + +# VIM-like +copymap <UP> k +copymap <DOWN> j +copymap <LEFT> h +copymap <RIGHT> l +copymap <HOME> gg +copymap <END> G +copymap <PAGEDOWN> <C-F> +copymap <PAGEUP> <C-B> + +map J move down=0.5 pages=True +map K move up=0.5 pages=True +copymap J <C-D> +copymap K <C-U> + +# Jumping around +map H history_go -1 +map L history_go 1 +map ] move_parent 1 +map [ move_parent -1 +map } traverse +map ) jump_non + +map gh cd ~ +map ge cd /etc +map gu cd /usr +map gd cd ~/Documents +map gdp cd ~/Documents/Personal +map gdw cd ~/Documents/Professional +map g77 cd ~/73h4x +map g7c cd ~/73h4x/code +map g7d cd ~/73h4x/dotfiles +map g7n cd ~/73h4x/notes +map g7p cd ~/73h4x/projects +map gll cd ~/Library +map gla cd ~/Library/Audio +map gli cd ~/Library/Images +map glt cd ~/Library/Textfiles +map glv cd ~/Library/Video +map gL cd -r %f +map go cd /opt +map gv cd /var +map gm cd /media +map gM cd /mnt +map gs cd /srv +map gp cd /tmp +map gr cd / +map gR eval fm.cd(ranger.RANGERDIR) +map g/ cd / +map g? cd /usr/share/doc/ranger + +# External Programs +map E edit +map du shell -p du --max-depth=1 -h --apparent-size +map dU shell -p du --max-depth=1 -h --apparent-size | sort -rh +map yp yank path +map yd yank dir +map yn yank name + +# Filesystem Operations +map = chmod + +map cw console rename%space +map a rename_append +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 +map pht paste_hardlinked_subtree + +map dD console delete + +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) +map dG eval fm.cut(dirarg=dict(to=-1), narg=quantifier) +map dj eval fm.cut(dirarg=dict(down=1), narg=quantifier) +map dk eval fm.cut(dirarg=dict(up=1), narg=quantifier) +map ygg eval fm.copy(dirarg=dict(to=0), narg=quantifier) +map yG eval fm.copy(dirarg=dict(to=-1), narg=quantifier) +map yj eval fm.copy(dirarg=dict(down=1), narg=quantifier) +map yk eval fm.copy(dirarg=dict(up=1), narg=quantifier) + +# Searching +map / console search%space +map n search_next +map N search_next forward=False +map ct search_next order=tag +map cs search_next order=size +map ci search_next order=mimetype +map cc search_next order=ctime +map cm search_next order=mtime +map ca search_next order=atime + +# Tabs +map <C-n> tab_new +map <C-w> tab_close +map <TAB> tab_move 1 +map <S-TAB> tab_move -1 +map <A-Right> tab_move 1 +map <A-Left> tab_move -1 +map gt tab_move 1 +map gT tab_move -1 +map gn tab_new +map gc tab_close +map uq tab_restore +map <a-1> tab_open 1 +map <a-2> tab_open 2 +map <a-3> tab_open 3 +map <a-4> tab_open 4 +map <a-5> tab_open 5 +map <a-6> tab_open 6 +map <a-7> tab_open 7 +map <a-8> tab_open 8 +map <a-9> tab_open 9 + +# Sorting +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 +map on chain set sort=natural; set sort_reverse=False +map om chain set sort=mtime; set sort_reverse=False +map oc chain set sort=ctime; set sort_reverse=False +map oa chain set sort=atime; set sort_reverse=False +map ot chain set sort=type; set sort_reverse=False +map oe chain set sort=extension; set sort_reverse=False + +map oS chain set sort=size; set sort_reverse=True +map oB chain set sort=basename; set sort_reverse=True +map oN chain set sort=natural; set sort_reverse=True +map oM chain set sort=mtime; set sort_reverse=True +map oC chain set sort=ctime; set sort_reverse=True +map oA chain set sort=atime; set sort_reverse=True +map oT chain set sort=type; set sort_reverse=True +map oE chain set sort=extension; set sort_reverse=True + +map dc get_cumulative_size + +# Settings +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 +copymap zf zz + +# Bookmarks +map `<any> enter_bookmark %any +map '<any> enter_bookmark %any +map m<any> set_bookmark %any +map um<any> unset_bookmark %any + +map m<bg> draw_bookmarks +copymap m<bg> um<bg> `<bg> '<bg> + +# Generate all the chmod bindings with some python help: +eval for arg in "rwxXst": cmd("map +u{0} shell -f chmod u+{0} %s".format(arg)) +eval for arg in "rwxXst": cmd("map +g{0} shell -f chmod g+{0} %s".format(arg)) +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)) + +eval for arg in "rwxXst": cmd("map -u{0} shell -f chmod u-{0} %s".format(arg)) +eval for arg in "rwxXst": cmd("map -g{0} shell -f chmod g-{0} %s".format(arg)) +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 +# =================================================================== +# Note: Unmapped keys are passed directly to the console. + +# Basic +cmap <tab> eval fm.ui.console.tab() +cmap <s-tab> eval fm.ui.console.tab(-1) +cmap <ESC> eval fm.ui.console.close() +cmap <CR> eval fm.ui.console.execute() +cmap <C-l> redraw_window + +copycmap <ESC> <C-c> +copycmap <CR> <C-j> + +# Move around +cmap <up> eval fm.ui.console.history_move(-1) +cmap <down> eval fm.ui.console.history_move(1) +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() + +# And of course the emacs way +copycmap <up> <C-p> +copycmap <down> <C-n> +copycmap <left> <C-b> +copycmap <right> <C-f> +copycmap <home> <C-a> +copycmap <end> <C-e> +copycmap <delete> <C-d> +copycmap <backspace> <C-h> + +# Note: There are multiple ways to express backspaces. <backspace> (code 263) +# and <backspace2> (code 127). To be sure, use both. +copycmap <backspace> <backspace2> + +# This special expression allows typing in numerals: +cmap <allow_quantifiers> false + +# =================================================================== +# == Pager Keybindings +# =================================================================== + +# Movement +pmap <down> pager_move down=1 +pmap <up> pager_move up=1 +pmap <left> pager_move left=4 +pmap <right> pager_move right=4 +pmap <home> pager_move to=0 +pmap <end> pager_move to=-1 +pmap <pagedown> pager_move down=1.0 pages=True +pmap <pageup> pager_move up=1.0 pages=True +pmap <C-d> pager_move down=0.5 pages=True +pmap <C-u> pager_move up=0.5 pages=True + +copypmap <UP> k <C-p> +copypmap <DOWN> j <C-n> <CR> +copypmap <LEFT> h +copypmap <RIGHT> l +copypmap <HOME> g +copypmap <END> G +copypmap <C-d> d +copypmap <C-u> u +copypmap <PAGEDOWN> n f <C-F> <Space> +copypmap <PAGEUP> p b <C-B> + +# Basic +pmap <C-l> redraw_window +pmap <ESC> pager_close +copypmap <ESC> q Q i <F3> +pmap E edit_file + +# =================================================================== +# == Taskview Keybindings +# =================================================================== + +# Movement +tmap <up> taskview_move up=1 +tmap <down> taskview_move down=1 +tmap <home> taskview_move to=0 +tmap <end> taskview_move to=-1 +tmap <pagedown> taskview_move down=1.0 pages=True +tmap <pageup> taskview_move up=1.0 pages=True +tmap <C-d> taskview_move down=0.5 pages=True +tmap <C-u> taskview_move up=0.5 pages=True + +copytmap <UP> k <C-p> +copytmap <DOWN> j <C-n> <CR> +copytmap <HOME> g +copytmap <END> G +copytmap <C-u> u +copytmap <PAGEDOWN> n f <C-F> <Space> +copytmap <PAGEUP> p b <C-B> + +# Changing priority and deleting tasks +tmap J eval -q fm.ui.taskview.task_move(-1) +tmap K eval -q fm.ui.taskview.task_move(0) +tmap dd eval -q fm.ui.taskview.task_remove() +tmap <pagedown> eval -q fm.ui.taskview.task_move(-1) +tmap <pageup> eval -q fm.ui.taskview.task_move(0) +tmap <delete> eval -q fm.ui.taskview.task_remove() + +# Basic +tmap <C-l> redraw_window +tmap <ESC> taskview_close +copytmap <ESC> q Q w <C-c>
A .config/ranger/rifle.conf

@@ -0,0 +1,229 @@

+# +# This is the configuration file of "rifle", ranger's file executor/opener. +# Each line consists of conditions and a command. For each line the conditions +# are checked and if they are met, the respective command is run. +# +# Syntax: +# <condition1> , <condition2> , ... = command +# +# The command can contain these environment variables: +# $1-$9 | The n-th selected file +# $@ | All selected files +# +# If you use the special command "ask", rifle will ask you what program to run. +# +# Prefixing a condition with "!" will negate its result. +# These conditions are currently supported: +# match <regexp> | The regexp matches $1 +# ext <regexp> | The regexp matches the extension of $1 +# mime <regexp> | The regexp matches the mime type of $1 +# name <regexp> | The regexp matches the basename of $1 +# path <regexp> | The regexp matches the absolute path of $1 +# has <program> | The program is installed (i.e. located in $PATH) +# env <variable> | The environment variable "variable" is non-empty +# file | $1 is a file +# directory | $1 is a directory +# number <n> | change the number of this command to n +# terminal | stdin, stderr and stdout are connected to a terminal +# X | $DISPLAY is not empty (i.e. Xorg runs) +# +# There are also pseudo-conditions which have a "side effect": +# flag <flags> | Change how the program is run. See below. +# label <label> | Assign a label or name to the command so it can +# | be started with :open_with <label> in ranger +# | or `rifle -p <label>` in the standalone executable. +# else | Always true. +# +# Flags are single characters which slightly transform the command: +# f | Fork the program, make it run in the background. +# | New command = setsid $command >& /dev/null & +# r | Execute the command with root permissions +# | New command = sudo $command +# t | Run the program in a new terminal. If $TERMCMD is not defined, +# | rifle will attempt to extract it from $TERM. +# | New command = $TERMCMD -e $command +# Note: The "New command" serves only as an illustration, the exact +# implementation may differ. +# Note: When using rifle in ranger, there is an additional flag "c" for +# only running the current file even if you have marked multiple files. + +#------------------------------------------- +# Websites +#------------------------------------------- +# Rarely installed browsers get higher priority; It is assumed that if you +# install a rare browser, you probably use it. Firefox/konqueror/w3m on the +# other hand are often only installed as fallback browsers. +#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 -- "$@" +#ext x?html?, has chromium-browser, X, flag f = chromium-browser -- "$@" +#ext x?html?, has chromium, X, flag f = chromium -- "$@" +#ext x?html?, has google-chrome, X, flag f = google-chrome -- "$@" +#ext x?html?, has opera, X, flag f = opera -- "$@" +#ext x?html?, has firefox, X, flag f = firefox -- "$@" +#ext x?html?, has seamonkey, X, flag f = seamonkey -- "$@" +#ext x?html?, has iceweasel, X, flag f = iceweasel -- "$@" +#ext x?html?, has epiphany, X, flag f = epiphany -- "$@" +#ext x?html?, has konqueror, X, flag f = konqueror -- "$@" +#ext x?html?, has elinks, terminal = elinks "$@" +#ext x?html?, has links2, terminal = links2 "$@" +#ext x?html?, has links, terminal = links "$@" +#ext x?html?, has lynx, terminal = lynx -- "$@" +#ext x?html?, has w3m, terminal = w3m "$@" + +#------------------------------------------- +# Misc +#------------------------------------------- +# Define the "editor" for text files as first action +mime ^text, label editor = ${VISUAL:-$EDITOR} -- "$@" +mime ^text, label pager = "$PAGER" -- "$@" +!mime ^text, label editor, ext htmllxml|json|csv|tex|py|pl|rb|js|sh|php = ${VISUAL:-$EDITOR} -- "$@" +!mime ^text, label pager, ext html|xml|json|csv|tex|py|pl|rb|js|sh|php = "$PAGER" -- "$@" + +ext 1 = man "$1" +ext s[wmf]c, has zsnes, X = zsnes "$1" +ext s[wmf]c, has snes9x-gtk,X = snes9x-gtk "$1" +ext nes, has fceux, X = fceux "$1" +ext exe = wine "$1" +name ^[mM]akefile$ = ${VISUAL:-$EDITOR} -- "$@" + +#-------------------------------------------- +# Code +#------------------------------------------- +ext py = python -- "$1" +ext pl = perl -- "$1" +ext rb = ruby -- "$1" +ext js = node -- "$1" +ext sh = sh -- "$1" +ext php = php -- "$1" + +#-------------------------------------------- +# Audio without X +#------------------------------------------- +mime ^audio|ogg$, terminal, has mpv = mpv --no-audio-display -- "$@" +mime ^audio|ogg$, terminal, has mplayer2 = mplayer2 -- "$@" +mime ^audio|ogg$, terminal, has mplayer = mplayer -- "$@" +ext midi?, terminal, has wildmidi = wildmidi -- "$@" + +#-------------------------------------------- +# Video/Audio with a GUI +#------------------------------------------- +mime ^video|audio, has gmplayer, X, flag f = gmplayer -- "$@" +mime ^video|audio, has smplayer, X, flag f = smplayer "$@" +mime ^video, has mpv, X, flag f = mpv -- "$@" +mime ^video, has mpv, X, flag f = mpv --fs -- "$@" +mime ^video, has mplayer2, X, flag f = mplayer2 -- "$@" +mime ^video, has mplayer2, X, flag f = mplayer2 -fs -- "$@" +mime ^video, has mplayer, X, flag f = mplayer -- "$@" +mime ^video, has mplayer, X, flag f = mplayer -fs -- "$@" +mime ^video|audio, has vlc, X, flag f = vlc -- "$@" +mime ^video|audio, has totem, X, flag f = totem -- "$@" +mime ^video|audio, has totem, X, flag f = totem --fullscreen -- "$@" + +#-------------------------------------------- +# Video without X: +#------------------------------------------- +mime ^video, terminal, !X, has mpv = mpv -- "$@" +mime ^video, terminal, !X, has mplayer2 = mplayer2 -- "$@" +mime ^video, terminal, !X, has mplayer = mplayer -- "$@" + +#------------------------------------------- +# Documents +#------------------------------------------- +ext pdf, has llpp, X, flag f = llpp "$@" +ext pdf, has evince, X, flag f = evince -- "$@" +ext pdf, has zathura, X, flag f = zathura -- "$@" +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 atril, X, flag f = atril -- "$@" +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 pdf, has open, X, flat f = open "$@" + +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 -- "$@" +ext pptx?|od[dfgpst]|docx?|sxc|xlsx?|xlt|xlw|gnm|gnumeric, has libreoffice, X, flag f = libreoffice "$@" +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 -- "$@" + +ext epub, has ebook-viewer, X, flag f = ebook-viewer -- "$@" +ext mobi, has ebook-viewer, X, flag f = ebook-viewer -- "$@" + +#------------------------------------------- +# Image Viewing: +#------------------------------------------- +mime ^image/svg, has inkscape, X, flag f = inkscape -- "$@" +mime ^image/svg, has display, X, flag f = display -- "$@" +mime ^image/gif, has eog, X, flag f = eog -- "$@" +# mime ^image/gif, has gthumb, X, flag f = gthumb -- "$@" +# works for gifs, makes SURE they repeat +mime ^image/gif, has mpv, X, flag f = mpv --loop=inf -- "$@" + +mime ^image, has eog, X, flag f = eog -- "$@" +mime ^image, has feh, X, flag f = feh -- "$@" +mime ^image, has pqiv, X, flag f = pqiv -- "$@" +mime ^image, has sxiv, X, flag f = sxiv -- "$@" +mime ^image, has mirage, X, flag f = mirage -- "$@" +mime ^image, has ristretto, X, flag f = ristretto "$@" +mime ^image, has eom, X, flag f = eom -- "$@" +mime ^image, has nomacs, X, flag f = nomacs -- "$@" +mime ^image, has geeqie, X, flag f = geeqie -- "$@" +mime ^image, has gimp, X, flag f = gimp -- "$@" +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 ace|ar|arc|bz2?|cab|cpio|cpt|deb|dgc|dmg|gz, has atool = atool --list --each -- "$@" | "$PAGER" +ext iso|jar|msi|pkg|rar|shar|tar|tgz|xar|xpi|xz|zip, has atool = atool --list --each -- "$@" | "$PAGER" +ext 7z|ace|ar|arc|bz2?|cab|cpio|cpt|deb|dgc|dmg|gz, has atool = atool --extract --each -- "$@" +ext iso|jar|msi|pkg|rar|shar|tar|tgz|xar|xpi|xz|zip, has atool = atool --extract --each -- "$@" + +# Listing and extracting archives without atool: +ext tar|gz|bz2|xz, has tar = tar vvtf "$1" | "$PAGER" +ext tar|gz|bz2|xz, has tar = for file in "$@"; do tar vvxf "$file"; done +ext bz2, has bzip2 = for file in "$@"; do bzip2 -dk "$file"; done +ext zip, has unzip = unzip -l "$1" | less +ext zip, has unzip = for file in "$@"; do unzip -d "${file%.*}" "$file"; done +ext ace, has unace = unace l "$1" | less +ext ace, has unace = for file in "$@"; do unace e "$file"; done +ext rar, has unrar = unrar l "$1" | less +ext rar, has unrar = for file in "$@"; do unrar x "$file"; done + +#------------------------------------------- +# Misc +#------------------------------------------- +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|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 = ${VISUAL:-$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"
A .config/ranger/scope.sh

@@ -0,0 +1,178 @@

+#!/usr/bin/env bash + +set -o noclobber -o noglob -o nounset -o pipefail +IFS=$'\n' + +# If the option `use_preview_script` is set to `true`, +# then this script will be called and its output will be displayed in ranger. +# ANSI color codes are supported. +# STDIN is disabled, so interactive scripts won't work properly + +# This script is considered a configuration file and must be updated manually. +# It will be left untouched if you upgrade ranger. + +# Meanings of exit codes: +# code | meaning | action of ranger +# -----+------------+------------------------------------------- +# 0 | success | Display stdout as preview +# 1 | no preview | Display no preview at all +# 2 | plain text | Display the plain content of the file +# 3 | fix width | Don't reload when width changes +# 4 | fix height | Don't reload when height changes +# 5 | fix both | Don't ever reload +# 6 | image | Display the image `$IMAGE_CACHE_PATH` points to as an image preview +# 7 | image | Display the file directly as an image + +# Script arguments +FILE_PATH="${1}" # Full path of the highlighted file +PV_WIDTH="${2}" # Width of the preview pane (number of fitting characters) +PV_HEIGHT="${3}" # Height of the preview pane (number of fitting characters) +IMAGE_CACHE_PATH="${4}" # Full path that should be used to cache image preview +PV_IMAGE_ENABLED="${5}" # 'True' if image previews are enabled, 'False' otherwise. + +FILE_EXTENSION="${FILE_PATH##*.}" +FILE_EXTENSION_LOWER=$(echo ${FILE_EXTENSION} | tr '[:upper:]' '[:lower:]') + +# Settings +HIGHLIGHT_SIZE_MAX=262143 # 256KiB +HIGHLIGHT_TABWIDTH=8 +HIGHLIGHT_STYLE='pablo' +PYGMENTIZE_STYLE='autumn' + + +handle_extension() { + case "${FILE_EXTENSION_LOWER}" in + # Archive + 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) + atool --list -- "${FILE_PATH}" && exit 5 + bsdtar --list --file "${FILE_PATH}" && exit 5 + exit 1;; + rar) + # Avoid password prompt by providing empty password + unrar lt -p- -- "${FILE_PATH}" && exit 5 + exit 1;; + 7z) + # Avoid password prompt by providing empty password + 7z l -p -- "${FILE_PATH}" && exit 5 + exit 1;; + + # PDF + pdf) + # Preview as text conversion + pdftotext -l 10 -nopgbrk -q -- "${FILE_PATH}" - && exit 5 + exiftool "${FILE_PATH}" && exit 5 + exit 1;; + + # BitTorrent + torrent) + transmission-show -- "${FILE_PATH}" && exit 5 + exit 1;; + + # OpenDocument + odt|ods|odp|sxw) + # Preview as text conversion + odt2txt "${FILE_PATH}" && exit 5 + exit 1;; + + # HTML + htm|html|xhtml) + # Preview as text conversion + w3m -dump "${FILE_PATH}" && exit 5 + lynx -dump -- "${FILE_PATH}" && exit 5 + elinks -dump "${FILE_PATH}" && exit 5 + ;; # Continue with next handler on failure + esac +} + +handle_image() { + local mimetype="${1}" + case "${mimetype}" in + # SVG + # image/svg+xml) + # convert "${FILE_PATH}" "${IMAGE_CACHE_PATH}" && exit 6 + # exit 1;; + + # Image + image/*) + local orientation + orientation="$( identify -format '%[EXIF:Orientation]\n' -- "${FILE_PATH}" )" + # If orientation data is present and the image actually + # needs rotating ("1" means no rotation)... + if [[ -n "$orientation" && "$orientation" != 1 ]]; then + # ...auto-rotate the image according to the EXIF data. + convert -- "${FILE_PATH}" -auto-orient "${IMAGE_CACHE_PATH}" && exit 6 + fi + + # `w3mimgdisplay` will be called for all images (unless overriden as above), + # but might fail for unsupported types. + exit 7;; + + # Video + # video/*) + # # Thumbnail + # ffmpegthumbnailer -i "${FILE_PATH}" -o "${IMAGE_CACHE_PATH}" -s 0 && exit 6 + # exit 1;; + # PDF + # application/pdf) + # pdftoppm -f 1 -l 1 \ + # -scale-to-x 1920 \ + # -scale-to-y -1 \ + # -singlefile \ + # -jpeg -tiffcompression jpeg \ + # -- "${FILE_PATH}" "${IMAGE_CACHE_PATH%.*}" \ + # && exit 6 || exit 1;; + esac +} + +handle_mime() { + local mimetype="${1}" + case "${mimetype}" in + # Text + text/* | */xml) + # Syntax highlight + if [[ "$( stat --printf='%s' -- "${FILE_PATH}" )" -gt "${HIGHLIGHT_SIZE_MAX}" ]]; then + exit 2 + fi + if [[ "$( tput colors )" -ge 256 ]]; then + local pygmentize_format='terminal256' + local highlight_format='xterm256' + else + local pygmentize_format='terminal' + local highlight_format='ansi' + fi + highlight --replace-tabs="${HIGHLIGHT_TABWIDTH}" --out-format="${highlight_format}" \ + --style="${HIGHLIGHT_STYLE}" --force -- "${FILE_PATH}" && exit 5 + # pygmentize -f "${pygmentize_format}" -O "style=${PYGMENTIZE_STYLE}" -- "${FILE_PATH}" && exit 5 + exit 2;; + + # Image + image/*) + # Preview as text conversion + # img2txt --gamma=0.6 --width="${PV_WIDTH}" -- "${FILE_PATH}" && exit 4 + exiftool "${FILE_PATH}" && exit 5 + exit 1;; + + # Video and audio + video/* | audio/*) + mediainfo "${FILE_PATH}" && exit 5 + exiftool "${FILE_PATH}" && exit 5 + exit 1;; + esac +} + +handle_fallback() { + echo '----- File Type Classification -----' && file --dereference --brief -- "${FILE_PATH}" && exit 5 + exit 1 +} + + +MIMETYPE="$( file --dereference --brief --mime-type -- "${FILE_PATH}" )" +if [[ "${PV_IMAGE_ENABLED}" == 'True' ]]; then + handle_image "${MIMETYPE}" +fi +handle_extension +handle_mime "${MIMETYPE}" +handle_fallback + +exit 1
A .config/systemd/user/kdeconnectd.service

@@ -0,0 +1,12 @@

+[Unit] +Description=KDEConnect Daemon +StartLimitIntervalSec=200 +StartLimitBurst=15 + +[Service] +Environment=DISPLAY=:0 +ExecStart=/usr/lib/kdeconnectd +Restart=on-failure + +[Install] +WantedBy=default.target
A README.md

@@ -0,0 +1,10 @@

+# x1phosura's dotfiles extra + +Miscellaneous extra configs: some changed minimally to none, others very customized. Some files are based off of or inspired by others, some are purely my own. + +This is intended more as a "holding place" or backup for my configs, so software development/version control best practices will not apply (translation: git history may be periodically destroyed). + +Dotfiles are placed using symlinks for ease of management and to make copying unnecessary. The dotfile symlink script _should_ be idempotent. + +Feel free to peruse if curious or if reading my dotfiles seems like your idea of a fun time. +
A bin/TODO/mp3-tag-setter.sh

@@ -0,0 +1,91 @@

+#!/usr/bin/env bash + +# by AAAAAAAA + +# assumes that mp3 files-to-be-tagged are named accordingly: +# Track # - Artist - Title.mp3 +# +# TODO: get semi-working +# TODO: run shellcheck on this file once it works +# TODO: use mutagen/mid3v2 because it's better and more up-to-date +# + +# sets tag $TAG for every .mp3 file in the currecnt directory +set_tag() { + echo "Type in the field name _exactly_: " + read "FIELD" + for i in *.mp3 ; do ${TAGEDITOR} ${TAG} ${FIELD} "$i"; done +} + +# reads song titles from textfile, as well as ARTIST and ALBUM variables, +# assumes song title order in file matches up with filename order in current +# directory, then renames accordingly +rename_mp3s() { + MP3FILELIST="$(ls -1)" + while LINE= read -r line + do + # something with $line + done < $INPUTFILE + +} + +# sets variables for command and flags for the id3 tag editor of choice +TAGEDITOR="id3tag" # id3tag comes with id3v2, which is in the Arch repo +ALBUM_FLAG="-A" +ARTIST_FLAG="-a" +YEAR_FLAG="-y" +TRACK_NUM_FLAG="-t" +TITLE_FLAG="-s" + +WELCOME="mp3-tag-setter.sh Version 0.2\n \ +This script applies to every .mp3 file in the current directory.\n \ +Note: actions with (*) require the files to be named accordingly:\n \ + Track# - Artist - Title.mp3\n \ +Would you like to:\n \ +1) Set the album\n \ +2) Set the artist\n \ +3) Set the year\n \ +4) Set track numbers (*)\n \ +5) Set track titles (*)\n \ +6) Mass rename of files according to pre-defined textfile (is own thing)\n" + +echo -e $WELCOME +read "ACTION" + +case $ACTION in +1) + TAG="$ALBUM_FLAG" + set_flag() + ;; +2) + TAG="$ARTIST_FLAG" + set_flag() + ;; +3) + TAG="$YEAR_FLAG" + set_flag() + ;; +4) + # set track numbers from filename + # + ;; +5) + # set track titles from filename + # + ;; +6) + # renames a set of .mp3s IN ORDER according to ordered list in a textfile + # echo an explanation as to how this works + # + echo "Type in the name of a textfile with song titles: " + read INPUTFILE + rename_mp3s() + ;; +*) + echo "Invalid action. Please type 1, 2, 3 or 4." + ;; +esac + +# sets titles in metadata +#for i in *.mp3; do TITLE="$(echo $i | awk 'BEGIN{FS="-"} {print $3}' | sed 's/.mp3//g')"; id3tag -s "$TITLE" "$i" ; done +
A bin/TODO/wifi-bruteforce.sh

@@ -0,0 +1,24 @@

+#!/usr/bin/env bash + +# wpa-bruteforce.sh +# Attempts to connect to an SSID given a password list, uses wpa_supplicant +# DOES NOT WORK YET! +# by AAAAAAAA + + +# TODO: change so that wordlist is read from a file +wordlist="blueberry blackberry chocolate compassion delightful delighted \ +equality espresso exciting fabulous fantastic generous peppermint pleasure \ +wonderful" + +wint="wlp4s0" # wireless networking interface + +echo "Enter the wpa/2 SSID you're trying to connect to: " +read ssid + +for pass in $wordlist; do + echo "Trying to connect to $ssid using password $pass" + wpa_supplicant -B -i "$wint" -c <(wpa_passphrase "$ssid" "$pass") + # sudo dhcpcd "$wint" # needed if systemd dhcpcd service not used +done +
A bin/backer-upper-0.7.5

@@ -0,0 +1,67 @@

+#!/usr/bin/env bash + +# by x1phosura + +# Synchronizes the destination to the source, preserving metadata (owner, +# group, permissions, timestamps, etc...) and symbolic links. It also skips +# replacing files based on a calculated checksum, which can save a lot of time +# with backups! ssh is used for encryption, and the script displays the sync +# progress with what SHOULD be human-readable numbers. +# +# Does NOT need to be run with sudo (and shouldn't). + +echo "Enter the username for the remote machine: " +read ruser +echo "Enter the hostname (if DNS) or IPv4 address for the remote machine: " +read rhost + +# '-a' preserves attributes like permissions, owner/group, and more, '-v' is +# verbose, '-h' is "human readable", and '-c' compares files to-be synced/ +# transfered, if already existing, by checksum (rather than by filesize or +# modified time). '-e' specifies the remote shell to use, which here is ssh +# '--stats' and '--progress' simply show a lot of info about the file transfers +# '-z' compresses data during the transfer +options="-avhcz -e ssh --stats --progress" + +echo "Delete files at destination not present in source directories? (y/n):" +read del_remote + +if [ "$del_remote" = "y" ]; then # TEST THIS OPTION OUT BEFORE USE!! + # '--delete' deletes files at the destination that are NOT present from the + # source. USE CAREFULLY!! '--force' modifies '--delete' to handle something + # do to with non-empty directories being deleted or overridden, so I'm + # guessing I want it + echo "Extraneous files found in destination will be deleted." + options="$options --delete --force" +elif [ "$del_remote" = "n" ]; then + echo "Extraneous files found in destination will be kept." +else + echo "Error: expected 'y' or 'n' character as input. Aborting for safety..." + exit 1 +fi + + +# Note: as they currently stand, DO NOT add trailing slashes to these +# filenames!! Why? Here is the best explanation I've seen as to how trailing +# slashes work in rsync: +# Without a slash on the source directory means copy both the source +# directory, and the contents (recursively if specified) to the destination +# directory while adding a trailing slash means only copy the contents of +# the source directory, recursively if specified, to the destination. +# TODO: auto-generate paths (or read from textfile) instead of hardcoding +filelist="$HOME/73h4x \ +$HOME/Documents \ +$HOME/Downloads \ +$HOME/OSes \ +$HOME/Library \ +$HOME/Subgenius \ +$HOME/temp" + +# Command structure: +# rsync $options src/dir1 src/dir2... "$ruser"@"$rhost":dest/dir/ + +# copy from here TO a remote destination +rsync $options $filelist "$ruser"@"$rhost":~/ + +# copy from a remote destination TO here (TODO) +
A bin/battery-level.sh

@@ -0,0 +1,4 @@

+#!/bin/sh + +upower -i $(upower -e | grep BAT) | grep -E "state|to\ full|to\ empty|percentage" +
A bin/fsdiff.sh

@@ -0,0 +1,24 @@

+#!/bin/sh + +# Note: this is designed to also work across machines (i.e. remotely). For +# local-only directory comparisons where permissions, mod-times, etc... can be +# ignored, you can actually do this with just 'diff': +# $ diff --recursive --brief DIR1 DIR2 + +if [ "$#" != 2 ]; then + echo "usage: fsdiff.sh [DIR1] [DIR2]" + echo "Compare files from directory DIR2 to directory DIR1" + exit 1 +fi + +# Note: '--itemize-changes' is a useful option sometimes. +# symmetrical diff (compare both directories to one another; differences in +# DIR2 will be preceeded by 'deleted') +rsync_flags="--recursive --links --verbose --checksum --delete --dry-run" +# directional diff (compare DIR2 to contents of DIR1) +#rsync_flags="--recursive --links --verbose --checksum --dry-run" + +#echo "By default, prints files which are different in ${1}" +#echo "'deleting' means the file is different/new in ${2} (not present in ${1})" +rsync $rsync_flags "${1}/" "${2}" +
A bin/gay

@@ -0,0 +1,385 @@

+#!/usr/bin/env python3 + + +from argparse import ArgumentParser, Namespace +from atexit import register +from enum import Enum +from itertools import chain, count, cycle, islice, repeat +from math import pi, sin +from os import environ +from platform import system +from random import choice, randint +from shutil import get_terminal_size +from sys import stdin +from typing import Callable, Dict, Iterator, List, Optional, Tuple, cast +from unicodedata import east_asian_width + + +class ColourSpace(Enum): + EIGHT = "8" + TRUE = "24" + + +class Gradient(Enum): + D1 = "1d" + D2 = "2d" + + +class Flags(Enum): + LES = 1 + GAY = 2 + BI = 3 + TRANS = 4 + ACE = 5 + PAN = 6 + NB = 7 + GQ = 8 + + +HexColour = str +RGB = Tuple[int, int, int] +RawPalette = List[HexColour] +Palette = List[RGB] + +WINDOWS = system() == "Windows" +COLS, ROWS = get_terminal_size((80, 80)) + +UNICODE_WIDTH_LOOKUP = { + "W": 2, # CJK + "N": 0, # Non printable +} + +ASPECT_RATIO = (3, 5) +FLAG_SPECS: Dict[Flags, RawPalette] = { + Flags.LES: ["#D62E02", "#FD9855", "#FFFFFF", "#D161A2", "#A20160"], + Flags.GAY: ["#FF0018", "#FFA52C", "#FFFF41", "#008018", "#0000F9", "#86007D"], + Flags.BI: ["#D60270", "#D60270", "#9B4F96", "#0038A8", "#0038A8"], + Flags.TRANS: ["#55CDFC", "#F7A8B8", "#FFFFFF", "#F7A8B8", "#55CDFC"], + Flags.ACE: ["#000000", "#A4A4A4", "#FFFFFF", "#810081"], + Flags.PAN: ["#FF1B8D", "#FFDA00", "#1BB3FF"], + Flags.NB: ["#FFF430", "#FFFFFF", "#9C59D1", "#000000"], + Flags.GQ: ["#B77FDD", "#FFFFFF", "#48821E"], +} + + +def parse_args() -> Namespace: + rand_flag = choice(tuple(f for f in Flags)) + rand_interpolation = choice(tuple(i.value for i in Gradient)) + colour_space = ( + ColourSpace.TRUE + if environ.get("COLORTERM") in {"truecolor", "24bit"} + else ColourSpace.EIGHT + ) + namespace = Namespace(flag=rand_flag) + parser = ArgumentParser() + + mode_group = parser.add_argument_group() + mode_group.add_argument("-f", "--flag", dest="flag_only", action="store_true") + + flag_group = parser.add_argument_group() + flag_group.add_argument( + "-l", "--les", "--lesbian", action="store_const", dest="flag", const=Flags.LES, + ) + flag_group.add_argument( + "-g", "--gay", action="store_const", dest="flag", const=Flags.GAY, + ) + flag_group.add_argument( + "-b", "--bi", "--bisexual", action="store_const", dest="flag", const=Flags.BI, + ) + flag_group.add_argument( + "-t", + "--trans", + "--transgender", + action="store_const", + dest="flag", + const=Flags.TRANS, + ) + flag_group.add_argument( + "-a", "--ace", "--asexual", action="store_const", dest="flag", const=Flags.ACE, + ) + flag_group.add_argument( + "-p", + "--pan", + "--pansexual", + action="store_const", + dest="flag", + const=Flags.PAN, + ) + flag_group.add_argument( + "-n", "--nb", "--non-binary", action="store_const", dest="flag", const=Flags.NB, + ) + flag_group.add_argument( + "--gq", "--gender-queer", action="store_const", dest="flag", const=Flags.GQ, + ) + + opt_group = parser.add_argument_group() + opt_group.add_argument( + "-c", + "--colour", + choices=tuple(c.value for c in ColourSpace), + default=colour_space.value, + ) + opt_group.add_argument( + "-i", + "--interpolation", + choices=tuple(i.value for i in Gradient), + default=rand_interpolation, + ) + opt_group.add_argument("--period", type=lambda i: max(abs(int(i)), 1)) + opt_group.add_argument( + "--tabs", "--tab-width", type=lambda i: max(abs(int(i)), 1), default=4 + ) + + return parser.parse_args(namespace=namespace) + + +def trap_sig() -> None: + if not WINDOWS: + from signal import SIG_DFL, SIGPIPE, signal + + signal(SIGPIPE, SIG_DFL) + + +def on_exit() -> None: + print("\033[0m", end="", flush=True) + + +def stdin_stream() -> Iterator[str]: + while True: + size = COLS * 4 + line = stdin.read(size) + if line: + yield from line + else: + break + + +def normalize_width(tab_width: int, stream: Iterator[str]) -> Iterator[str]: + for char in stream: + if char == "\t": + yield from repeat(" ", tab_width) + else: + yield char + + +def unicode_width(stream: Iterator[str]) -> Iterator[Tuple[int, str]]: + def char_width(char: str) -> int: + try: + code = east_asian_width(char) + return UNICODE_WIDTH_LOOKUP.get(code, 1) + except Exception: + return 1 + + for char in stream: + yield char_width(char), char + + +def parse_raw_palette(raw: RawPalette) -> Palette: + def parse_colour(colour: HexColour) -> RGB: + hexc = colour[1:] + it = iter(hexc) + parsed = tuple( + int(f"{h1}{h2}", 16) for h1, h2 in iter(lambda: tuple(islice(it, 2)), ()) + ) + return cast(RGB, parsed) + + return [parse_colour(p) for p in raw] + + +DecorateChar = Callable[[RGB], Iterator[str]] +DecorateReset = Callable[[], Iterator[str]] + + +def decor_for(space: ColourSpace) -> Tuple[DecorateChar, DecorateChar, DecorateReset]: + def reset() -> Iterator[str]: + yield "\033[0m" + + def decor_8(rgb: RGB) -> Iterator[str]: + r, g, b = map(lambda c: int(round(c / 255 * 5)), rgb) + yield ";" + yield str(16 + 36 * r + 6 * g + b) + + def decor_24(rgb: RGB) -> Iterator[str]: + yield from chain(*zip(repeat(";"), map(str, rgb))) + + if space == ColourSpace.EIGHT: + + def fg(colour: RGB) -> Iterator[str]: + yield "\033[38;5" + yield from decor_8(colour) + yield "m" + + def bg(colour: RGB) -> Iterator[str]: + yield "\033[48;5" + yield from decor_8(colour) + yield "m" + + return fg, bg, reset + elif space == ColourSpace.TRUE: + + def fg(colour: RGB) -> Iterator[str]: + yield "\033[38;2" + yield from decor_24(colour) + yield "m" + + def bg(colour: RGB) -> Iterator[str]: + yield "\033[48;2" + yield from decor_24(colour) + yield "m" + + return fg, bg, reset + else: + raise ValueError() + + +def paint_flag(colour_space: ColourSpace, palette: Palette) -> Iterator[str]: + r, c = ASPECT_RATIO + _, bg, reset = decor_for(colour_space) + height = len(palette) + ratio = r / c * 0.5 + multiplier = max(int(min((ROWS - 4) / height, COLS / height * ratio)), 1) + line = " " * COLS + for colour in palette: + for _ in range(multiplier): + yield from bg(colour) + yield line + yield from reset() + yield "\n" + + +def enumerate_lines(stream: Iterator[str]) -> Iterator[Tuple[bool, int, str]]: + + l_stream = unicode_width(stream) + prev: Optional[Tuple[int, str]] = next(l_stream, None) + x = 0 if prev is None else 1 + + def drain(ret: bool) -> Iterator[Tuple[bool, int, str]]: + nonlocal prev + if prev is not None: + yield (ret, *prev) + prev = None + + for width, char in l_stream: + new = x + width + if new > COLS: + yield from drain(True) + prev = (width, char) + x = width + elif new == COLS or char == "\n": + yield from drain(False) + yield True, width, char + x = 0 + else: + yield from drain(False) + prev = (width, char) + x = new + + yield from drain(False) + + +def lerp(c1: RGB, c2: RGB, mix: float) -> RGB: + lhs = map(lambda c: c * mix, c1) + rhs = map(lambda c: c * (1 - mix), c2) + new = map(lambda c: int(round(sum(c))), zip(lhs, rhs)) + return cast(RGB, tuple(new)) + + +def sine_wave(t: float) -> float: + period = pi * pi + x = t * period + return (sin(x / pi + pi / 2) + 1) / 2 + + +def interpolate_1d(palette: Palette, rep: int) -> Iterator[Iterator[RGB]]: + colours = cycle(palette) + + def once() -> Iterator[RGB]: + prev = next(colours) + while True: + curr = next(colours) + for t in range(rep + 1): + mix = sine_wave(t / rep) + yield lerp(prev, curr, mix) + prev = curr + + yield from repeat(once()) + + +# contributed by https://github.com/nshepperd +# https://github.com/ms-jpq/gay/issues/2 +def interpolate_2d(palette: Palette, rep: int) -> Iterator[Iterator[RGB]]: + num = len(palette) + + for y in count(): + + def line() -> Iterator[RGB]: + for x in count(): + p = (x + 1.5 * y) / rep + i = int(p) + prev = palette[i % num] + curr = palette[(i + 1) % num] + mix = sine_wave(p - i) + yield lerp(prev, curr, mix) + + yield line() + + +def interpolation_for( + mode: Gradient, palette: Palette, rep: Optional[int] +) -> Iterator[Iterator[RGB]]: + if mode == Gradient.D1: + period = rep or randint(10, 20) + return interpolate_1d(palette, period) + if mode == Gradient.D2: + period = rep or randint(10, 15) + return interpolate_2d(palette, period) + else: + raise ValueError() + + +def colourize( + colour_space: ColourSpace, rgb_gen: Iterator[Iterator[RGB]], stream: Iterator[str], +) -> Iterator[str]: + fg, _, reset = decor_for(colour_space) + colour_gen = next(rgb_gen) + for new_line, width, char in enumerate_lines(stream): + if width: + colour = next(colour_gen) + yield from fg(colour) + yield char + if new_line: + yield from reset() + colour_gen = next(rgb_gen) + + +def main() -> None: + trap_sig() + args = parse_args() + register(on_exit) + colour_space = ColourSpace(args.colour) + palette = parse_raw_palette(FLAG_SPECS[args.flag]) + + if args.flag_only: + flag_stripes = paint_flag(colour_space=colour_space, palette=palette) + print(*flag_stripes, sep="", end="") + else: + stream = stdin_stream() + normalized_stream = normalize_width(args.tabs, stream) + interpolation = Gradient(args.interpolation) + + rgb_gen = interpolation_for( + mode=interpolation, palette=palette, rep=args.period + ) + gen = colourize( + colour_space=colour_space, rgb_gen=rgb_gen, stream=normalized_stream, + ) + for chunk in iter(lambda: tuple(islice(gen, COLS)), ()): + print(*chunk, sep="", end="") + + +try: + main() +except KeyboardInterrupt: + exit(130) +except BrokenPipeError: + exit(13)
A bin/pcsx2

@@ -0,0 +1,1 @@

+/home/x1phosura/opt/PCSX2/pcsx2-v1.7.4675-linux-AppImage-64bit-Qt.AppImage
A bin/qFlipper

@@ -0,0 +1,1 @@

+/home/x1phosura/opt/qFlipper/qFlipper-x86_64-1.3.2.AppImage
A bin/redscript

@@ -0,0 +1,22 @@

+#!/bin/sh + +# redscript: uses redshift to change screen color temperature to reduce blue +# light, set it back to default, or even manually set it. +# x1phosura + +# redshift -P -O <temperature number> +# Note: temperature 1000 - 25000, default is 6500 + +if [ "$1" = "" ]; then + redshift -P -O 6500 # default: revert back to neutral color temperature +elif [ "$1" = "MID" ]; then + redshift -P -O 4200 +elif [ "$1" = "LOW" ]; then + redshift -P -O 3000 +elif [ "$1" = "SET" ]; then + redshift -P -O "$2" # set color temperature manually +else + printf "Options:\n" + printf " <nothing>\n MID\n LOW\n SET <number 1000-25000>\n" +fi +
A bin/scimindent.rkt

@@ -0,0 +1,201 @@

+#! /usr/bin/env racket + +#lang racket/base + +;Dorai Sitaram +;Oct 8, 1999 +;last change 2020-11-14 + +;This script takes lines of Scheme or Lisp code from its +;stdin and produces an indented version thereof on its +;stdout. + +(define *lisp-keywords* '()) + +(define (set-lisp-indent-number sym num-of-subforms-to-be-indented-wide) + (let* ((x (symbol->string sym)) + (c (assf (lambda (a) (string-ci=? x a)) *lisp-keywords*))) + (unless c + (set! c (cons x (box 0))) + (set! *lisp-keywords* (cons c *lisp-keywords*))) + (set-box! (cdr c) num-of-subforms-to-be-indented-wide))) + +(define (read-home-lispwords) + (let ([init-file (or (getenv "LISPWORDS") + (build-path (find-system-path 'home-dir) ".lispwords"))]) + (when (file-exists? init-file) + (call-with-input-file init-file + (lambda (i) + (let loop () + (let ([w (read i)]) + (unless (eof-object? w) + (let ([a (car w)]) + (cond [(number? a) + (for-each (lambda (x) (set-lisp-indent-number x a)) (cdr w))] + [(list? a) + (let ([n (cadr w)]) + (for-each (lambda (x) (set-lisp-indent-number x n)) a))] + [else + (set-lisp-indent-number a (cadr w))])) + (loop))))))))) + +(define (past-next-atom s i n) + (let loop ((i i)) + (if (>= i n) n + (let ((c (string-ref s i))) + (cond ((char=? c #\\) (loop (+ i 2))) + ((memv c '(#\space #\tab #\( #\) #\[ #\] #\" #\' #\` #\, #\;)) + i) + (else (loop (+ i 1)))))))) + +(define (get-lisp-indent-number s) + (let ((c (assf (lambda (a) (string-ci=? s a)) *lisp-keywords*))) + (cond (c (unbox (cdr c))) + ((and (>= (string-length s) 3) + (string-ci=? (substring s 0 3) "def")) 0) + (else -1)))) + +(define (literal-token? s) + (let ((x (let ((i (open-input-string s))) + (begin0 (read i) (close-input-port i))))) + (or (char? x) (number? x) (string? x)))) + +(define (calc-subindent s i n) + (let* ((j (past-next-atom s i n)) + (lisp-indent-num -1) + (delta-indent + (if (= j i) 0 + (let ((w (substring s i j))) + (if (and (>= i 2) + (memv (string-ref s (- i 2)) '(#\' #\`))) + 0 + (begin + (set! lisp-indent-num (get-lisp-indent-number w)) + (case lisp-indent-num + ((-2) 0) + ((-1) (if (< j n) (+ (- j i) 1) 1)) + (else 1)))))))) + (values delta-indent lisp-indent-num j))) + +(define (num-leading-spaces s) + (let ((n (string-length s))) + (let loop ((i 0) (j 0)) + (if (>= i n) 0 + (case (string-ref s i) + ((#\space) (loop (+ i 1) (+ j 1))) + ((#\tab) (loop (+ i 1) (+ j 8))) + (else j)))))) + +(define (string-trim-blanks s) + (let ((n (string-length s))) + (let ((j (let loop ((j 0)) + (if (or (>= j n) + (not (char-whitespace? (string-ref s j)))) + j + (loop (+ j 1)))))) + (if (>= j n) "" + (let ((k (let loop ((k (- n 1))) + (if (or (< k 0) + (not (char-whitespace? (string-ref s k)))) + (+ k 1) + (loop (- k 1)))))) + (substring s j k)))))) + +(define-struct lparen + (spaces-before lisp-indent-num num-finished-subforms) + #:mutable) + +(define (indent-lines) + (let ((default-left-i -1) (left-i 0) (paren-stack '()) (inside-string? #f)) + (let line-loop () + (let ((curr-line (read-line))) + (unless (eof-object? curr-line) + (let* ((leading-spaces (num-leading-spaces curr-line)) + (curr-left-i + (cond (inside-string? leading-spaces) + ((null? paren-stack) + (when (= left-i 0) + (when (= default-left-i -1) + (set! default-left-i leading-spaces)) + (set! left-i default-left-i)) + left-i) + (else (let* ((lp (car paren-stack)) + (lin (lparen-lisp-indent-num lp)) + (nfs (lparen-num-finished-subforms lp)) + (extra-w 0)) + (when (< nfs lin) + (set! extra-w 2)) + (+ (lparen-spaces-before lp) extra-w)))))) + (set! curr-line (string-trim-blanks curr-line)) + (unless (string=? curr-line "") + (do ((i 0 (+ i 1))) + ((= i curr-left-i)) + (write-char #\space)) + (display curr-line)) + (newline) + ; + (let ((n (string-length curr-line)) + (escape? #f) + (token-interstice? #f)) + (let ((incr-finished-subforms (lambda () + (unless token-interstice? + (cond ((and (pair? paren-stack) + (car paren-stack)) => + (lambda (lp) + (let ((nfs (lparen-num-finished-subforms lp))) + (set-lparen-num-finished-subforms! + lp (+ nfs 1)))))) + (set! token-interstice? #t))))) + (let loop ((i 0)) + (unless (>= i n) + (let ((c (string-ref curr-line i))) + (cond (escape? (set! escape? #f) (loop (+ i 1))) + ((char=? c #\\) + (set! token-interstice? #f) + (set! escape? #t) (loop (+ i 1))) + (inside-string? + (when (char=? c #\") + (set! inside-string? #f) + (incr-finished-subforms)) + (loop (+ i 1))) + ((char=? c #\;) + (incr-finished-subforms) + 'break-loop) + ((char=? c #\") + (incr-finished-subforms) + (set! inside-string? #t) + (loop (+ i 1))) + ((memv c '(#\space #\tab)) + (incr-finished-subforms) + (loop (+ i 1))) + ((memv c '(#\( #\[)) + (incr-finished-subforms) + (let-values (((delta-indent lisp-indent-num j) + (calc-subindent curr-line (+ i 1) n))) + (set! paren-stack + (cons (make-lparen (+ 1 i curr-left-i delta-indent) + lisp-indent-num + -1) + paren-stack)) + (set! token-interstice? #t) + (let ((inext (+ i 1))) + (when (> j inext) + (set! inext j) + (set! token-interstice? #f)) + (loop inext)))) + ((memv c '(#\) #\])) + (set! token-interstice? #f) + (cond ((pair? paren-stack) + (set! paren-stack (cdr paren-stack))) + (else (set! left-i 0))) + (loop (+ i 1))) + (else (set! token-interstice? #f) + (loop (+ i 1))))))) + (incr-finished-subforms)))) + (line-loop)))))) + +(read-home-lispwords) + +(indent-lines) + +;eof
A bin/screenshot.sh

@@ -0,0 +1,4 @@

+#!/bin/sh + +grim -g "$(slurp)" "$HOME/Desktop/$(date +%FT%T)_grim.png" +
A bin/start-tor-browser

@@ -0,0 +1,3 @@

+#!/usr/bin/sh + +sh -c '"/home/$USER/tor-browser_en-US/Browser/start-tor-browser" --detach || ([ ! -x "/home/$USER/tor-browser_en-US/Browser/start-tor-browser" ] && "$(dirname "$*")"/Browser/start-tor-browser --detach)' dummy %k
A bin/sync-src-to-dest.sh

@@ -0,0 +1,9 @@

+#!/bin/sh + +if [ ! "$#" = 2 ]; then + echo "Usage: $0 [src-dir/] [dest-dir/]" + exit 1 +fi + +rsync -avhcz -e ssh --stats --progress --delete --force "$1" "$2" +
A bin/tomb

@@ -0,0 +1,3432 @@

+#!/usr/bin/env zsh +# +# Tomb, the Crypto Undertaker +# +# A commandline tool to easily operate encryption of secret data +# + +# {{{ License + +# Copyright (C) 2007-2021 Dyne.org Foundation +# +# Tomb is designed, written and maintained by Denis Roio <jaromil@dyne.org> +# +# Please refer to the AUTHORS file for more information. +# +# This source code is free software; you can redistribute it and/or +# modify it under the terms of the GNU Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This source code is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Please refer +# to the GNU Public License for more details. +# +# You should have received a copy of the GNU Public License along with +# this source code; if not, , see <https://www.gnu.org/licenses/>. + +# }}} - License + +# {{{ Global variables + +typeset VERSION="2.9.0" +typeset DATE="Jan/2021" +typeset TOMBEXEC=$0 +typeset TMPDIR=${${TMPPREFIX%/*}:-/tmp} +# TODO: configure which tmp dir to use from a cli flag + +# Tomb is using some global variables set by the shell: +# TMPPREFIX, UID, GID, PATH, TTY, USERNAME +# You can grep 'global variable' to see where they are used. + +# Keep a reference of the original command line arguments +typeset -a OLDARGS +for arg in "${(@)argv}"; do OLDARGS+=("$arg"); done + +# Special command requirements +typeset -a DD WIPE PINENTRY +DD=(dd) +WIPE=(rm -f) +PINENTRY=(pinentry) + +# load zsh regex module +zmodload zsh/mapfile +zmodload -F zsh/stat b:zstat + +# make sure variables aren't exported +unsetopt allexport + +# Flag optional commands if available (see _ensure_dependencies()) +typeset -i KDF=1 +typeset -i STEGHIDE=1 +typeset -i CLOAKIFY=1 +typeset -i DECLOAKIFY=1 +typeset -i SPHINX=1 +typeset -i RESIZER=1 +typeset -i SWISH=1 +typeset -i QRENCODE=1 + +# Default mount options +typeset MOUNTOPTS="rw,noatime,nodev" + +# Makes glob matching case insensitive +unsetopt CASE_MATCH + +typeset -AH OPTS # Command line options (see main()) + +# Command context (see _whoami()) +typeset -H _USER # Running username +typeset -Hi _UID # Running user identifier +typeset -Hi _GID # Running user group identifier +typeset -H _TTY # Connected input terminal + +# Tomb context (see is_valid_tomb()) +typeset -H TOMBPATH # Full path to the tomb +typeset -H TOMBDIR # Directory where the tomb is +typeset -H TOMBFILE # File name of the tomb +typeset -H TOMBNAME # Name of the tomb + +# Tomb secrets +typeset -H TOMBKEY # Encrypted key contents (see forge_key(), recover_key()) +typeset -H TOMBKEYFILE # Key file (ditto) +typeset -H TOMBSECRET # Raw deciphered key (see forge_key(), gpg_decrypt()) +typeset -H TOMBPASSWORD # Raw tomb passphrase (see gen_key(), ask_key_password()) +typeset -H TOMBTMP # Filename of secure temp just created (see _tmp_create()) + +typeset -aH TOMBTMPFILES # Keep track of temporary files +typeset -aH TOMBLOOPDEVS # Keep track of used loop devices +typeset -A TOMBFILESSTAT # Keep track of access date attributes + +typeset _MSG_FD_OVERRIDE # if set, _msg will write to this file descriptor + +# Make sure sbin is in PATH (man zshparam) +path+=( /sbin /usr/sbin ) + +# For gettext +export TEXTDOMAIN=tomb + +# }}} + +# {{{ Safety functions + +# Wrap sudo with a more visible message +_sudo() { + local msg="[sudo] Enter password for user ::1 user:: to gain superuser privileges" + command -v gettext 1>/dev/null 2>/dev/null && msg="$(gettext -s "$msg")" + msg=${(S)msg//::1*::/$USER} + sudo -p " +$msg + +" ${@} +} + +# Cleanup anything sensitive before exiting. +_endgame() { + + # Restore access time of sensitive files + [[ -z $TOMBFILESSTAT ]] || _restore_stat + + # Prepare some random material to overwrite vars + local rr="$RANDOM" + while [[ ${#rr} -lt 500 ]]; do + rr+="$RANDOM" + done + + # Ensure no information is left in unallocated memory + TOMBPATH="$rr"; unset TOMBPATH + TOMBDIR="$rr"; unset TOMBDIR + TOMBFILE="$rr"; unset TOMBFILE + TOMBNAME="$rr"; unset TOMBNAME + TOMBKEY="$rr"; unset TOMBKEY + TOMBKEYFILE="$rr"; unset TOMBKEYFILE + TOMBSECRET="$rr"; unset TOMBSECRET + TOMBPASSWORD="$rr"; unset TOMBPASSWORD + + # Clear temporary files + for f in $TOMBTMPFILES; do + ${=WIPE} "$f" + done + unset TOMBTMPFILES + + # Detach loop devices + for l in $TOMBLOOPDEVS; do + _sudo losetup -d "$l" + done + unset TOMBLOOPDEVS + +} + +# Trap functions for the _endgame event +TRAPINT() { _endgame INT } +TRAPEXIT() { _endgame EXIT } +TRAPHUP() { _endgame HUP } +TRAPQUIT() { _endgame QUIT } +TRAPABRT() { _endgame ABORT } +TRAPKILL() { _endgame KILL } +TRAPPIPE() { _endgame PIPE } +TRAPTERM() { _endgame TERM } +TRAPSTOP() { _endgame STOP } + +_cat() { local -a _arr; + # read file using mapfile, newline fix + _arr=("${(f@)${mapfile[${1}]%$'\n'}}"); print "$_arr" + } + +_is_found() { + # returns 0 if binary is found in path + [[ -z $1 ]] && return 1 + command -v "$1" 1>/dev/null 2>/dev/null + return $? +} + +# Track acces and modification time of tomb files. +# $1: file to track +# date format: seconds since Epoch +# stat format: <last access>:<last modified> +_track_stat() { + local file="$1" + local stat=$(stat --format="%X:%Y" "$file") + TOMBFILESSTAT+=("$file" "$stat") +} + +# Restore files stats +_restore_stat() { + local file stat + for file stat in "${(@kv)TOMBFILESSTAT}"; do + stats=("${(@s.:.)stat}") + _verbose "Restoring access and modification time for ::1 file::" $file + [[ -z "${stats[1]}" ]] || touch -a --date="@${stats[1]}" "$file" + [[ -z "${stats[2]}" ]] || touch -m --date="@${stats[2]}" "$file" + done +} + +# Identify the running user +# Set global variables _UID, _GID, _TTY, and _USER, either from the +# command line, -U, -G, -T, respectively, or from the environment. +# Also update USERNAME and HOME to maintain consistency. +_whoami() { + + # Set username from UID or environment + _USER=$SUDO_USER + [[ -z $_USER ]] && { _USER=$USERNAME } + [[ -z $_USER ]] && { _USER=$(id -un) } + [[ -z $_USER ]] && { + _failure "Failing to identify the user who is calling us" } + + # Get GID from option -G or the environment + option_is_set -G \ + && _GID=$(option_value -G) || _GID=$(id -g $_USER) + + # Get UID from option -U or the environment + option_is_set -U \ + && _UID=$(option_value -U) || _UID=$(id -u $_USER) + + _verbose "Identified caller: ::1 username:: (::2 UID:::::3 GID::)" $_USER $_UID $_GID + + # Update USERNAME accordingly if possible + # [[ $EUID == 0 && $_USER != $USERNAME ]] && { + # _verbose "Updating USERNAME from '::1 USERNAME::' to '::2 _USER::')" $USERNAME $_USER + # USERNAME=$_USER + # } + + # Force HOME to _USER's HOME if necessary + local home=`_get_home $_USER` + [[ $home == $HOME ]] || { + _verbose "Updating HOME to match user's: ::1 home:: (was ::2 HOME::)" \ + $home $HOME + HOME=$home } + + # Get connecting TTY from option -T or the environment + option_is_set -T && _TTY=$(option_value -T) + [[ -z $_TTY ]] && _TTY=$TTY + +} + +# Provide a random filename in shared memory +_tmp_create() { + [[ -d "$TMPDIR" ]] || { + # we create the tempdir with the sticky bit on + _sudo mkdir -m 1777 "$TMPDIR" + [[ $? == 0 ]] || _failure "Fatal error creating the temporary directory: ::1 temp dir::" "$TMPDIR" + } + + # We're going to add one more $RANDOM for each time someone complains + # about this being too weak of a random. + tfile="${TMPDIR}/$RANDOM$RANDOM$RANDOM$RANDOM" # Temporary file + umask 066 + [[ $? == 0 ]] || { + _failure "Fatal error setting the permission umask for temporary files" } + + [[ -r "$tfile" ]] && { + _failure "Someone is messing up with us trying to hijack temporary files." } + + touch "$tfile" + [[ $? == 0 ]] || { + _failure "Fatal error creating a temporary file: ::1 temp file::" "$tfile" } + + _verbose "Created tempfile: ::1 temp file::" "$tfile" + TOMBTMP="$tfile" + TOMBTMPFILES+=("$tfile") + + return 0 +} + +# Check if a *block* device is encrypted +# Synopsis: _is_encrypted_block /path/to/block/device +# Return 0 if it is an encrypted block device +_is_encrypted_block() { + local b=$1 # Path to a block device + local s="" # lsblk option -s (if available) + + # Issue #163 + # lsblk --inverse appeared in util-linux 2.22 + # but --version is not consistent... + lsblk --help | grep -Fq -- --inverse + [[ $? -eq 0 ]] && s="--inverse" + + sudo lsblk $s -o type -n $b 2>/dev/null \ + | egrep -q '^crypt$' + + return $? +} + +# Check if swap is activated +# Return 0 if NO swap is used, 1 if swap is used. +# Return 1 if any of the swaps is not encrypted. +# Return 2 if swap(s) is(are) used, but ALL encrypted. +# Use _check_swap in functions. It will call this function and +# exit if unsafe swap is present. +_ensure_safe_swap() { + + local -i r=1 # Return code: 0 no swap, 1 unsafe swap, 2 encrypted + local -a swaps # List of swap partitions + local bone is_crypt + + swaps="$(awk '/^\// { print $1 }' /proc/swaps 2>/dev/null)" + [[ -z "$swaps" ]] && return 0 # No swap partition is active + + _message "An active swap partition is detected..." + for s in $=swaps; do + if _is_encrypted_block $s; then + r=2; + else + # We're dealing with unencrypted stuff. + # Maybe it lives on an encrypted filesystem anyway. + # @todo: verify it's actually on an encrypted FS (see #163 and !189) + # Well, no: bail out. + r=1; break; + fi + done + + if [[ $r -eq 2 ]]; then + _success "The undertaker found that all swap partitions are encrypted. Good." + else + _warning "This poses a security risk." + _warning "You can deactivate all swap partitions using the command:" + _warning " swapoff -a" + _warning "[#163] I may not detect plain swaps on an encrypted volume." + _warning "But if you want to proceed like this, use the -f (force) flag." + fi + return $r + +} + +# Wrapper to allow encrypted swap and remind the user about possible +# data leaks to disk if swap is on, which shouldn't be ignored. It could +# be run once in main(), but as swap evolves, it's better to run it +# whenever swap may be needed. +# Exit if unencrypted swap is active on the system. +_check_swap() { + if ! option_is_set -f && ! option_is_set --ignore-swap; then + _ensure_safe_swap + case $? in + 0|2) # No, or encrypted swap + return 0 + ;; + *) # Unencrypted swap + _failure "Operation aborted." + ;; + esac + fi +} + +pinentry_assuan_getpass() { + # simply prints out commands for pinentry's stdin to activate the + # password dialog + cat <<EOF +OPTION ttyname=$TTY +OPTION lc-ctype=$LANG +SETTITLE $title +SETDESC $description +SETPROMPT Password: +GETPIN +EOF +} + +# Ask user for a password +# Wraps around the pinentry command, from the GnuPG project, as it +# provides better security and conveniently use the right toolkit. +ask_password() { + + local description="$1" + local title="${2:-Enter tomb password.}" + local output + local password + local gtkrc + local theme + local pass_asked + + # Distributions have broken wrappers for pinentry: they do + # implement fallback, but they disrupt the output somehow. We are + # better off relying on less intermediaries, so we implement our + # own fallback mechanisms. Pinentry supported: curses, gtk-2, qt4, qt5 + # and x11. + + # make sure LANG is set, default to C + LANG=${LANG:-C} + + _verbose "asking password with tty=$TTY lc-ctype=$LANG" + + pass_asked=0 + + if [[ ! -z $WAYLAND_DISPLAY ]]; then + _verbose "wayland display detected" + _is_found "pinentry-gnome3" && { + _verbose "using pinentry-gnome3 on wayland" + output=$(pinentry_assuan_getpass | pinentry-gnome3) + pass_asked=1 + } + fi + if [[ ! -z $DISPLAY ]] && [[ $pass_asked == 0 ]]; then + _verbose "X11 display detected" + if _is_found "pinentry-gtk-2"; then + _verbose "using pinentry-gtk2" + output=$(pinentry_assuan_getpass | pinentry-gtk-2) + pass_asked=1 + elif _is_found "pinentry-x11"; then + _verbose "using pinentry-x11" + output=$(pinentry_assuan_getpass | pinentry-x11) + pass_asked=1 + elif _is_found "pinentry-gnome3"; then + _verbose "using pinentry-gnome3 on X11" + output=$(pinentry_assuan_getpass | pinentry-gnome3) + pass_asked=1 + elif _is_found "pinentry-qt5"; then + _verbose "using pinentry-qt5" + output=$(pinentry_assuan_getpass | pinentry-qt5) + pass_asked=1 + elif _is_found "pinentry-qt4"; then + _verbose "using pinentry-qt4" + output=$(pinentry_assuan_getpass | pinentry-qt4) + pass_asked=1 + fi + fi + if [[ $pass_asked == 0 ]]; then + _verbose "no display detected" + _is_found "pinentry-curses" && { + _verbose "using pinentry-curses with no display" + output=$(pinentry_assuan_getpass | pinentry-curses) + pass_asked=1 + } + fi + + [[ $pass_asked == 0 ]] && + _failure "Cannot find any pinentry-curses and no DISPLAY detected." + + # parse the pinentry output + local pinentry_error + for i in ${(f)output}; do + [[ "$i" =~ "^ERR.*" ]] && { + pinentry_error="${i[(w)3]}" + } + + # here the password is found + [[ "$i" =~ "^D .*" ]] && password="${i##D }"; + done + + [[ ! -z $pinentry_error ]] && [[ -z $password ]] && { + _warning "Pinentry error: ::1 error::" ${pinentry_error} + print "canceled" + return 1 + } + + # if sphinx mode is chosen, use the provided input + # as master password to retrieve the actual password + if option_is_set --sphx-user || option_is_set --sphx-host; then + password=$(sphinx_get_password "$password") + fi + + [[ -z $password ]] && { + _warning "Empty password" + print "empty" + return 1 + } + + print "$password" + return 0 +} + +# Retrieve PASSWORD from sphinx +# $1 MASTER password for the password store +# requires --sphx-host and --sphx-user flags to be set +sphinx_get_password() { + local errorfile + local password + if option_is_set --sphx-user && option_is_set --sphx-host; then + # value error in sphinx doesn't set exit code + # using tempfile as a workaround to notice the error + errorfile=$(mktemp /tmp/tomb_error.XXXXXXXXX) + password=$(echo "$1" | sphinx get $(option_value --sphx-user) $(option_value --sphx-host) 2>$errorfile) + if ! grep -q "ValueError: fail" $errorfile ; then + echo "$password" + rm $errorfile + return 0 + else + _warning "sphinx returns error: ::1 error::" $(cat $errorfile) + rm $errorfile + _failure "Failed to retrieve actual password with sphinx." + fi + else + _failure "Both host and user have to be set to use sphinx" + fi +} + +# Create PASSWORD in sphinx +# $1 MASTER password for the password store +# requires --sphx-host and --sphx-user flags to be set +sphinx_set_password() { + local errorfile + local password + if option_is_set --sphx-user && option_is_set --sphx-host; then + # value error in sphinx doesn't set exit code + # using tempfile as a workaround to notice the error + errorfile=$(mktemp /tmp/tomb_error.XXXXXXXXX) + # check first if this host/user combination exists in store + # if yes, there is no need to make a call to create + password=$(echo "$1" | sphinx get $(option_value --sphx-user) $(option_value --sphx-host) 2>$errorfile) + if ! grep -q "ValueError: fail" $errorfile ; then + echo "$password" + rm $errorfile + return 0 + fi + # no such host/user combination in store, create one + password=$(echo "$1" | sphinx create $(option_value --sphx-user) $(option_value --sphx-host) ulsd 0 2>$errorfile) + if ! grep -q "ValueError: fail" $errorfile ; then + echo "$password" + rm $errorfile + return 0 + else + _warning "sphinx returns error: ::1 error::" $(cat $errorfile) + rm $errorfile + _failure "Failed to create password with sphinx" + fi + else + _failure "Both host and user have to be set to use sphinx" + fi +} + +# Check if a filename is a valid tomb +is_valid_tomb() { + + _verbose "is_valid_tomb ::1 tomb file::" $1 + + # First argument must be the path to a tomb + [[ ! -z $1 ]] || _failure "Tomb file is missing from arguments." + + local _fail=0 + # Tomb file must be a readable, writable, non-empty regular file. + # If passed the "ro" mount option, the writable check is skipped. + [[ ! -w "$1" ]] && [[ $(option_value -o) != *"ro"* ]] && { + _warning "Tomb file is not writable: ::1 tomb file::" $1 + _fail=1 + } + _verbose "tomb file is readable" + + [[ ! -f "$1" ]] && { + _warning "Tomb file is not a regular file: ::1 tomb file::" $1 + _fail=1 + } + _verbose "tomb file is a regular file" + + [[ ! -s "$1" ]] && { + _warning "Tomb file is empty (zero length): ::1 tomb file::" $1 + _fail=1 + } + _verbose "tomb file is not empty" + + [[ $_fail == 1 ]] && { + _failure "Tomb command failed: ::1 command name::" $subcommand + } + + # Tomb file may be a LUKS FS (or we are creating it) + [[ "`file $1`" =~ "luks encrypted file" ]] || { + _warning "File is not yet a tomb: ::1 tomb file::" $1 } + + # We set global variables + typeset -g TOMBPATH TOMBDIR TOMBFILE TOMBNAME TOMBMAPPER + + TOMBPATH="$1" + + TOMBDIR=$(dirname $TOMBPATH) + + TOMBFILE=$(basename $TOMBPATH) + + # The tomb name is TOMBFILE without an extension and underscores instead of spaces (for mount and cryptsetup) + # It can start with dots: ..foo bar baz.tomb -> ..foo_bar_baz + TOMBNAME=${${TOMBFILE// /_}%.*} + # use the entire filename if the previous transformation returns + # an empty string. This handles the corner case of tomb being + # hidden files (starting with a dot) and have no extension (only + # one dot in string) + TOMBNAME=${TOMBNAME:-${TOMBFILE}} + [[ -z $TOMBNAME ]] && + _failure "Tomb won't work without a TOMBNAME." + + # checks if Tomb already mounted (or we cannot alter it) + local maphash=`realpath $TOMBPATH | sha256sum -z` + local nextloop=`_sudo losetup -f` + TOMBMAPPER="tomb.$TOMBNAME.${maphash[(w)1]}.`basename $nextloop`" + local mounted_tombs=(`list_tomb_mounts`) + local usedmapper + for t in ${mounted_tombs}; do + usedmapper=`basename "${t[(ws:;:)1]}"` + [[ "${usedmapper%.*}" == "${TOMBMAPPER%.*}" ]] && + _failure "Tomb file already in use: ::1 tombname::" $TOMBPATH + done + _verbose "Mapper: ::1 mapper::" $TOMBMAPPER + + _verbose "tomb file is not currently in use" + + _message "Valid tomb file found: ::1 tomb path::" $TOMBPATH + return 0 +} + + +# $1 is the tomb file to be lomounted +lo_mount() { + tpath="$1" + + # check if we have support for loop mounting + TOMBLOOP=`_sudo losetup -f` + [[ $? = 0 ]] || { + _warning "Loop mount of volumes is not possible on this machine, this error" + _warning "often occurs on VPS and kernels that don't provide the loop module." + _warning "It is impossible to use Tomb on this machine under these conditions." + _failure "Operation aborted." + } + + _sudo losetup -f "$tpath" # allocates the next loopback for our file + + TOMBLOOPDEVS+=("$TOMBLOOP") # add to array of lodevs used + return 0 +} + +# print out latest loopback mounted +lo_new() { print - "${TOMBLOOPDEVS[${#TOMBLOOPDEVS}]}" } + +# $1 is the path to the lodev to be preserved after quit +lo_preserve() { + _verbose "lo_preserve on ::1 path::" $1 + # remove the lodev from the tomb_lodevs array + TOMBLOOPDEVS=("${(@)TOMBLOOPDEVS:#$1}") +} + +# eventually used for debugging +dump_secrets() { + print "TOMBPATH: $TOMBPATH" + print "TOMBNAME: $TOMBNAME" + + print "TOMBKEY len: ${#TOMBKEY}" + print "TOMBKEYFILE: $TOMBKEYFILE" + print "TOMBSECRET len: ${#TOMBSECRET}" + print "TOMBPASSWORD: $TOMBPASSWORD" + + print "TOMBTMPFILES: ${(@)TOMBTMPFILES}" + print "TOMBLOOPDEVS: ${(@)TOMBLOOPDEVS}" +} + +# }}} + +# {{{ Commandline interaction + +usage() { + _print "Syntax: tomb [options] command [arguments]" + echo + _print "Commands:" + echo + _print " // Creation:" + _print " dig create a new empty TOMB file of size -s in MiB" + _print " forge create a new KEY file and set its password" + _print " lock installs a lock on a TOMB to use it with KEY" + echo + _print " // Operations on tombs:" + _print " open open an existing TOMB (-k KEY file or - for stdin)" + _print " index update the search indexes of tombs" + _print " search looks for filenames matching text patterns" + _print " list list of open TOMBs and information on them" + _print " ps list of running processes inside open TOMBs" + _print " close close a specific TOMB (or 'all')" + _print " slam slam a TOMB killing all programs using it" + [[ $RESIZER == 1 ]] && { + _print " resize resize a TOMB to a new size -s (can only grow)" + } + echo + _print " // Operations on keys:" + _print " passwd change the password of a KEY (needs old pass)" + _print " setkey change the KEY locking a TOMB (needs old key and pass)" + echo + [[ $QRENCODE == 1 ]] && { + _print " // Backup on paper:" + _print " engrave makes a QR code of a KEY to be saved on paper" + echo + } + [[ $STEGHIDE == 1 || $CLOAKIFY == 1 || $DECLOAKIFY == 1 ]] && { + _print " // Steganography:" + [[ $STEGHIDE == 1 ]] && { + _print " bury hide a KEY inside a JPEG image (for use with -k)" + _print " exhume extract a KEY from a JPEG image (prints to stdout)" + } + [[ $CLOAKIFY == 1 ]] && { + _print " cloak transform a KEY into TEXT using CIPHER (for use with -k)" + } + [[ $DECLOAKIFY == 1 ]] && { + _print " uncloak extract a KEY from a TEXT using CIPHER (prints to stdout)" + } + echo + } + _print "Options:" + echo + _print " -s size of the tomb file when creating/resizing one (in MiB)" + _print " -k path to the key to be used ('-k -' to read from stdin)" + _print " -n don't launch the execution hooks found in tomb" + _print " -p preserve the ownership of all files in tomb" + _print " -o options passed to commands: open, lock, forge (see man)" + _print " -f force operation (i.e. even if swap is active)" + _print " -g use a GnuPG key to encrypt a tomb key" + _print " -r provide GnuPG recipients (separated by comma)" + _print " -R provide GnuPG hidden recipients (separated by comma)" + + [[ $SPHINX == 1 ]] && { + _print " --sphx-user user associated with the key (for use with pitchforkedsphinx)" + _print " --sphx-host host associated with the key (for use with pitchforkedsphinx)" + } + + [[ $KDF == 1 ]] && { + _print " --kdf forge keys armored against dictionary attacks" + } + + echo + _print " -h print this help" + _print " -v print version, license and list of available ciphers" + _print " -q run quietly without printing informations" + _print " -D print debugging information at runtime" + echo + _print "For more information on Tomb read the manual: man tomb" + _print "Please report bugs on <http://github.com/dyne/tomb/issues>." +} + + +# Check whether a commandline option is set. +# +# Synopsis: option_is_set -flag [out] +# +# First argument is the commandline flag (e.g., "-s"). +# If the second argument is present and set to 'out', print out the +# result: either 'set' or 'unset' (useful for if conditions). +# +# Return 0 if is set, 1 otherwise +option_is_set() { + local -i r # the return code (0 = set, 1 = unset) + + [[ -n ${(k)OPTS[$1]} ]]; + r=$? + + [[ $2 == "out" ]] && { + [[ $r == 0 ]] && { print 'set' } || { print 'unset' } + } + + return $r; +} + +# Print the option value matching the given flag +# Unique argument is the commandline flag (e.g., "-s"). +option_value() { + print -n - "${OPTS[$1]}" +} + +# Messaging function with pretty coloring +function _msg() { + local msg="$2" + local i + command -v gettext 1>/dev/null 2>/dev/null && msg="$(gettext -s "$2")" + for i in {3..${#}}; do + msg=${(S)msg//::$(($i - 2))*::/$*[$i]} + done + + local command="print -P" + local progname="${TOMBEXEC##*/}" + local pchars="" + local pcolor="normal" + local fd=2 + local -i returncode + + case "$1" in + inline) + command+=" -n"; pchars=" > "; pcolor="yellow" + ;; + message) + pchars=" . "; pcolor="white" + ;; + verbose) + pchars="[D]"; pcolor="blue" + ;; + success) + pchars="(*)"; pcolor="green" + ;; + warning) + pchars="[W]"; pcolor="yellow" + ;; + failure) + pchars="[E]"; pcolor="red" + returncode=1 + ;; + print) + progname="" + fd=1 + ;; + *) + pchars="[F]"; pcolor="red" + msg="Developer oops! Usage: _msg MESSAGE_TYPE \"MESSAGE_CONTENT\"" + returncode=127 + ;; + esac + + [[ -n $_MSG_FD_OVERRIDE ]] && fd=$_MSG_FD_OVERRIDE + + if [[ -t $fd ]]; then + [[ -n "$progname" ]] && progname="$fg[magenta]$progname$reset_color" + [[ -n "$pchars" ]] && pchars="$fg_bold[$pcolor]$pchars$reset_color" + msg="$fg[$pcolor]$msg$reset_color" + fi + + ${=command} "${progname}" "${pchars}" "${msg}" >&$fd + return $returncode +} + +function _message() { + local notice="message" + [[ "$1" = "-n" ]] && shift && notice="inline" + option_is_set -q || _msg "$notice" $@ + return 0 +} + +function _verbose() { + option_is_set -D && _msg verbose $@ + return 0 +} + +function _success() { + option_is_set -q || _msg success $@ + return 0 +} + +function _warning() { + option_is_set -q || _msg warning $@ + return 1 +} + +function _failure() { + typeset -i exitcode=${exitv:-1} + option_is_set -q || _msg failure $@ + # be sure we forget the secrets we were told + exit $exitcode +} + +function _print() { + option_is_set -q || _msg print $@ + return 0 +} + +_list_optional_tools() { + typeset -a _deps + _deps=(gettext dcfldd shred steghide) + _deps+=(resize2fs tomb-kdb-pbkdf2 qrencode swish-e unoconv lsof) + for d in $_deps; do + _print "`which $d`" + done + return 0 +} + + +# Check program dependencies +# +# Tomb depends on system utilities that must be present, and other +# functionality that can be provided by various programs according to +# what's available on the system. If some required commands are +# missing, bail out. +_ensure_dependencies() { + + # Check for required programs + for req in cryptsetup pinentry sudo gpg mkfs.ext4 e2fsck; do + command -v $req 1>/dev/null 2>/dev/null || { + _failure "Missing required dependency ::1 command::. Please install it." $req; } + done + + # Ensure system binaries are available in the PATH + path+=(/sbin /usr/sbin) # zsh magic + + # Which dd command to use + command -v dcfldd 1>/dev/null 2>/dev/null && DD=(dcfldd statusinterval=1) + + # Which wipe command to use + command -v shred 1>/dev/null 2>/dev/null && WIPE=(shred -f -u) + + # Check for lsof for slamming tombs + command -v lsof 1>/dev/null 2>/dev/null || LSOF=0 + # Check for steghide + command -v steghide 1>/dev/null 2>/dev/null || STEGHIDE=0 + # Check for python2 + command -v python2 -V 1>/dev/null 2>/dev/null || PYTHON2=0 + # Check for cloakify + command -v cloakify 1>/dev/null 2>/dev/null || CLOAKIFY=0 + # Check for decloakify + command -v decloakify 1>/dev/null 2>/dev/null || DECLOAKIFY=0 + # Check for pitchforkedsphinx client + command -v sphinx 1>/dev/null 2>/dev/null || SPHINX=0 + # Check for resize + command -v resize2fs 1>/dev/null 2>/dev/null || RESIZER=0 + # Check for KDF auxiliary tools + command -v tomb-kdb-pbkdf2 1>/dev/null 2>/dev/null || KDF=0 + # Check for Swish-E file content indexer + command -v swish-e 1>/dev/null 2>/dev/null || SWISH=0 + # Check for QREncode for paper backups of keys + command -v qrencode 1>/dev/null 2>/dev/null || QRENCODE=0 +} + +# }}} - Commandline interaction + +# {{{ Key operations + +# $@ is the list of all the recipient used to encrypt a tomb key +is_valid_recipients() { + typeset -a recipients + recipients=($@) + trusted=(m f u w s) + + _verbose "is_valid_recipients" + + # All the keys ID must be valid (the public keys must be present in the database) + for gpg_id in ${recipients[@]}; do + trust="$(gpg --with-colons --batch --list-keys "$gpg_id" 2> /dev/null | + awk 'BEGIN { FS=":" } /^pub/ { print $2; exit}')" + [[ $? != 0 ]] && { + _warning "Not a valid GPG key ID: ::1 gpgid:: " $gpg_id + return 1 + } + [[ ${trusted[(r)$trust]} != $trust ]] && { + _warning "The key ::1 gpgid:: is not trusted enough" $gpg_id + return 1 + } + done + + # At least one private key must be present + for gpg_id in ${recipients[@]}; do + gpg --with-colons --batch --list-secret-keys "$gpg_id" &> /dev/null + [[ $? = 0 ]] && { + return 0 + } + done + + return 1 +} + +# $@ is the list of all the recipient used to encrypt a tomb key +# Print the recipient arg to be used in gpg. +_recipients_arg() { + local arg="$1"; shift + typeset -a recipients + recipients=($@) + + for gpg_id in ${recipients[@]}; do + print -R -n "$arg $gpg_id " + done + return 0 +} + +# $1 is a GPG key recipient +# Print the fingerprint of the GPG key +_gpg_fingerprint() { + gpg --with-colons --fingerprint "$1" | + awk 'BEGIN { FS=":" } /^fpr/ { print $10; exit }' } +_gpg_uid() { + gpg --with-colons --list-key "$1" | + awk 'BEGIN { FS=":" } /^uid/ { print $10; exit}' } + +# helpers to retrieve data from passwd using getent +_get_username() { getent passwd ${1} | awk -F: '{print $1}' } +_get_home() { getent passwd ${1} | awk -F: '{print $6}' } + +# $1 is the encrypted key contents we are checking +is_valid_key() { + local key="$1" # Unique argument is an encrypted key to test + + _verbose "is_valid_key" + + [[ -z $key ]] && key=$TOMBKEY + [[ "$key" = "cleartext" ]] && { + { option_is_set --unsafe } || { + _warning "cleartext key from stdin selected: this is unsafe." + exitv=127 _failure "please use --unsafe if you really want to do this." + } + _warning "received key in cleartext from stdin (unsafe mode)" + return 0 } + + [[ -z $key ]] && { + _warning "is_valid_key() called without an argument." + return 1 + } + + # If the key file is an image don't check file header + [[ -r $TOMBKEYFILE ]] \ + && [[ $(file $TOMBKEYFILE) =~ "JP.G" ]] \ + && { + _message "Key is an image, it might be valid." + return 0 } + + [[ $KDF == 1 ]] && { ! option_is_set -g } && { option_is_set --kdf } && { + _head="${key[(f)1]}" + [[ $_head =~ '^_KDF_' ]] || { + _warning "Key is missing KDF header." + return 1 + } + } + + [[ $key =~ "BEGIN PGP" ]] && { + _message "Key is valid." + return 0 } + + return 1 +} + +# $1 is a string containing an encrypted key +recover_key() { + local key="${1}" # Unique argument is an encrypted key + + _warning "Attempting key recovery." + + _head="${key[(f)1]}" # take the first line + + TOMBKEY="" # Reset global variable + + [[ $_head =~ "^_KDF_" ]] && TOMBKEY+="$_head\n" + + TOMBKEY+="-----BEGIN PGP MESSAGE-----\n" + TOMBKEY+="$key\n" + TOMBKEY+="-----END PGP MESSAGE-----\n" + + return 0 +} + +# Retrieve the tomb key from the file specified from the command line, +# or from stdin if -k - was selected. Run validity checks on the +# file. On success, return 0 and print out the full path of the key. +# Set global variables TOMBKEY and TOMBKEYFILE. +_load_key() { + local keyfile="$1" # Unique argument is an optional keyfile + + [[ -z $keyfile ]] && keyfile=$(option_value -k) + [[ -z $keyfile ]] && { + _failure "This operation requires a key file to be specified using the -k option." } + + if [[ $keyfile == "-" ]]; then + _verbose "load_key reading from stdin." + _message "Waiting for the key to be piped from stdin... " + TOMBKEYFILE=stdin + TOMBKEY=$(cat) + elif [[ $keyfile == "cleartext" ]]; then + _verbose "load_key reading SECRET from stdin" + _message "Waiting for the key to be piped from stdin... " + TOMBKEYFILE=cleartext + TOMBKEY=cleartext + TOMBSECRET=$(cat) + else + _verbose "load_key argument: ::1 key file::" $keyfile + [[ -r $keyfile ]] || _failure "Key not found, specify one using -k." + _track_stat "$keyfile" + TOMBKEYFILE=$keyfile + TOMBKEY="${mapfile[$TOMBKEYFILE]}" + fi + + _verbose "load_key: ::1 key::" $TOMBKEYFILE + + [[ -z $TOMBKEY ]] && { + # something went wrong, there is no key to load + # this occurs especially when piping from stdin and aborted + _failure "Key not found, specify one using -k." + } + + is_valid_key $TOMBKEY || { + _warning "The key seems invalid or its format is not known by this version of Tomb." + recover_key $TOMBKEY + } + + # Declared TOMBKEYFILE (path) + # Declared TOMBKEY (contents) + + return 0 +} + +# takes two args just like get_lukskey +# prints out the decrypted content +# contains tweaks for different gpg versions +# support both symmetric and asymmetric encryption +gpg_decrypt() { + # fix for gpg 1.4.11 where the --status-* options don't work ;^/ + local gpgver=$(gpg --version --no-permission-warning | awk '/^gpg/ {print $3}') + local gpgpass="$1\n$TOMBKEY" + local tmpres ret + typeset -a gpgopt + gpgpopt=(--batch --no-tty --passphrase-fd 0 --no-options) + + { option_is_set -g } && { + gpgpass="$TOMBKEY" + gpgpopt=(--yes) + + # GPG option '--try-secret-key' exist since GPG 2.1 + { option_is_set -R } && { autoload -U is-at-least && is-at-least "2.1" $gpgver } && { + typeset -a recipients + recipients=(${(s:,:)$(option_value -R)}) + { is_valid_recipients $recipients } || { + _failure "You set an invalid GPG ID." + } + gpgpopt+=(`_recipients_arg "--try-secret-key" $recipients`) + } + } + + [[ $gpgver == "1.4.11" ]] && { + _verbose "GnuPG is version 1.4.11 - adopting status fix." + TOMBSECRET=`print - "$gpgpass" | \ + gpg --decrypt ${gpgpopt[@]}` + ret=$? + unset gpgpass + return $ret + } + + _tmp_create + tmpres=$TOMBTMP + TOMBSECRET=`print - "$gpgpass" | \ + gpg --decrypt ${gpgpopt[@]} \ + --status-fd 2 --no-mdc-warning --no-permission-warning \ + --no-secmem-warning 2> $tmpres` + unset gpgpass + ret=1 + for i in ${(f)"$(cat $tmpres)"}; do + _verbose "$i" + [[ "$i" =~ "DECRYPTION_OKAY" ]] && ret=0; + done + return $ret + +} + + +# Gets a key file and a password, prints out the decoded contents to +# be used directly by Luks as a cryptographic key +get_lukskey() { + # $1 is the password + _verbose "get_lukskey" + + _password="$1" + + + firstline="${TOMBKEY[(f)1]}" + + # key is KDF encoded + if [[ $firstline =~ '^_KDF_' ]]; then + kdf_hash="${firstline[(ws:_:)2]}" + _verbose "KDF: ::1 kdf::" "$kdf_hash" + case "$kdf_hash" in + "pbkdf2sha1") + kdf_salt="${firstline[(ws:_:)3]}" + kdf_ic="${firstline[(ws:_:)4]}" + kdf_len="${firstline[(ws:_:)5]}" + _message "Unlocking KDF key protection (::1 kdf::)" $kdf_hash + _verbose "KDF salt: $kdf_salt" + _verbose "KDF ic: $kdf_ic" + _verbose "KDF len: $kdf_len" + _password=$(tomb-kdb-pbkdf2 $kdf_salt $kdf_ic $kdf_len 2>/dev/null <<<$_password) + ;; + *) + _failure "No suitable program for KDF ::1 program::." $pbkdf_hash + unset _password + return 1 + ;; + esac + + # key needs to be exhumed from an image + elif [[ -r $TOMBKEYFILE && $(file $TOMBKEYFILE) =~ "JP.G" ]]; then + if option_is_set -g; then + # When using a GPG key, the tomb key is buried using a steganography password + if option_is_set --tomb-pwd; then + _password="`option_value --tomb-pwd`" + _verbose "tomb-pwd = ::1 tomb pass::" $_password + else + _password=$(ask_password "Insert password to exhume key from $imagefile") + [[ $? != 0 ]] && { + _warning "User aborted password dialog." + return 1 + } + fi + exhume_key $TOMBKEYFILE "$_password" + unset _password + else + exhume_key $TOMBKEYFILE "$_password" + fi + fi + + gpg_decrypt "$_password" # Save decrypted contents into $TOMBSECRET + + ret="$?" + + _verbose "get_lukskey returns ::1::" $ret + return $ret +} + +# This function asks the user for the password to use the key it tests +# it against the return code of gpg on success returns 0 and saves +# the password in the global variable $TOMBPASSWORD +ask_key_password() { + [[ -z "$TOMBKEYFILE" ]] && { + _failure "Internal error: ask_key_password() called before _load_key()." } + + [[ "$TOMBKEYFILE" = "cleartext" ]] && { + _verbose "no password needed, using secret bytes from stdin" + return 0 } + + if option_is_set -g; then + _verbose "no password needed, using GPG key" + get_lukskey + return $? + fi + + _message "A password is required to use key ::1 key::" $TOMBKEYFILE + passok=0 + tombpass="" + if [[ -z $1 ]]; then + + for c in 1 2 3; do + if [[ $c == 1 ]]; then + tombpass=$(ask_password "Insert password to: $TOMBKEYFILE") + else + tombpass=$(ask_password "Insert password to: $TOMBKEYFILE (attempt $c)") + fi + [[ $? = 0 ]] || { + _warning "User aborted password dialog." + return 1 + } + + get_lukskey "$tombpass" + + [[ $? = 0 ]] && { + passok=1; _message "Password OK." + break; + } + done + + else + # if a second argument is present then the password is already known + tombpass="$1" + _verbose "ask_key_password with tombpass: ::1 tomb pass::" $tombpass + + # if sphinx mode is chosen, use the provided input + # as master password to retrieve the actual password + if option_is_set --sphx-user || option_is_set --sphx-host; then + tombpass=$(sphinx_get_password "$tombpass") + fi + + get_lukskey "$tombpass" + + [[ $? = 0 ]] && { + passok=1; _message "Password OK." + } + + fi + [[ $passok == 1 ]] || return 1 + + TOMBPASSWORD=$tombpass + return 0 +} + +# call cryptsetup with arguments using the currently known secret +# echo flags eliminate newline and disable escape (BSD_ECHO) +_cryptsetup() { + print -R -n - "$TOMBSECRET" | _sudo cryptsetup --type luks1 --key-file - ${@} + return $? +} + +# change tomb key password +change_passwd() { + local tmpnewkey lukskey c tombpass tombpasstmp + + _check_swap # Ensure swap is secure, if any + _load_key # Try loading key from option -k and set TOMBKEYFILE + + { option_is_set -g } && { + _message "Commanded to change GnuPG key for tomb key ::1 key::" $TOMBKEYFILE + } || { + _message "Commanded to change password for tomb key ::1 key::" $TOMBKEYFILE + } + + _tmp_create + tmpnewkey=$TOMBTMP + + if option_is_set --tomb-old-pwd; then + local tomboldpwd="`option_value --tomb-old-pwd`" + _verbose "tomb-old-pwd = ::1 old pass::" $tomboldpwd + ask_key_password "$tomboldpwd" + else + ask_key_password + fi + [[ $? == 0 ]] || _failure "No valid password supplied." + + { option_is_set -g } && { + _success "Changing GnuPG key for ::1 key file::" $TOMBKEYFILE + } || { + _success "Changing password for ::1 key file::" $TOMBKEYFILE + } + + # Here $TOMBSECRET contains the key material in clear + + { option_is_set --tomb-pwd } && { + local tombpwd="`option_value --tomb-pwd`" + _verbose "tomb-pwd = ::1 new pass::" $tombpwd + gen_key "$tmpnewkey" "$tombpwd" + } || { + gen_key "$tmpnewkey" + } + + { is_valid_key "${mapfile[$tmpnewkey]}" } || { + _failure "Error: the newly generated keyfile does not seem valid." } + + # Copy the new key as the original keyfile name + cp -f "${tmpnewkey}" $TOMBKEYFILE + { option_is_set -g } && { + _success "Your GnuPG key was successfully changed" + } || { + _success "Your passphrase was successfully updated." + } + + return 0 +} + + +# takes care to encrypt a key +# honored options: --kdf --tomb-pwd -o -g -r +gen_key() { + # $1 key file + # $2 the password to use; if not set ask user + # -o is the --cipher-algo to use (string taken by GnuPG) + local algopt="`option_value -o`" + local algo="${algopt:-AES256}" + local gpgpass opt + local recipients_opt + typeset -a gpgopt + local sphx_host_tmp + local sphx_user_tmp + # here user is prompted for key password + tombpass="" + tombpasstmp="" + + # remove sphinx opts not to mess with initial password prompt + option_is_set --sphx-user && { + sphx_user_tmp="$(option_value --sphx-user)" + unset "OPTS[--sphx-user]" + } + option_is_set --sphx-host && { + sphx_host_tmp="$(option_value --sphx-host)" + unset "OPTS[--sphx-host]" + } + + if option_is_set -g; then + gpgopt=(--encrypt) + + if option_is_set -r || option_is_set -R; then + typeset -a recipients + if option_is_set -r; then + recipients=(${(s:,:)$(option_value -r)}) + recipients_opt="--recipient" + else + recipients=(${(s:,:)$(option_value -R)}) + recipients_opt="--hidden-recipient" + fi + + is_valid_recipients $recipients || { + _failure "You set an invalid GPG ID." + } + + _warning "You are going to encrypt a tomb key with ::1 nrecipients:: recipient(s)." ${#recipients} + _warning "It is your responsibility to check these fingerprints." + _warning "The fingerprints are:" + for gpg_id in ${recipients[@]}; do + _warning " `_gpg_fingerprint "$gpg_id"` :: `_gpg_uid "$gpg_id"`" + done + + gpgopt+=(`_recipients_arg "$recipients_opt" $recipients`) + else + _message "No recipient specified, using default GPG key." + gpgopt+=("--default-recipient-self") + fi + + # Set gpg inputs and options + gpgpass="$TOMBSECRET" + opt='' + else + if [ "$2" = "" ]; then + while true; do + # 3 tries to write two times a matching password + tombpass=`ask_password "Type the new password to secure your key"` + if [[ $? != 0 ]]; then + _failure "User aborted." + fi + if [ -z $tombpass ]; then + _failure "You set empty password, which is not possible." + fi + tombpasstmp=$tombpass + tombpass=`ask_password "Type the new password to secure your key (again)"` + if [[ $? != 0 ]]; then + _failure "User aborted." + fi + if [ "$tombpasstmp" = "$tombpass" ]; then + break; + fi + unset tombpasstmp + unset tombpass + done + else + tombpass="$2" + _verbose "gen_key takes tombpass from CLI argument: ::1 tomb pass::" $tombpass + fi + + # if sphinx mode is chosen, use the provided input + # as master password to generate the actual password + if [[ ! -z $sphx_host_tmp ]] || [[ ! -z $sphx_user_tmp ]]; then + OPTS[--sphx-user]=$sphx_user_tmp + OPTS[--sphx-host]=$sphx_host_tmp + unset sphx_user_tmp + unset sphx_host_tmp + tombpass=$(sphinx_set_password "$tombpass") + if [[ $? != 0 ]]; then + _failure "User aborted." + fi + fi + + header="" + [[ $KDF == 1 ]] && { + { option_is_set --kdf } && { + # KDF is a new key strenghtening technique against brute forcing + # see: https://github.com/dyne/Tomb/issues/82 + itertime="`option_value --kdf`" + # removing support of floating points because they can't be type checked well + if [[ "$itertime" != <-> ]]; then + unset tombpass + unset tombpasstmp + _warning "Wrong argument for --kdf: must be an integer number (iteration seconds)." + _failure "Depending on the speed of machines using this tomb, use 1 to 10, or more" + return 1 + fi + # --kdf takes one parameter: iter time (on present machine) in seconds + local -i microseconds + microseconds=$(( itertime * 1000000 )) + _success "Using KDF, iteration time: ::1 microseconds::" $microseconds + _message "generating salt" + pbkdf2_salt=`tomb-kdb-pbkdf2-gensalt` + _message "calculating iterations" + pbkdf2_iter=`tomb-kdb-pbkdf2-getiter $microseconds` + _message "encoding the password" + # We use a length of 64bytes = 512bits (more than needed!?) + tombpass=`tomb-kdb-pbkdf2 $pbkdf2_salt $pbkdf2_iter 64 <<<"${tombpass}"` + + header="_KDF_pbkdf2sha1_${pbkdf2_salt}_${pbkdf2_iter}_64\n" + } + } + print $header >> "$1" + + # Set gpg inputs and options + gpgpass="${tombpass}\n$TOMBSECRET" + gpgopt=(--passphrase-fd 0 --symmetric --no-options) + opt='-n' + fi + + _tmp_create + local tmpres=$TOMBTMP + print $opt - "$gpgpass" \ + | gpg --openpgp --force-mdc --cipher-algo ${algo} \ + --batch --no-tty ${gpgopt} \ + --status-fd 2 -o - --armor 2> $tmpres >> "$1" + unset gpgpass + # check result of gpg operation + for i in ${(f)"$(cat $tmpres)"}; do + _verbose "$i" + done + + # print -n "${tombpass}" \ + # | gpg --openpgp --force-mdc --cipher-algo ${algo} \ + # --batch --no-options --no-tty --passphrase-fd 0 --status-fd 2 \ + # -o - -c -a ${lukskey} + + TOMBPASSWORD="$tombpass" # Set global variable + unset tombpass + unset tombpasstmp +} + +# prints an array of ciphers available in gnupg (to encrypt keys) +list_gnupg_ciphers() { + # On gpg1 and gpg2 line 10 always point to available ciphers. + # Print those until the next section is found + ciphers=(`gpg --version | awk ' +BEGIN { ciphers=0 } +NR==11 { gsub(/,/,""); sub(/^.*:/,""); print; ciphers=1; next } +/^.*:/ { ciphers=0 } +{ if(ciphers==0) { next } else { gsub(/,/,""); print; } } +'`) + print "${ciphers}" + return 1 +} + +# Steganographic function to bury a key inside an image. +# Requires steghide(1) to be installed +bury_key() { + + _load_key # Try loading key from option -k and set TOMBKEY + + imagefile=$PARAM + + [[ "`file $imagefile`" =~ "JPEG" ]] || { + _warning "Encode failed: ::1 image file:: is not a jpeg image." $imagefile + return 1 + } + + _success "Encoding key ::1 tomb key:: inside image ::2 image file::" $TOMBKEY $imagefile + { option_is_set -g } && { + _message "Using GnuPG Key ID" + } || { + _message "Please confirm the key password for the encoding" + } + + # We ask the password and test if it is the same encoding the + # base key, to insure that the same password is used for the + # encryption and the steganography. This is a standard enforced + # by Tomb, but it isn't strictly necessary (and having different + # password would enhance security). Nevertheless here we prefer + # usability. + # However, steganography cannot be done with GPG key. Therefore, + # if using a GPG key, we test if the user can decrypt the tomb + # with its key and we ask for a steganography password. + + { option_is_set --tomb-pwd } && { ! option_is_set -g } && { + local tombpwd="`option_value --tomb-pwd`" + _verbose "tomb-pwd = ::1 tomb pass::" $tombpwd + ask_key_password "$tombpwd" + } || { + ask_key_password + } + [[ $? != 0 ]] && { + _warning "Wrong password/GnuPG ID supplied." + _failure "You shall not bury a key whose password is unknown to you." } + + if option_is_set -g && option_is_set --tomb-pwd; then + TOMBPASSWORD="`option_value --tomb-pwd`" + _verbose "tomb-pwd = ::1 tomb pass::" $TOMBPASSWORD + elif option_is_set -g; then + tombpass="" + tombpasstmp="" + while true; do + # 3 tries to write two times a matching password + tombpass=`ask_password "Type a password to bury your key"` + if [[ $? != 0 ]]; then + _failure "User aborted." + fi + if [ -z $tombpass ]; then + _failure "You set empty password, which is not possible." + fi + tombpasstmp=$tombpass + tombpass=`ask_password "Type a password to bury your key (again)"` + if [[ $? != 0 ]]; then + _failure "User aborted." + fi + if [ "$tombpasstmp" = "$tombpass" ]; then + break; + fi + unset tombpasstmp + unset tombpass + done + TOMBPASSWORD="$tombpass" + fi + + # We omit armor strings since having them as constants can give + # ground to effective attacks on steganography + print - "$TOMBKEY" | awk ' +/^-----/ {next} +/^Version/ {next} +{print $0}' \ + | steghide embed --embedfile - --coverfile ${imagefile} \ + -p $TOMBPASSWORD -z 9 -e serpent cbc + if [ $? != 0 ]; then + _warning "Encoding error: steghide reports problems." + res=1 + else + _success "Tomb key encoded succesfully into image ::1 image file::" $imagefile + res=0 + fi + + return $res +} + +# mandatory 1st arg: the image file where key is supposed to be +# optional 2nd arg: the password to use (same as key, internal use) +# optional 3rd arg: the key where to save the result (- for stdout) +exhume_key() { + [[ -z $1 ]] && { + _failure "Exhume failed, no image specified" } + + local imagefile="$1" # The image file where to look for the key + local tombpass="$2" # (Optional) the password to use (internal use) + local destkey="$3" # (Optional) the key file where to save the + # result (- for stdout) + local r=1 # Return code (default: fail) + + # write all messages to stderr to avoid polluting stdout + _MSG_FD_OVERRIDE=2 + + # Ensure the image file is a readable JPEG + [[ ! -r $imagefile ]] && { + _failure "Exhume failed, image file not found: ::1 image file::" "${imagefile:-none}" } + [[ ! $(file "$imagefile") =~ "JP.G" ]] && { + _failure "Exhume failed: ::1 image file:: is not a jpeg image." $imagefile } + + # When a password is passed as argument then always print out + # the exhumed key on stdout without further checks (internal use) + [[ -n "$tombpass" ]] && { + TOMBKEY=$(steghide extract -sf $imagefile -p $tombpass -xf -) + [[ $? != 0 ]] && { + _failure "Wrong password or no steganographic key found" } + + recover_key $TOMBKEY + + return 0 + } + + # Ensure we have a valid destination for the key + [[ -z $destkey ]] && { option_is_set -k } && destkey=$(option_value -k) + [[ -z $destkey ]] && { + destkey="-" # No key was specified: fallback to stdout + _message "printing exhumed key on stdout" } + + # Bail out if destination exists, unless -f (force) was passed + [[ $destkey != "-" && -s $destkey ]] && { + _warning "File exists: ::1 tomb key::" $destkey + { option_is_set -f } && { + _warning "Use of --force selected: overwriting." + rm -f $destkey + } || { + _warning "Make explicit use of --force to overwrite." + _failure "Refusing to overwrite file. Operation aborted." } + } + + _message "Trying to exhume a key out of image ::1 image file::" $imagefile + { option_is_set --tomb-pwd } && { + tombpass=$(option_value --tomb-pwd) + _verbose "tomb-pwd = ::1 tomb pass::" $tombpass + } || { + [[ -n $TOMBPASSWORD ]] && tombpass=$TOMBPASSWORD + } || { + tombpass=$(ask_password "Insert password to exhume key from $imagefile") + [[ $? != 0 ]] && { + _warning "User aborted password dialog." + return 1 + } + } + + # Extract the key from the image + steghide extract -sf $imagefile -p ${tombpass} -xf $destkey + r=$? + + # Report to the user + [[ "$destkey" = "-" ]] && destkey="stdout" + [[ $r == 0 ]] && { + _success "Key succesfully exhumed to ::1 key::." $destkey + } || { + _warning "Nothing found in ::1 image file::" $imagefile + } + + unset _MSG_FD_OVERRIDE + + return $r +} + +# Steganographic function to transform a key into harmless-looking text +# using a cipher +# Requires cloakify to be installed +# +# mandatory 1st arg: the cipher to use +# optional 2nd arg: the output file where to save the result (none for stdout) +cloakify_key() { + + _load_key # Try loading key from option -k and set TOMBKEY + + local cipher="$1" # The cipher to use + local destfile="$2" # (Optional) the output file where to save the + # result (none for stdout) + + _success "Encoding key ::1 tomb key:: using cipher ::2 cipher file::" $TOMBKEYFILE $cipher + + # Ensure we have a valid destination for the cloaked key + [[ -z $destfile ]] && { + destfile="/dev/stdout" # No file was specified: fallback to stdout + _message "printing cloaked key on stdout" } + + # Bail out if destination exists, unless -f (force) was passed + [[ $destfile != "/dev/stdout" && -s $destfile ]] && { + _warning "File exists: ::1 output file::" $destfile + { option_is_set -f } && { + _warning "Use of --force selected: overwriting." + rm -f $destfile + } || { + _warning "Make explicit use of --force to overwrite." + _failure "Refusing to overwrite file. Operation aborted." } + } + + # Cipher the key + cloakify $TOMBKEYFILE $cipher >$destfile + if [ $? != 0 ]; then + _warning "Encoding error: cloakify reports problems." + res=1 + else + _success "Tomb key encoded succesfully" + res=0 + fi + + return $res +} + +# mandatory 1st arg: the text file where key is supposed to be +# mandatory 2nd arg: the cipher to use +# optional 3rd arg: the key where to save the result (none for stdout) +decloakify_key() { + [[ -z $1 ]] && { + _failure "Uncloak failed, no text file specified" } + [[ -z $2 ]] && { + _failure "Uncloak failed, no cipher file specified" } + + local textfile="$1" # The text file where to look for the key + local cipher="$2" # The cipher to use + local destkey="$3" # (Optional) the key file where to save the + # result (none for stdout) + local r=1 # Return code (default: fail) + + # write all messages to stderr to avoid polluting stdout + _MSG_FD_OVERRIDE=2 + + # Ensure the text file is readable + [[ ! -r $textfile ]] && { + _failure "Uncloak failed, text file not found: ::1 text file::" "${textfile:-none}" } + # Ensure the cipher file is readable + [[ ! -r $cipher ]] && { + _failure "Uncloak failed, cipher file not found: ::1 cipher file::" "${cipher:-none}" } + + # Ensure we have a valid destination for the key + [[ -z $destkey ]] && { option_is_set -k } && destkey=$(option_value -k) + [[ -z $destkey ]] && { + destkey="/dev/stdout" # No key was specified: fallback to stdout + _message "printing uncloaked key on stdout" } + + # Bail out if destination exists, unless -f (force) was passed + [[ $destkey != "/dev/stdout" && -s $destkey ]] && { + _warning "File exists: ::1 tomb key::" $destkey + { option_is_set -f } && { + _warning "Use of --force selected: overwriting." + rm -f $destkey + } || { + _warning "Make explicit use of --force to overwrite." + _failure "Refusing to overwrite file. Operation aborted." } + } + + # Extract the key from the text file + decloakify $textfile $cipher >$destkey + r=$? + + # Report to the user + [[ "$destkey" = "/dev/stdout" ]] && destkey="stdout" + [[ $r == 0 ]] && { + _success "Key succesfully uncloaked to ::1 key::." $destkey + } || { + _warning "Nothing found in ::1 text file::" $textfile + } + + unset _MSG_FD_OVERRIDE + + return $r +} + +# Produces a printable image of the key contents so a backup on paper +# can be made and hidden in books etc. +engrave_key() { + + _load_key # Try loading key from option -k and set TOMBKEYFILE + + local keyname=$(basename $TOMBKEYFILE) + local pngname="$keyname.qr.png" + + _success "Rendering a printable QRCode for key: ::1 tomb key file::" $TOMBKEYFILE + # we omit armor strings to save space + awk '/^-----/ {next}; /^Version/ {next}; {print $0}' $TOMBKEYFILE \ + | qrencode --size 4 --level H --casesensitive -o $pngname + [[ $? != 0 ]] && { + _failure "QREncode reported an error." } + + _success "Operation successful:" + # TODO: only if verbose and/or not silent + ls -lh $pngname + file $pngname +} + +# }}} - Key handling + +# {{{ Create + +# Since version 1.5.3, tomb creation is a three-step process that replaces create_tomb(): +# +# * dig a .tomb (the large file) using /dev/urandom (takes some minutes at least) +# +# * forge a .key (the small file) using /dev/random (good entropy needed) +# +# * lock the .tomb file with the key, binding the key to the tomb (requires dm_crypt format) + +# Step one - Dig a tomb +# +# Synopsis: dig_tomb /path/to/tomb -s sizemebibytes +# +# It will create an empty file to be formatted as a loopback +# filesystem. Initially the file is filled with random data taken +# from /dev/urandom to improve overall tomb's security and prevent +# some attacks aiming at detecting how much data is in the tomb, or +# which blocks in the filesystem contain that data. + +dig_tomb() { + # $1 arg is path to tomb + + # Require the specification of the size of the tomb (-s) in MiB + local -i tombsize=$(option_value -s) + + _message "Commanded to dig tomb ::1 tomb path::" $tombpath + + [[ ! -z $1 ]] || _failure "Missing path to tomb" + [[ -n "$tombsize" ]] || _failure "Size argument missing, use -s" + [[ $tombsize == <-> ]] || _failure "Size must be an integer (mebibytes)" + [[ $tombsize -ge 10 ]] || _failure "Tombs can't be smaller than 10 mebibytes" + + [[ -e $1 ]] && { + _warning "A tomb exists already. I'm not digging here:" + ls -lh $1 + return 1 + } + + _success "Creating a new tomb in ::1 tomb path::" $1 + _message "Generating ::1 tomb file:: of ::2 size::MiB" $1 $tombsize + + touch "$1" + [[ $? = 0 ]] || { + _warning "Error creating the tomb ::1 tomb path::" $1 + _failure "Operation aborted." + } + # Ensure that file permissions are safe even if interrupted + [[ -n $SUDO_USER ]] && chown ${_UID}:${_GID} "$1" + chmod 0600 $1 + _verbose "Data dump using ::1:: from /dev/urandom" ${DD[1]} + ${=DD} if=/dev/urandom bs=1048576 count=$tombsize of=$1 + ls -lh "$1" + + _success "Done digging ::1 tomb name::" $1 + _message "Your tomb is not yet ready, you need to forge a key and lock it:" + _message "tomb forge ::1 tomb path::.key" $1 + _message "tomb lock ::1 tomb path:: -k ::1 tomb path::.key" $1 + + return 0 +} + +# Step two -- Create a detached key to lock a tomb with +# +# Synopsis: forge_key [destkey|-k destkey] [-o cipher] [-r|-R gpgid] +# +# Arguments: +# -k path to destination keyfile +# -o Use an alternate algorithm +# -r GPG recipients to be used +# +forge_key() { + # can be specified both as simple argument or using -k + local destkey="$1" + { option_is_set -k } && { destkey=$(option_value -k) } + + local algo="AES256" # Default encryption algorithm + + [[ -z "$destkey" ]] && { + _failure "A filename needs to be specified using -k to forge a new key." } + + # _message "Commanded to forge key ::1 key::" $destkey + + _check_swap # Ensure the available memory is safe to use + + # Ensure GnuPG won't exit with an error before first run + local gpghome=${GNUPGHOME:-$HOME/.gnupg} + [[ -r $gpghome/pubring.gpg ]] || { + mkdir -p -m 0700 $gpghome + touch $gpghome/pubring.gpg } + + # Do not overwrite any files accidentally + [[ -r "$destkey" ]] && { + ls -lh $destkey + _failure "Forging this key would overwrite an existing file. Operation aborted." } + + touch $destkey + [[ $? == 0 ]] || { + _warning "Cannot generate encryption key." + _failure "Operation aborted." } + chmod 0600 $destkey + + # Update algorithm if it was passed on the command line with -o + { option_is_set -o } && algopt="$(option_value -o)" + [[ -n "$algopt" ]] && algo=$algopt + + _message "Commanded to forge key ::1 key:: with cipher algorithm ::2 algorithm::" \ + $destkey $algo + + [[ $KDF == 1 ]] && { ! option_is_set -g } && { + _message "Using KDF to protect the key password (`option_value --kdf` rounds)" + } + + TOMBKEYFILE="$destkey" # Set global variable + + _warning "This operation takes time. Keep using this computer on other tasks." + _warning "Once done you will be asked to choose a password for your tomb." + _warning "To make it faster you can move the mouse around." + _warning "If you are on a server, you can use an Entropy Generation Daemon." + + # Use /dev/urandom as the entropy source, unless --use-random is specified + local random_source=/dev/urandom + { option_is_set --use-random } && random_source=/dev/random + + _verbose "Data dump using ::1:: from ::2 source::" ${DD[1]} $random_source + TOMBSECRET=$(${=DD} bs=1 count=512 if=$random_source) + [[ $? == 0 ]] || { + _warning "Cannot generate encryption key." + _failure "Operation aborted." } + + # Here the global variable TOMBSECRET contains the naked secret + + { option_is_set -g } && { + _success "Using GnuPG key(s) to encrypt your key: ::1 tomb key::" $TOMBKEYFILE + } || { + _success "Choose the password of your key: ::1 tomb key::" $TOMBKEYFILE + } + _message "(You can also change it later using 'tomb passwd'.)" + # _user_file $TOMBKEYFILE + + tombname="$TOMBKEYFILE" # XXX ??? + # the gen_key() function takes care of the new key's encryption + { option_is_set --tomb-pwd } && { + local tombpwd="`option_value --tomb-pwd`" + _verbose "tomb-pwd = ::1 new pass::" $tombpwd + gen_key $TOMBKEYFILE "$tombpwd" + } || { + gen_key $TOMBKEYFILE + } + + # load the key contents (set global variable) + TOMBKEY="${mapfile[$TOMBKEYFILE]}" + + # this does a check on the file header + is_valid_key $TOMBKEY || { + _warning "The key does not seem to be valid." + _warning "Dumping contents to screen:" + print "${mapfile[$TOMBKEY]}" + _warning "--" + rm -f ${TOMBKEYFILE} + _failure "Operation aborted." + } + + [[ -n $SUDO_USER ]] && chown ${_UID}:${_GID} "$TOMBKEYFILE" + _message "Done forging ::1 key file::" $TOMBKEYFILE + _success "Your key is ready:" + ls -lh $TOMBKEYFILE +} + +# Step three -- Lock tomb +# +# Synopsis: tomb_lock file.tomb file.tomb.key [-o cipher] [-r gpgid] +# +# Lock the given tomb with the given key file, in fact formatting the +# loopback volume as a LUKS device. +# Default cipher 'aes-xts-plain64'can be overridden with -o +lock_tomb_with_key() { + # old default was aes-cbc-essiv:sha256 + # Override with -o + # for more alternatives refer to cryptsetup(8) + local cipher="aes-xts-plain64" + + local tombpath="$1" # First argument is the path to the tomb + + [[ -n $tombpath ]] || { + _warning "No tomb specified for locking." + _warning "Usage: tomb lock file.tomb -k file.tomb.key" + return 1 + } + + + is_valid_tomb $tombpath + + _message "Commanded to lock tomb ::1 tomb file::" $TOMBFILE + + [[ -f $TOMBPATH ]] || { + _failure "There is no tomb here. You have to dig it first." } + + _verbose "Tomb found: ::1 tomb path::" $TOMBPATH + + local filesystem=ext4 + option_is_set --filesystem && { + filesystem=`option_value --filesystem` + case $filesystem in + ext3|ext4) ;; + btrfs) ;; + *) + _failure "Filesystem not supported: ::1 filesystem::" $filesystem + return 1 + ;; + esac + # TODO: check validity, only ext3 or 4 or btrfs support + _message "Selected filesystem type $filesystem." + } + + lo_mount $TOMBPATH + + _verbose "Loop mounted on ::1 mount point::" $TOMBLOOP + + _message "Checking if the tomb is empty (we never step on somebody else's bones)." + _sudo cryptsetup isLuks ${TOMBLOOP} + if [ $? = 0 ]; then + # is it a LUKS encrypted nest? then bail out and avoid reformatting it + _warning "The tomb was already locked with another key." + _failure "Operation aborted. I cannot lock an already locked tomb. Go dig a new one." + else + _message "Fine, this tomb seems empty." + fi + + _load_key # Try loading key from option -k and set TOMBKEYFILE + + # the encryption cipher for a tomb can be set when locking using -c + { option_is_set -o } && algopt="$(option_value -o)" + [[ -n "$algopt" ]] && cipher=$algopt + _message "Locking using cipher: ::1 cipher::" $cipher + + # get the pass from the user and check it + if option_is_set --tomb-pwd; then + tomb_pwd="`option_value --tomb-pwd`" + _verbose "tomb-pwd = ::1 tomb pass::" $tomb_pwd + ask_key_password "$tomb_pwd" + else + ask_key_password + fi + [[ $? == 0 ]] || _failure "No valid password supplied." + + _success "Locking ::1 tomb file:: with ::2 tomb key file::" $TOMBFILE $TOMBKEYFILE + + _message "Formatting Luks mapped device." + _cryptsetup --batch-mode \ + --cipher ${cipher} --hash sha512 --key-size 512 --key-slot 0 \ + luksFormat ${TOMBLOOP} + [[ $? == 0 ]] || { + _warning "cryptsetup luksFormat returned an error." + _failure "Operation aborted." } + + _cryptsetup --cipher ${cipher} --hash sha512 luksOpen ${TOMBLOOP} tomb.tmp + [[ $? == 0 ]] || { + _warning "cryptsetup luksOpen returned an error." + _failure "Operation aborted." } + + _message "Formatting your Tomb with $filesystem filesystem." + case $filesystem in + ext3|ext4) + _sudo mkfs.${filesystem} -q -F -j -L $TOMBNAME /dev/mapper/tomb.tmp + ;; + btrfs) # TODO: cover with test + _sudo mkfs.${filesystem} -q -L $TOMBNAME /dev/mapper/tomb.tmp + ;; + esac + + [[ $? == 0 ]] || { + _warning "Tomb format returned an error." + _sudo cryptsetup luksClose tomb.tmp + _failure "Your tomb ::1 tomb file:: may be corrupted." $TOMBFILE } + + # Sync + _sudo cryptsetup luksClose tomb.tmp + + _message "Done locking ::1 tomb name:: using Luks dm-crypt ::2 cipher::" $TOMBNAME $cipher + _success "Your tomb is ready in ::1 tomb path:: and secured with key ::2 tomb key::" \ + $TOMBPATH $TOMBKEYFILE + return 0 +} + +# This function changes the key that locks a tomb +change_tomb_key() { + local tombkey="$1" # Path to the tomb's key file + local tombpath="$2" # Path to the tomb + + _message "Commanded to reset key for tomb ::1 tomb path::" $tombpath + + [[ -z "$tombpath" ]] && { + _warning "Command 'setkey' needs two arguments: the old key file and the tomb." + _warning "I.e: tomb -k new.tomb.key old.tomb.key secret.tomb" + _failure "Execution aborted." + } + + _check_swap + + is_valid_tomb $tombpath + + lo_mount $TOMBPATH + + _sudo cryptsetup isLuks ${TOMBLOOP} + # is it a LUKS encrypted nest? we check one more time + [[ $? == 0 ]] || { + _failure "Not a valid LUKS encrypted volume: ::1 volume::" $TOMBPATH } + + _load_key $tombkey # Try loading given key and set TOMBKEY + + + # TOMBKEYFILE + local oldkey=$TOMBKEY + local oldkeyfile=$TOMBKEYFILE + + # we have everything, prepare to mount + _success "Changing lock on tomb ::1 tomb name::" $TOMBNAME + _message "Old key: ::1 old key::" $oldkeyfile + + # load the old key + if option_is_set --tomb-old-pwd; then + tomb_old_pwd="`option_value --tomb-old-pwd`" + _verbose "tomb-old-pwd = ::1 old pass::" $tomb_old_pwd + ask_key_password "$tomb_old_pwd" + else + ask_key_password + fi + [[ $? == 0 ]] || { + _failure "No valid password supplied for the old key." } + old_secret=$TOMBSECRET + + # luksOpen the tomb (not really mounting, just on the loopback) + print -R -n - "$old_secret" | _sudo cryptsetup --key-file - \ + luksOpen ${TOMBLOOP} ${TOMBMAPPER} + [[ $? == 0 ]] || _failure "Unexpected error in luksOpen." + + _load_key # Try loading new key from option -k and set TOMBKEYFILE + + _message "New key: ::1 key file::" $TOMBKEYFILE + + if option_is_set --tomb-pwd; then + tomb_new_pwd="`option_value --tomb-pwd`" + _verbose "tomb-pwd = ::1 tomb pass::" $tomb_new_pwd + ask_key_password "$tomb_new_pwd" + else + ask_key_password + fi + [[ $? == 0 ]] || { + _failure "No valid password supplied for the new key." } + + _tmp_create + tmpnewkey=$TOMBTMP + print -R -n - "$TOMBSECRET" >> $tmpnewkey + + print -R -n - "$old_secret" | _sudo cryptsetup --key-file - \ + luksChangeKey "$TOMBLOOP" "$tmpnewkey" + + [[ $? == 0 ]] || _failure "Unexpected error in luksChangeKey." + + _sudo cryptsetup luksClose "${TOMBMAPPER}" || _failure "Unexpected error in luksClose." + + _success "Succesfully changed key for tomb: ::1 tomb file::" $TOMBFILE + _message "The new key is: ::1 new key::" $TOMBKEYFILE + + return 0 +} + +# }}} - Creation + +# {{{ Open + +_update_control_file() { + # make sure a control file exists, gives it user ownership + # and replaces it with new contents + # stdin = contents + # $1 = path to control file + # $2 = contents + [[ -z $2 ]] && return 1 + _sudo touch "$1" + _sudo chown ${_UID}:${_GID} "$1" + print "$2" > "$1" + _verbose "updated control file $1 = $2" +} + +_detect_filesystem() { + local device=$1 + _verbose "detecting filesystem of ::1 device::" $device + print "`lsblk -in -o FSTYPE $device`" +} + +# $1 = tombfile $2(optional) = mountpoint +mount_tomb() { + [[ -n "$1" ]] || _failure "No tomb name specified for opening." + + _message "Commanded to open tomb ::1 tomb name::" $1 + + _check_swap + + is_valid_tomb $1 + + _track_stat "$TOMBPATH" + + _load_key # Try loading new key from option -k and set TOMBKEYFILE + + tombmount="$2" + [[ -z $tombmount ]] && { + tombmount=/media/$TOMBNAME + [[ -d /media ]] || { # no /media found, adopting /run/media/$USER (udisks2 compat) + tombmount=/run/media/$_USER/$TOMBNAME + } + _message "Mountpoint not specified, using default: ::1 mount point::" $tombmount + } + + _success "Opening ::1 tomb file:: on ::2 mount point::" $TOMBNAME $tombmount + + # check if the mountpoint is already used + mounted_tombs=(`list_tomb_mounts`) + for t in ${mounted_tombs}; do + usedmount=${t[(ws:;:)2]} + [[ "$usedmount" == "$tombmount" ]] && + _failure "Mountpoint already in use: ::1 mount point::" $tombmount + done + + lo_mount $TOMBPATH + + _sudo cryptsetup isLuks ${TOMBLOOP} || { + # is it a LUKS encrypted nest? see cryptsetup(1) + _failure "::1 tomb file:: is not a valid Luks encrypted storage file." $TOMBFILE } + + _message "This tomb is a valid LUKS encrypted device." + + luksdump="`_sudo cryptsetup luksDump ${TOMBLOOP}`" + tombdump=(`print $luksdump | awk ' + /^Cipher name/ {print $3} + /^Cipher mode/ {print $3} + /^Hash spec/ {print $3}'`) + _message "Cipher is \"::1 cipher::\" mode \"::2 mode::\" hash \"::3 hash::\"" $tombdump[1] $tombdump[2] $tombdump[3] + + slotwarn=`print $luksdump | awk ' + BEGIN { zero=0 } + /^Key slot 0/ { zero=1 } + /^Key slot.*ENABLED/ { if(zero==1) print "WARN" }'` + [[ "$slotwarn" == "WARN" ]] && { + _warning "Multiple key slots are enabled on this tomb. Beware: there can be a backdoor." } + + _verbose "Tomb key: ::1 key file::" $TOMBKEYFILE + + # take the name only, strip extensions + _verbose "Tomb name: ::1 tomb name:: (to be engraved)" $TOMBNAME + + { option_is_set --tomb-pwd } && { ! option_is_set -g } && { + tomb_pwd="`option_value --tomb-pwd`" + _verbose "tomb-pwd = ::1 tomb pass::" $tomb_pwd + ask_key_password "$tomb_pwd" + } || { + ask_key_password + } + [[ $? == 0 ]] || _failure "No valid password supplied." + + _cryptsetup luksOpen ${TOMBLOOP} ${TOMBMAPPER} + [[ $? = 0 ]] || { + _failure "Failure mounting the encrypted file." } + + # preserve the loopdev after exit + lo_preserve "$TOMBLOOP" + + # array: [ cipher, keysize, loopdevice ] + tombstat=(`_sudo cryptsetup status ${TOMBMAPPER} | awk ' + /cipher:/ {print $2} + /keysize:/ {print $2} + /device:/ {print $2}'`) + _success "Success unlocking tomb ::1 tomb name::" $TOMBNAME + _verbose "Key size is ::1 size:: for cipher ::2 cipher::" $tombstat[2] $tombstat[1] + + filesystem=`_detect_filesystem /dev/mapper/${TOMBMAPPER}` + _message "Filesystem detected: ::1 filesystem::" $filesystem + # TODO: check if FS is supported, else close luks and loop + + _verbose "Tomb engraved as ::1 tomb name::" $TOMBNAME + + _message "Checking filesystem via ::1::" $tombstat[3] + case $filesystem in + ext3|ext4) + _sudo fsck -p -C0 /dev/mapper/${TOMBMAPPER} + # TODO: btrfs filesystem label [<device>|<mount_point>] [<newlabel>] + _sudo tune2fs -L $TOMBNAME /dev/mapper/${TOMBMAPPER} > /dev/null + ;; + btrfs) + _sudo btrfs check /dev/mapper/${TOMBMAPPER} + _sudo btrfs filesystem label /dev/mapper/${TOMBMAPPER} ${TOMBNAME} + ;; + esac + + # we need root from here on + _sudo mkdir -p $tombmount + + # Default mount options are overridden with the -o switch + { option_is_set -o } && { + local oldmountopts=$MOUNTOPTS + MOUNTOPTS="$(option_value -o)" } + # TODO: safety check MOUNTOPTS + # safe_mount_options && + _sudo mount -o $MOUNTOPTS /dev/mapper/${TOMBMAPPER} ${tombmount} + # Clean up if the mount failed + [[ $? == 0 ]] || { + _warning "Error mounting ::1 mapper:: on ::2 tombmount::" $TOMBMAPPER $tombmount + [[ $oldmountopts != $MOUNTOPTS ]] && \ + _warning "Are mount options '::1 mount options::' valid?" $MOUNTOPTS + # TODO: move cleanup to _endgame() + [[ -d $tombmount ]] && _sudo rmdir $tombmount + [[ -e /dev/mapper/$TOMBMAPPER ]] && _sudo cryptsetup luksClose $TOMBMAPPER + # The loop is taken care of in _endgame() + _failure "Cannot mount ::1 tomb name::" $TOMBNAME + } + + _success "Success opening ::1 tomb file:: on ::2 mount point::" $TOMBFILE $tombmount + + local tombtty tombhost tombuid tombuser + + # print out when it was opened the last time, by whom and where + [[ -r ${tombmount}/.last ]] && { + tombsince=$(_cat ${tombmount}/.last) + tombsince=$(date --date=@$tombsince +%c) + tombtty=$(_cat ${tombmount}/.tty) + tombhost=$(_cat ${tombmount}/.host) + tomblast=$(_cat ${tombmount}/.last) + tombuid=$(_cat ${tombmount}/.uid | tr -d ' ') + + tombuser=`_get_username $tombuid` + + _message "Last visit by ::1 user::(::2 tomb build::) from ::3 tty:: on ::4 host::" $tombuser $tombuid $tombtty $tombhost + _message "on date ::1 date::" $tombsince + } + + # write down the UID and TTY that opened the tomb + _update_control_file ${tombmount}/.uid $_UID + _update_control_file ${tombmount}/.tty $_TTY + # also the hostname + _update_control_file ${tombmount}/.host `hostname` + # and the "last time opened" information + # in minutes since 1970, this is printed at next open + _update_control_file ${tombmount}/.last `date +%s` + # human readable: date --date=@"`cat .last`" +%c + + # process bind-hooks (mount -o bind of directories) + # and exec-hooks (execute on open) + option_is_set -n || { + exec_safe_bind_hooks ${tombmount} + exec_safe_func_hooks open ${tombmount} + } + + # Changes ownership to current user. This facilitates a lot + # usability by single users. If a Tomb is "multiuser" and contains + # ACL "by convention" using UNIX ownership that needs to be + # preserved then this behavior can be deactivated using -p + option_is_set -p || _sudo chown -R ${_UID}:${_GID} ${tombmount} + + return 0 +} + +## HOOKS EXECUTION +# +# Execution of code inside a tomb may present a security risk, e.g., +# if the tomb is shared or compromised, an attacker could embed +# malicious code. When in doubt, open the tomb with the -n switch in +# order to skip this feature and verify the files mount-hooks and +# bind-hooks inside the tomb yourself before letting them run. + +# Mount files and directories from the tomb to the current user's HOME. +# +# Synopsis: exec_safe_bind_hooks /path/to/mounted/tomb +# +# This can be a security risk if you share tombs with untrusted people. +# In that case, use the -n switch to turn off this feature. +exec_safe_bind_hooks() { + local mnt="$1" # First argument is the mount point of the tomb + + # Default mount options are overridden with the -o switch + [[ -n ${(k)OPTS[-o]} ]] && MOUNTOPTS=${OPTS[-o]} + + # No HOME set? Note: this should never happen again. + [[ -z $HOME ]] && { + _warning "How pitiful! A tomb, and no HOME." + return 1 } + + [[ -z $mnt || ! -d $mnt ]] && { + _warning "Cannot exec bind hooks without a mounted tomb." + return 1 } + + [[ -r "$mnt/bind-hooks" ]] || { + _verbose "bind-hooks not found in ::1 mount point::" $mnt + return 0 } + + typeset -Al maps # Maps of files and directories to mount + typeset -al mounted # Track already mounted files and directories + + # better parsing for bind hooks checks for two separated words on + # each line, using zsh word separator array subscript + _bindhooks="${mapfile[${mnt}/bind-hooks]}" + for h in ${(f)_bindhooks}; do + s="${h[(w)1]}" + d="${h[(w)2]}" + [[ -z $s ]] && { _warning "bind-hooks file is broken"; return 1 } + [[ -z $d ]] && { _warning "bind-hooks file is broken"; return 1 } + maps+=($s $d) + _verbose "bind-hook found: $s -> $d" + done + unset _bindhooks + + for dir in ${(k)maps}; do + [[ "${dir[1]}" == "/" || "${dir[1,2]}" == ".." ]] && { + _warning "bind-hooks map format: local/to/tomb local/to/\$HOME" + continue } + + [[ "${${maps[$dir]}[1]}" == "/" || "${${maps[$dir]}[1,2]}" == ".." ]] && { + _warning "bind-hooks map format: local/to/tomb local/to/\$HOME. Rolling back" + for dir in ${mounted}; do _sudo umount $dir; done + return 0 } + + if [[ ! -r "$HOME/${maps[$dir]}" ]]; then + _warning "bind-hook target not existent, skipping ::1 home::/::2 subdir::" $HOME ${maps[$dir]} + elif [[ ! -r "$mnt/$dir" ]]; then + _warning "bind-hook source not found in tomb, skipping ::1 mount point::/::2 subdir::" $mnt $dir + else + _sudo mount -o bind,$MOUNTOPTS $mnt/$dir $HOME/${maps[$dir]} \ + && mounted+=("$HOME/${maps[$dir]}") + fi + done +} + +# Execute automated actions configured in the tomb. +# +# Synopsis: exec_safe_func_hooks /path/to/mounted/tomb +# +# If an executable file named 'exec-hooks' is found inside the tomb, +# run it as a user. This might need a dialog for security on what is +# being run, however we expect you know well what is inside your tomb. +# If you're mounting an untrusted tomb, be safe and use the -n switch +# to verify what it would run if you let it. This feature opens the +# possibility to make encrypted executables. +exec_safe_func_hooks() { + local mnt + mnt="$2" + # Only run if post-hooks has the executable bit set + [[ -x $mnt/exec-hooks ]] && { + _success "Exec hook: ::1 exec hook:: ::2 action::" \ + "${mnt}/exec-hooks" "$1" + # here call two actions: open or close. Synopsis: + # $1 $2 $3 $4 $5 + # open "$tombmount" + # close "$tombmount" "$tombname" "$tombloop" "$TOMBMAPPER" + $mnt/exec-hooks "$1" "$2" "$3" "$4" "$5" + return $? + } + return 0 +} + +# }}} - Tomb open + +# {{{ List + +# list all tombs mounted in a readable format +# $1 is optional, to specify a tomb +list_tombs() { + + local tombname tombmount tombfs tombfsopts tombloop + local ts tombtot tombused tombavail tombpercent tombp tombsince + local tombtty tombhost tombuid tombuser + # list all open tombs + mounted_tombs=(`list_tomb_mounts $1`) + [[ ${#mounted_tombs} == 0 ]] && { + _failure "I can't see any ::1 status:: tomb, may they all rest in peace." ${1:-open} } + + for t in ${mounted_tombs}; do + mapper=`basename ${t[(ws:;:)1]}` + tombname=${t[(ws:;:)5]} + tombmount=${t[(ws:;:)2]} + tombfs=${t[(ws:;:)3]} + tombfsopts=${t[(ws:;:)4]} + tombloop=${mapper[(ws:.:)4]} + + # calculate tomb size + ts=`df -hP /dev/mapper/$mapper | +awk "/mapper/"' { print $2 ";" $3 ";" $4 ";" $5 }'` + tombtot=${ts[(ws:;:)1]} + tombused=${ts[(ws:;:)2]} + tombavail=${ts[(ws:;:)3]} + tombpercent=${ts[(ws:;:)4]} + tombp=${tombpercent%%%} + + # obsolete way to get the last open date from /dev/mapper + # which doesn't work when tomb filename contain dots + # tombsince=`date --date=@${mapper[(ws:.:)3]} +%c` + + # find out who opens it from where + [[ -r ${tombmount}/.tty ]] && { + tombsince=$(_cat ${tombmount}/.last) + tombsince=$(date --date=@$tombsince +%c) + tombtty=$(_cat ${tombmount}/.tty) + tombhost=$(_cat ${tombmount}/.host) + tombuid=$(_cat ${tombmount}/.uid | tr -d ' ') + + tombuser=`_get_username $tombuid` + } + + { option_is_set --get-mountpoint } && { print $tombmount; continue } + + _message "::1 tombname:: open on ::2 tombmount:: using ::3 tombfsopts::" \ + $tombname $tombmount $tombfsopts + + _verbose "::1 tombname:: /dev/::2 tombloop:: device mounted (detach with losetup -d)" $tombname $tombloop + + _message "::1 tombname:: open since ::2 tombsince::" $tombname $tombsince + + [[ -z "$tombtty" ]] || { + _message "::1 tombname:: open by ::2 tombuser:: from ::3 tombtty:: on ::4 tombhost::" \ + $tombname $tombuser $tombtty $tombhost + } + + _message "::1 tombname:: size ::2 tombtot:: of which ::3 tombused:: (::5 tombpercent::%) is used: ::4 tombavail:: free " \ + $tombname $tombtot $tombused $tombavail $tombpercent + + [[ ${tombp} -ge 90 ]] && { + _warning "::1 tombname:: warning: your tomb is almost full!" $tombname + } + + # Now check hooks + mounted_hooks=(`list_tomb_binds $tombname $tombmount`) + for h in ${mounted_hooks}; do + _message "::1 tombname:: hooks ::2 hookdest::" \ + $tombname ${h[(ws:;:)2]} + done + done + return 0 +} + + +# Print out an array of mounted tombs (internal use) +# Format is semi-colon separated list of attributes +# if 1st arg is supplied, then list only that tomb +# +# String positions in the semicolon separated array: +# +# 1. full mapper path +# +# 2. mountpoint +# +# 3. filesystem type +# +# 4. mount options +# +# 5. tomb name +list_tomb_mounts() { + [[ -z "$1" ]] && { + # list all open tombs + _sudo findmnt -rvo SOURCE,TARGET,FSTYPE,OPTIONS,LABEL \ + | awk ' +BEGIN { main="" } +/^\/dev\/mapper\/tomb/ { + if(main==$1) next; + print $1 ";" $2 ";" $3 ";(" $4 ");[" $5 "]" + main=$1 +} +' + } || { + # list a specific tomb + # add square parens if not present (detection) + local tname + if [[ "${1[1]}" = "[" ]]; then tname="$1" + else tname="[$1]"; fi + _sudo findmnt -rvo SOURCE,TARGET,FSTYPE,OPTIONS,LABEL \ + | awk -vtomb="$tname" ' +BEGIN { main="" } +/^\/dev\/mapper\/tomb/ { + if("["$5"]"!=tomb) next; + if(main==$1) next; + print $1 ";" $2 ";" $3 ";(" $4 ");[" $5 "]" + main=$1 +} +' + } +} + +# list_tomb_binds +# print out an array of mounted bind hooks (internal use) +# format is semi-colon separated list of attributes +# needs two arguments: name of tomb whose hooks belong +# mount tomb +list_tomb_binds() { + [[ -z "$2" ]] && { + _failure "Internal error: list_tomb_binds called without argument." } + + # much simpler than the crazy from before + # in fact, the second parameter is now redundant + # as we only need the tomb name + + # note that this code assumes that the tomb name is provided in square brackets + + _sudo findmnt -ro SOURCE,TARGET,FSTYPE,OPTIONS,LABEL \ + | grep -F "/dev/mapper/tomb" \ + | awk -vpattern="$1" ' +BEGIN { } +{ + if("["$5"]"!=pattern) next; + if(index($1,"[")==0) next; + gsub("[[][^]]*[]]","",$1); + print $1 ";" $2 ";" $3 ";(" $4 ");[" $5 "]" +} +' +} + +# }}} - Tomb list + +# {{{ Index and search + +# index files in all tombs for search +# $1 is optional, to specify a tomb +index_tombs() { + { command -v updatedb 1>/dev/null 2>/dev/null } || { + _failure "Cannot index tombs on this system: updatedb (mlocate) not installed." } + + updatedbver=`updatedb --version | grep '^updatedb'` + [[ "$updatedbver" =~ "GNU findutils" ]] && { + _warning "Cannot use GNU findutils for index/search commands." } + [[ "$updatedbver" =~ "mlocate" ]] || { + _failure "Index command needs 'mlocate' to be installed." } + + _verbose "$updatedbver" + + mounted_tombs=(`list_tomb_mounts $1`) + [[ ${#mounted_tombs} == 0 ]] && { + # Considering one tomb + [[ -n "$1" ]] && { + _failure "There seems to be no open tomb engraved as [::1::]" $1 } + # Or more + _failure "I can't see any open tomb, may they all rest in peace." } + + _success "Creating and updating search indexes." + + # start the LibreOffice document converter if installed + { command -v unoconv 1>/dev/null 2>/dev/null } && { + unoconv -l 2>/dev/null & + _verbose "unoconv listener launched." + sleep 1 } + + for t in ${mounted_tombs}; do + mapper=`basename ${t[(ws:;:)1]}` + tombname=${t[(ws:;:)5]} + tombmount=${t[(ws:;:)2]} + [[ -r ${tombmount}/.noindex ]] && { + _message "Skipping ::1 tomb name:: (.noindex found)." $tombname + continue } + _message "Indexing ::1 tomb name:: filenames..." $tombname + updatedb -l 0 -o ${tombmount}/.updatedb -U ${tombmount} + + # here we use swish to index file contents + [[ $SWISH == 1 ]] && { + _message "Indexing ::1 tomb name:: contents..." $tombname + rm -f ${tombmount}/.swishrc + _message "Generating a new swish-e configuration file: ::1 swish conf::" ${tombmount}/.swishrc + cat <<EOF > ${tombmount}/.swishrc +# index directives +DefaultContents TXT* +IndexDir $tombmount +IndexFile $tombmount/.swish +# exclude images +FileRules filename regex /\.jp.?g/i +FileRules filename regex /\.png/i +FileRules filename regex /\.gif/i +FileRules filename regex /\.tiff/i +FileRules filename regex /\.svg/i +FileRules filename regex /\.xcf/i +FileRules filename regex /\.eps/i +FileRules filename regex /\.ttf/i +# exclude audio +FileRules filename regex /\.mp3/i +FileRules filename regex /\.ogg/i +FileRules filename regex /\.wav/i +FileRules filename regex /\.mod/i +FileRules filename regex /\.xm/i +# exclude video +FileRules filename regex /\.mp4/i +FileRules filename regex /\.avi/i +FileRules filename regex /\.ogv/i +FileRules filename regex /\.ogm/i +FileRules filename regex /\.mkv/i +FileRules filename regex /\.mov/i +FileRules filename regex /\.flv/i +FileRules filename regex /\.webm/i +# exclude system +FileRules filename is ok +FileRules filename is lock +FileRules filename is control +FileRules filename is status +FileRules filename is proc +FileRules filename is sys +FileRules filename is supervise +FileRules filename regex /\.asc$/i +FileRules filename regex /\.gpg$/i +# pdf and postscript +FileFilter .pdf pdftotext "'%p' -" +FileFilter .ps ps2txt "'%p' -" +# compressed files +FileFilterMatch lesspipe "%p" /\.tgz$/i +FileFilterMatch lesspipe "%p" /\.zip$/i +FileFilterMatch lesspipe "%p" /\.gz$/i +FileFilterMatch lesspipe "%p" /\.bz2$/i +FileFilterMatch lesspipe "%p" /\.Z$/ +# spreadsheets +FileFilterMatch unoconv "-d spreadsheet -f csv --stdout %P" /\.xls.*/i +FileFilterMatch unoconv "-d spreadsheet -f csv --stdout %P" /\.xlt.*/i +FileFilter .ods unoconv "-d spreadsheet -f csv --stdout %P" +FileFilter .ots unoconv "-d spreadsheet -f csv --stdout %P" +FileFilter .dbf unoconv "-d spreadsheet -f csv --stdout %P" +FileFilter .dif unoconv "-d spreadsheet -f csv --stdout %P" +FileFilter .uos unoconv "-d spreadsheet -f csv --stdout %P" +FileFilter .sxc unoconv "-d spreadsheet -f csv --stdout %P" +# word documents +FileFilterMatch unoconv "-d document -f txt --stdout %P" /\.doc.*/i +FileFilterMatch unoconv "-d document -f txt --stdout %P" /\.odt.*/i +FileFilterMatch unoconv "-d document -f txt --stdout %P" /\.rtf.*/i +FileFilterMatch unoconv "-d document -f txt --stdout %P" /\.tex$/i +# native html support +IndexContents HTML* .htm .html .shtml +IndexContents XML* .xml +EOF + + swish-e -c ${tombmount}/.swishrc -S fs -v3 + } + _message "Search index updated." + done + return 0 +} + +search_tombs() { + { command -v locate 1>/dev/null 2>/dev/null } || { + _failure "Cannot index tombs on this system: updatedb (mlocate) not installed." } + + updatedbver=`updatedb --version | grep '^updatedb'` + [[ "$updatedbver" =~ "GNU findutils" ]] && { + _warning "Cannot use GNU findutils for index/search commands." } + [[ "$updatedbver" =~ "mlocate" ]] || { + _failure "Index command needs 'mlocate' to be installed." } + + _verbose "$updatedbver" + + # list all open tombs + mounted_tombs=(`list_tomb_mounts`) + [[ ${#mounted_tombs} == 0 ]] && { + _failure "I can't see any open tomb, may they all rest in peace." } + + _success "Searching for: ::1::" ${(f)@} + for t in ${mounted_tombs}; do + _verbose "Checking for index: ::1::" ${t} + mapper=`basename ${t[(ws:;:)1]}` + tombname=${t[(ws:;:)5]} + tombmount=${t[(ws:;:)2]} + [[ -r ${tombmount}/.updatedb ]] && { + # Use mlocate to search hits on filenames + _message "Searching filenames in tomb ::1 tomb name::" $tombname + locate -d ${tombmount}/.updatedb -e -i "${(f)@}" + _message "Matches found: ::1 matches::" \ + $(locate -d ${tombmount}/.updatedb -e -i -c ${(f)@}) + + # Use swish-e to search over contents + [[ $SWISH == 1 && -r $tombmount/.swish ]] && { + _message "Searching contents in tomb ::1 tomb name::" $tombname + swish-e -w ${@} -f $tombmount/.swish -H0 } + } || { + _warning "Skipping tomb ::1 tomb name::: not indexed." $tombname + _warning "Run 'tomb index' to create indexes." } + done + _message "Search completed." + return 0 +} + +# }}} - Index and search + +# {{{ Resize + +# resize tomb file size +resize_tomb() { + local tombpath="$1" # First argument is the path to the tomb + + _message "Commanded to resize tomb ::1 tomb name:: to ::2 size:: mebibytes." $1 $OPTS[-s] + + [[ -z "$1" ]] && _failure "No tomb name specified for resizing." + [[ ! -r "$1" ]] && _failure "Cannot find ::1::" $1 + + newtombsize="`option_value -s`" + [[ -z "$newtombsize" ]] && { + _failure "Aborting operations: new size was not specified, use -s" } + + is_valid_tomb $tombpath + + _load_key # Try loading new key from option -k and set TOMBKEYFILE + + if option_is_set --tomb-pwd; then + tomb_pwd="`option_value --tomb-pwd`" + _verbose "tomb-pwd = ::1 tomb pass::" $tomb_pwd + ask_key_password "$tomb_pwd" + else + ask_key_password + fi + [[ $? == 0 ]] || _failure "No valid password supplied." + + local oldtombsize=$(( `stat -c %s "$TOMBPATH" 2>/dev/null` / 1048576 )) + + # New tomb size must be specified + [[ -n "$newtombsize" ]] || { + _failure "You must specify the new size of ::1 tomb name::" $TOMBNAME } + # New tomb size must be an integer + [[ $newtombsize == <-> ]] || _failure "Size is not an integer." + + # Tombs can only grow in size + if [[ "$newtombsize" -gt "$oldtombsize" ]]; then + + delta="$(( $newtombsize - $oldtombsize ))" + + _message "Generating ::1 tomb file:: of ::2 size::MiB" $TOMBFILE $newtombsize + + _verbose "Data dump using ::1:: from /dev/urandom" ${DD[1]} + ${=DD} if=/dev/urandom bs=1048576 count=${delta} >> $TOMBPATH + [[ $? == 0 ]] || { + _failure "Error creating the extra resize ::1 size::, operation aborted." \ + $tmp_resize } + + # If same size this allows to re-launch resize if pinentry expires + # so that it will continue resizing without appending more space. + # Resizing the partition to the file size cannot harm data anyway. + elif [[ "$newtombsize" = "$oldtombsize" ]]; then + _message "Tomb seems resized already, operating filesystem stretch" + else + _failure "The new size must be greater then old tomb size." + fi + + lo_mount "$TOMBPATH" + + _message "opening tomb" + _cryptsetup luksOpen ${TOMBLOOP} ${TOMBMAPPER} || { + _failure "Failure mounting the encrypted file." } + + _sudo cryptsetup resize "${TOMBMAPPER}" || { + _failure "cryptsetup failed to resize ::1 mapper::" $TOMBMAPPER } + + + filesystem=`_detect_filesystem /dev/mapper/${TOMBMAPPER}` + _message "Filesystem detected: ::1 filesystem::" $filesystem + case $filesystem in + ext3|ext4) + _sudo e2fsck -p -f /dev/mapper/${TOMBMAPPER} || { + _sudo cryptsetup luksClose "${TOMBMAPPER}" + _failure "e2fsck failed to check ::1 mapper::" $TOMBMAPPER } + _sudo resize2fs /dev/mapper/${TOMBMAPPER} || { + _sudo cryptsetup luksClose "${TOMBMAPPER}" + _failure "resize2fs failed to resize ::1 mapper::" $TOMBMAPPER } + ;; + btrfs) + _sudo btrfs check /dev/mapper/${TOMBMAPPER} || { + _sudo cryptsetup luksClose "${TOMBMAPPER}" + _failure "filesystem check failed on ::1 mapper::" $TOMBMAPPER } + # btrfs requires mounting before resize + local mp=${TOMBNAME}.tomb.resize + mkdir -p /tmp/${mp} + _sudo mount /dev/mapper/${TOMBMAPPER} /tmp/${mp} + _sudo btrfs filesystem resize max /tmp/${mp} || { + _sudo umount /tmp/${mp} + _sudo cryptsetup luksClose "${TOMBMAPPER}" + rmdir /tmp/${mp} + _failure "filesystem resize failed on ::1 mapper::" $TOMBMAPPER } + _sudo umount /tmp/${mp} + rmdir /tmp/${mp} + ;; + # TODO: report error on unrecognized filesystem + esac + + # close and free the loop device + _sudo cryptsetup luksClose "${TOMBMAPPER}" + + return 0 +} + +# }}} + +# {{{ Close + +umount_tomb() { + local tombs how_many_tombs + local pathmap mapper tombname tombmount loopdev + local ans pidk pname + + if [ "$1" = "all" ]; then + mounted_tombs=(`list_tomb_mounts`) + else + mounted_tombs=(`list_tomb_mounts $1`) + fi + + [[ ${#mounted_tombs} == 0 ]] && { + _failure "There is no open tomb to be closed." } + + [[ ${#mounted_tombs} -gt 1 && -z "$1" ]] && { + _warning "Too many tombs mounted, please specify one (see tomb list)" + _warning "or issue the command 'tomb close all' to close them all." + _failure "Operation aborted." } + + for t in ${mounted_tombs}; do + mapper=`basename ${t[(ws:;:)1]}` + + # strip square parens from tombname + tombname=${t[(ws:;:)5]} + tombmount=${t[(ws:;:)2]} + tombfs=${t[(ws:;:)3]} + tombfsopts=${t[(ws:;:)4]} + tombloop=${mapper[(ws:.:)4]} + + _verbose "Name: ::1 tomb name::" $tombname + _verbose "Mount: ::1 mount point::" $tombmount + _verbose "Loop: ::1 mount loop::" $tombloop + _verbose "Mapper: ::1 mapper::" $mapper + + [[ -e "$mapper" ]] && { + _warning "Tomb not found: ::1 tomb file::" $1 + _warning "Please specify an existing tomb." + return 0 } + + option_is_set -n || { + exec_safe_func_hooks \ + close "$tombmount" "$tombname" "$tombloop" "$mapper" + exec_hook_res=$? + [[ $exec_hook_res = 0 ]] || { + _warning "close exec-hook returns a non-zero error code: ::1 error::" $exec_hook_res + _failure "Operation aborted" + } + } + + _message "Closing tomb ::1 tomb name:: mounted on ::2 mount point::" \ + $tombname $tombmount + + # check if there are binded dirs and close them + bind_tombs=(`list_tomb_binds $tombname $tombmount`) + for b in ${(f)"$(list_tomb_binds $tombname $tombmount)"}; do + bind_mapper="${b[(ws:;:)1]}" + bind_mount="${b[(ws:;:)2]}" + _message "Closing tomb bind hook: ::1 hook::" $bind_mount + _sudo umount $bind_mount || + _failure "Tomb bind hook ::1 hook:: is busy, cannot close tomb." $bind_mount + done + + # check if the tomb is actually still mounted. Background: + # When mounted on a binded directory in appears twice in 'list_tomb_binds' + # and will get umounted automatically through the above function + # causing an error and a remaining (decrypted!) loop device + # posing a security risk. + # See https://github.com/dyne/Tomb/issues/273 + + # checking for tombs still mounted + mounted_tombs=(`list_tomb_mounts`) + for t in ${mounted_tombs}; do + usedmount=${t[(ws:;:)2]} + [[ "$usedmount" == "$tombmount" ]] && { + # Tomb was not umounted through the above command + # Will do so now + _verbose "Performing umount of ::1 mount point::" $tombmount + _sudo umount ${tombmount} + [[ $? = 0 ]] || { _failure "Tomb is busy, cannot umount!" } + } + done + + # If we used a default mountpoint and is now empty, delete it + tombname_regex=${tombname//\[/} + tombname_regex=${tombname_regex//\]/} + + [[ "$tombmount" =~ "(/run)?/media(/$_USER)?/$tombname_regex" ]] && { + _sudo rmdir $tombmount } + + _sudo cryptsetup luksClose $mapper || + _failure "Error occurred in cryptsetup luksClose ::1 mapper::" $mapper + + # Normally the loopback device is detached when unused + [[ -e "/dev/$tombloop" ]] && { + _sudo losetup -d "/dev/$tombloop" || + _verbose "/dev/$tombloop was already closed." + } + + _success "Tomb ::1 tomb name:: closed: your bones will rest in peace." $tombname + + done # loop across mounted tombs + + return 0 +} + +list_processes() { + # $1 = (optional) name of tomb + # returns a list of process UIDs, one per line + local mounted_tombs i + local pnum puid pcmd powner found + found=0 + mounted_tombs=(`list_tomb_mounts $1`) + if [[ "${#mounted_tombs}" -gt 0 ]]; then + if [[ -z $1 ]]; then + _success "Listing processes running inside all open tombs..." + else + _success "Listing processes running inside tomb '::1 tombname::'..." "$1" + fi + + for i in ${mounted_tombs}; do + _verbose "scanning tomb: ::1 tombmount::" $i + tombmount=${i[(ws:;:)2]} + tombname=${i[(ws:;:)5]} + for pnum in ${(f)"$(_sudo lsof -t +D $tombmount)"}; do + found=$(($found + 1)) + _verbose "process found: $pnum" + puid=$(_cat /proc/${pnum}/loginuid) + pcmd=$(_cat /proc/${pnum}/cmdline) + powner=`_get_username $puid` + _verbose "process found: $pnum $pcmd ($powner)" + _message "::1 tombname:: ::2 cmd:: (::3 owner::)" \ + $tombname $pcmd $powner + done + done + fi + _message "::1 foundproc:: running processes found inside ::2 numtombs:: open tombs" \ + $found ${#mounted_tombs} + return 0 +} + +# Kill all processes using the tomb +slam_tomb() { + # $1 = (optional) name of tomb to slam, or "all" if more mounted + + if [ "$1" = "all" ]; then + mounted_tombs=(`list_tomb_mounts`) + else + mounted_tombs=(`list_tomb_mounts $1`) + fi + + [[ ${#mounted_tombs} == 0 ]] && { + _failure "There is no open tomb to be closed." } + + [[ ${#mounted_tombs} -gt 1 && -z "$1" ]] && { + _warning "Too many tombs mounted, please specify one (see tomb list)" + _warning "or issue the command 'tomb close all' to close them all." + _failure "Operation aborted." } + + local pnum puid pcmd powner result + result=0 + # iterate through all mounted tomb affected + for i in ${mounted_tombs}; do + tombname=${i[(ws:;:)5]} + tombmount=${i[(ws:;:)2]} + _success "Slamming tomb ::1 tombname:: mounted on ::2 tombmount::" \ + ${tombname} ${tombmount} + # iterate through all processes running in mounted tombs + for pnum in ${(f)"$(_sudo lsof -t +D $tombmount)"}; do + puid=$(_cat /proc/${pnum}/loginuid) + pcmd=$(_cat /proc/${pnum}/cmdline) + powner=`_get_username $puid` + _verbose "process found: $pnum $pcmd ($powner)" + # iterate through 3 different signals to send, break on success + for s in TERM HUP KILL; do + _message "::1 tombname:: sending ::2 sig:: to ::3 cmd:: (::4 uid::)" \ + ${tombname} ${s} ${pcmd} ${powner} + _sudo kill -$s $pnum + # give some time to the process for a clean quit + sleep .5 + # stop sending other signals if kill was succesfull + [[ -r /proc/$pnum ]] || break + done + # if process still running then signal failure + [[ -r /proc/$pnum ]] && { + _warning "Can't kill ::1 process:: ::2 pcmd:: (::3 powner::)" \ + $pnum $pcmd $powner + result=1 } + done + # if it failed killing a process, report it + [[ $result = 0 ]] && umount_tomb $tombname + done + return $result +} + +# }}} - Tomb close + +# {{{ Main routine + +main() { + + _ensure_dependencies # Check dependencies are present or bail out + + local -A subcommands_opts + ### Options configuration + # + # Hi, dear developer! Are you trying to add a new subcommand, or + # to add some options? Well, keep in mind that option names are + # global: they cannot bear a different meaning or behaviour across + # subcommands. The only exception is "-o" which means: "options + # passed to the local subcommand", and thus can bear a different + # meaning for different subcommands. + # + # For example, "-s" means "size" and accepts one argument. If you + # are tempted to add an alternate option "-s" (e.g., to mean + # "silent", and that doesn't accept any argument) DON'T DO IT! + # + # There are two reasons for that: + # I. Usability; users expect that "-s" is "size" + # II. Option parsing WILL EXPLODE if you do this kind of bad + # things (it will complain: "option defined more than once") + # + # If you want to use the same option in multiple commands then you + # can only use the non-abbreviated long-option version like: + # -force and NOT -f + # + main_opts=(q -quiet=q D -debug=D h -help=h v -version=v f -force=f -tmp: U: G: T: -no-color -unsafe g -gpgkey=g) + subcommands_opts[__default]="" + # -o in open and mount is used to pass alternate mount options + subcommands_opts[open]="n -nohook=n k: -kdf: o: -ignore-swap -tomb-pwd: r: R: -sphx-host: -sphx-user: p -preserve-ownership=p" + subcommands_opts[mount]=${subcommands_opts[open]} + + subcommands_opts[create]="" # deprecated, will issue warning + + # -o in forge and lock is used to pass an alternate cipher. + subcommands_opts[forge]="-ignore-swap k: -kdf: o: -tomb-pwd: -use-random r: R: -sphx-host: -sphx-user: " + subcommands_opts[dig]="-ignore-swap s: -size=s " + subcommands_opts[lock]="-ignore-swap k: -kdf: o: -tomb-pwd: r: R: -sphx-host: -sphx-user: -filesystem: " + subcommands_opts[setkey]="k: -ignore-swap -kdf: -tomb-old-pwd: -tomb-pwd: r: R: -sphx-host: -sphx-user: " + subcommands_opts[engrave]="k: " + + subcommands_opts[passwd]="k: -ignore-swap -kdf: -tomb-old-pwd: -tomb-pwd: r: R: -sphx-host: -sphx-user: " + subcommands_opts[close]="" + subcommands_opts[help]="" + subcommands_opts[slam]="" + subcommands_opts[ps]="" + subcommands_opts[list]="-get-mountpoint " + + subcommands_opts[index]="" + subcommands_opts[search]="" + + subcommands_opts[help]="" + subcommands_opts[bury]="k: -tomb-pwd: r: R: -sphx-host: -sphx-user: " + subcommands_opts[exhume]="k: -tomb-pwd: r: R: -sphx-host: -sphx-user: " + subcommands_opts[cloak]="k: " + subcommands_opts[uncloak]="k: " + # subcommands_opts[decompose]="" + # subcommands_opts[recompose]="" + # subcommands_opts[install]="" + subcommands_opts[askpass]="" + subcommands_opts[source]="" + subcommands_opts[resize]="-ignore-swap s: -size=s k: -tomb-pwd: r: R: -sphx-host: -sphx-user: " + subcommands_opts[check]="-ignore-swap " + # subcommands_opts[translate]="" + + ### Detect subcommand + local -aU every_opts #every_opts behave like a set; that is, an array with unique elements + for optspec in $subcommands_opts$main_opts; do + for opt in ${=optspec}; do + every_opts+=${opt} + done + done + local -a oldstar + oldstar=("${(@)argv}") + #### detect early: useful for --option-parsing + zparseopts -M -D -Adiscardme ${every_opts} + if [[ -n ${(k)discardme[--option-parsing]} ]]; then + print $1 + if [[ -n "$1" ]]; then + return 1 + fi + return 0 + fi + unset discardme + if ! zparseopts -M -E -D -Adiscardme ${every_opts}; then + _failure "Error parsing." + return 127 + fi + unset discardme + subcommand=$1 + if [[ -z $subcommand ]]; then + subcommand="__default" + fi + + if [[ -z ${(k)subcommands_opts[$subcommand]} ]]; then + _warning "There's no such command \"::1 subcommand::\"." $subcommand + exitv=127 _failure "Please try -h for help." + fi + argv=("${(@)oldstar}") + unset oldstar + + ### Parsing global + command-specific options + # zsh magic: ${=string} will split to multiple arguments when spaces occur + set -A cmd_opts ${main_opts} ${=subcommands_opts[$subcommand]} + # if there is no option, we don't need parsing + if [[ -n $cmd_opts ]]; then + zparseopts -M -E -D -AOPTS ${cmd_opts} + if [[ $? != 0 ]]; then + _warning "Some error occurred during option processing." + exitv=127 _failure "See \"tomb help\" for more info." + fi + fi + #build PARAM (array of arguments) and check if there are unrecognized options + ok=0 + PARAM=() + for arg in $*; do + if [[ $arg == '--' || $arg == '-' ]]; then + ok=1 + continue #it shouldn't be appended to PARAM + elif [[ $arg[1] == '-' ]]; then + if [[ $ok == 0 ]]; then + exitv=127 _failure "Unrecognized option ::1 arg:: for subcommand ::2 subcommand::" $arg $subcommand + fi + fi + PARAM+=$arg + done + # First parameter actually is the subcommand: delete it and shift + [[ $subcommand != '__default' ]] && { PARAM[1]=(); shift } + + ### End parsing command-specific options + + # Use colors unless told not to + { ! option_is_set --no-color } && { autoload -Uz colors && colors } + # Some options are only available during insecure mode + { ! option_is_set --unsafe } && { + for opt in --tomb-pwd --tomb-old-pwd; do + { option_is_set $opt } && { + exitv=127 _failure "You specified option ::1 option::, which is DANGEROUS and should only be used for testing\nIf you really want so, add --unsafe" $opt } + done + } + # read -t or --tmp flags to set a custom temporary directory + option_is_set --tmp && TMPDIR=$(option_value --tmp) + + + # When we run as root, we remember the original uid:gid to set + # permissions for the calling user and drop privileges + _whoami # Reset _UID, _GID, _TTY + + [[ -z $PARAM ]] && { + _verbose "Tomb command: ::1 subcommand::" $subcommand + } || { + _verbose "Tomb command: ::1 subcommand:: ::2 param::" $subcommand $PARAM + } + + [[ -z $_UID ]] || { + _verbose "Caller: uid[::1 uid::], gid[::2 gid::], tty[::3 tty::]." \ + $_UID $_GID $_TTY + } + + _verbose "Temporary directory: $TMPDIR" + + # Process subcommand + case "$subcommand" in + + # USAGE + help) + usage + ;; + + # DEPRECATION notice (leave here as 'create' is still present in old docs) + create) + _warning "The create command is deprecated, please use dig, forge and lock instead." + _warning "For more informations see Tomb's manual page (man tomb)." + _failure "Operation aborted." + ;; + + # CREATE Step 1: dig -s NN file.tomb + dig) + dig_tomb $PARAM + ;; + + # CREATE Step 2: forge file.tomb.key + forge) + forge_key $PARAM + ;; + + # CREATE Step 3: lock -k file.tomb.key file.tomb + lock) + lock_tomb_with_key $PARAM + ;; + + # Open the tomb + mount|open) + mount_tomb $PARAM + ;; + + # List all processes using a tomb + ps) + list_processes $PARAM + ;; + + # Slam a tomb killing all processes running inside + slam) + slam_tomb $PARAM + ;; + + # Close the tomb + # `slam` is used to force closing. + umount|close) + [[ "$subcommand" == "slam" ]] && { + SLAM=1 + [[ $LSOF == 0 ]] && { + unset SLAM + _warning "lsof not installed: cannot slam tombs." + _warning "Trying a regular close." }} + umount_tomb $PARAM[1] + ;; + + # Grow tomb's size + resize) + [[ $RESIZER == 0 ]] && { + _failure "Resize2fs not installed: cannot resize tombs." } + resize_tomb $PARAM[1] + ;; + + ## Contents manipulation + + # Index tomb contents + index) + index_tombs $PARAM[1] + ;; + + # List tombs + list) + list_tombs $PARAM[1] + ;; + + # Search tomb contents + search) + search_tombs $PARAM + ;; + + ## Locking operations + + # Export key to QR Code + engrave) + [[ $QRENCODE == 0 ]] && { + _failure "QREncode not installed: cannot engrave keys on paper." } + engrave_key $PARAM + ;; + + # Change password on existing key + passwd) + change_passwd $PARAM[1] + ;; + + # Change tomb key + setkey) + change_tomb_key $PARAM + ;; + + # STEGANOGRAPHY: hide key inside an image + bury) + [[ $STEGHIDE == 0 ]] && { + _failure "Steghide not installed: cannot bury keys into images." } + bury_key $PARAM[1] + ;; + + # STEGANOGRAPHY: read key hidden in an image + exhume) + [[ $STEGHIDE == 0 ]] && { + _failure "Steghide not installed: cannot exhume keys from images." } + exhume_key $PARAM[1] + ;; + + # STEGANOGRAPHY: transform key into text using cipher + cloak) + [[ $CLOAKIFY == 0 ]] && { + _failure "Cloakify not installed: cannot cipher keys into texts" } + cloakify_key $PARAM + ;; + + # STEGANOGRAPHY: read key from text using cipher + uncloak) + [[ $DECLOAKIFY == 0 ]] && { + _failure "Decloakify not installed: cannot decipher keys from texts" } + decloakify_key $PARAM + ;; + + + ## Internal commands useful to developers + + # Make tomb functions available to the calling shell or script + 'source') return 0 ;; + + # Ask user for a password interactively + askpass) ask_password $PARAM[1] $PARAM[2] ;; + + # Default operation: presentation, or version information with -v + __default) + _print "Tomb ::1 version:: - a strong and gentle undertaker for your secrets" $VERSION + echo + _print " Copyright (C) 2007-2021 Dyne.org Foundation, License GNU GPL v3+" + _print " This is free software: you are free to change and redistribute it" + _print " For the latest sourcecode go to <http://dyne.org/software/tomb>" + echo + option_is_set -v && { + local langwas=$LANG + LANG=en + _print " This source code is distributed in the hope that it will be useful," + _print " but WITHOUT ANY WARRANTY; without even the implied warranty of" + _print " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + LANG=$langwas + _print " When in need please refer to <http://dyne.org/support>." + echo + _print "System utils:" + echo + cat <<EOF + `zsh --version` + `sudo -V | head -n1` + `cryptsetup --version` + `pinentry --version | head -n1` + `findmnt -V` + `gpg --version | head -n1` - key forging algorithms (GnuPG symmetric ciphers): + `list_gnupg_ciphers` +EOF + echo + _print "Optional utils:" + echo + _list_optional_tools version + return 0 + } + usage + ;; + + # Reject unknown command and suggest help + *) + _warning "Command \"::1 subcommand::\" not recognized." $subcommand + _message "Try -h for help." + return 1 + ;; + esac + return $? +} + +# }}} + +# {{{ Run + +main "$@" || exit $? # Prevent `source tomb source` from exiting + +# }}}
A bin/truecolor

@@ -0,0 +1,25 @@

+#!/usr/bin/env bash +# +# Use this script to test if you have true color support in your terminal. +# Usage: ./truecolor.sh +# If the color ramp is perfectly smooth, true color is supported. +# +# Source: https://gist.github.com/XVilka/8346728 +# +# old 's': +#s="/\\/\\/\\/\\/\\"; s=s s s s s s s s; + +awk -v term_cols="${width:-$(tput cols || echo 80)}" 'BEGIN{ + s="/\\"; + for (colnum = 0; colnum<term_cols; colnum++) { + r = 255-(colnum*255/term_cols); + g = (colnum*510/term_cols); + b = (colnum*255/term_cols); + if (g>255) g = 510-g; + printf "\033[48;2;%d;%d;%dm", r,g,b; + printf "\033[38;2;%d;%d;%dm", 255-r,255-g,255-b; + printf "%s\033[0m", substr(s,colnum%2+1,1); + } + printf "\n"; +}' +
A bin/web-backup

@@ -0,0 +1,16 @@

+#!/usr/bin/env bash + +# web-backup.sh: tar backup web directory on a server w/ date-time in name +# by x1phosura + +# path to web directory to backup (CHANGE ME if different webserver!!!) +# vvv- below for FreeBSD webserver +WEBDIR=/usr/local/www/nginx +BACKUPDIR=~/web-backups + +if [ $# -ne 1 ] ; then # if 0 or >1 command line args + sudo tar -cvzf $BACKUPDIR/webdir-$(date +"%F%N").tar.gz $WEBDIR +else # if 1 command line arg + sudo tar -cvzf $BACKUPDIR/webdir-$(date +"%F%N").tar.gz $1 +fi +
A bin/wpa-connect

@@ -0,0 +1,143 @@

+#!/usr/bin/env bash + +# wpa-connect.sh +# Dumb wpa_supplicant wrapper to connect to wifi or create a new wpa profile +# Depends on wpa_supplicant and iw +# +# by x1phosura + +# If the script fails, you can always run the following AS ROOT: +# wpa_supplicant -B -i wlp3s0 -c <(wpa_passphrase profile_name passphrase) # && dhcpcd + +# wireless networking interface +# TODO: auto-read or allow changes +wint="wlp3s0" + +# where wpa_supplicant config files are stored on the system +wpa_conf_path="/etc/wpa_supplicant" +# list of profiles in the wpa_supplicant config path +# strips the '.conf' +# shellcheck disable=SC2012 +profile_list="$(ls /etc/wpa_supplicant | sed 's/.conf//g' | sed 's/^/ /g')" + +default="# to get the psk, do wpa_passphrase \\\"profile_name\\\" \\\"passphrase\\\"\n" + +sudo_validate() { + if [[ $(id -u) != 0 ]]; then # if not already root + sudo -v + fi +} + +print_usage() { + echo -ne \ + "Usage: "$(basename $0)" [ -dshln ] [ -c profile_name ]\n\n" \ + "Options:\n" \ + "-d --disconnect\n" \ + " Kill current wpa_supplicant process and disconnect\n" \ + "-s --scan\n" \ + " Scan for and list nearby SSIDS\n" \ + "-h --help\n" \ + " Displau this message\n" \ + "-l --list --list-profiles\n" \ + " List current available WPA/2 profiles\n" \ + "-n --new\n" \ + " Create a new wpa_supplicant profile (BETA feature)\n" \ + "-c --connect [profile_name]\n" \ + " Connect to the provided WPA/2 profile 'profile_name'\n" +} + +make_new_wpa_profile() { + printf "BETA feature!: Currently assumes a basic home WPA/2 setup (just " + printf "requires a password to log in).\n" + echo "Enter the config file's name (usually NetworkName.conf): " + read wpa_profile_name + echo "Enter the network's name (SSID) unescaped: " + read ssid + echo "Does the network need a password (PSK)? [y/N]: " + read has_psk + + sudo_validate + sudo touch "$wpa_conf_path"/"$wpa_profile_name" + + if [[ "$has_psk" != "" && $(printf "${has_psk:0:1}" | tr Y y) = "y" ]] ; then + echo "Enter the network's password (psk): " + read pass + sudo sh -c "echo -e \"$default\" > \"$wpa_conf_path\"/\"$wpa_profile_name\"" + sudo sh -c "wpa_passphrase \"$ssid\" \"$pass\" >> \"$wpa_conf_path\"/\"$wpa_profile_name\"" + sudo sh -c "chmod 660 \"$wpa_conf_path\"/\"$wpa_profile_name\"" + else # else unsecured network, connect with no password + sudo sh -c "cat > \"$wpa_conf_path\"/\"$wpa_profile_name\" << EOF +network={ + ssid=\"$ssid\" + key_mgmt=NONE +} +EOF" + fi + + echo "Profile made. Would you like to connect to your new profile? [y/N]" + read connect_new + + if [[ "$connect_new" != "" && $(printf "${connect_new:0:1}" | tr Y y) = "y" ]] + then + profile=$(printf "$wpa_profile_name" | sed 's/.conf//g') # get profile + connect_to_profile + fi +} + +connect_to_profile() { + sudo_validate + + [ "$(pgrep wpa_supplicant)" != "" ] && sudo killall wpa_supplicant + sleep 1 # necessary for some reason, I forget why + + #systemctl stop {wicd,netctl} && \ + sudo wpa_supplicant -B -i "$wint" -c /etc/wpa_supplicant/"$profile".conf + # sudo dhcpcd "$wint" # needed if systemd dhcpcd service not used +} + + +profile="" + +if [ $# -lt 1 ] ; then # if less than 1 argument (no args) provided... + print_usage ; exit 1 +fi + +while [[ "$#" -gt 0 ]]; do + case $1 in + -d|--disconnect) + sudo_validate + sudo killall wpa_supplicant ; break ;; + -s|--scan) + sudo_validate + # Note: `iw dev $wint scan | less` gives more verbose info in output + sudo iw dev $wint scan | grep 'SSID: ' \ + | sed -E 's/[[:space:]]+SSID: //g' + break ;; + -h|--help) + print_usage ; break ;; + -l|--list|--list-profiles) + printf "%s\n%s\n" \ + "Current profiles to choose from:" \ + "$profile_list " ; break ;; + -n|--new) + sudo_validate + make_new_wpa_profile # create a new wpa_supplicant profile + break ;; + -c|--connect) + profile="$2" + if [ "$profile" = "" ]; then + echo -ne "$(basename $0): -c, --connect takes an argument " \ + "'profile_name'\n\n" + print_usage + else + sudo_validate + connect_to_profile # connect to existing profile + fi + shift + break ;; + *) + print_usage ; exit 1 ;; + esac + shift +done +
A bin/x1phosura

@@ -0,0 +1,43 @@

+#!/bin/sh + +x1phosura=" + + ########## + ## ## + ## ## ## ## + ## ## + ## ## ## ## + ## ########## ## + #### #### + ## ## ## ## ## + ## ## + ## + ## + ## + ## + ## + ## + +" + +exists_truecolor='true' # TODO: detect if have truecolor support + +# vvv- original: +#fg_purple_true="\x1b[38;2;156;39;176m" # foreground is RGB 156,39,176 (#9C27B0) +fg_purple_true="\x1b[38;2;187;34;187m" # foreground is RGB 187,34,187 (#bb22bb) +bg_black_true="\x1b[48;2;0;0;0m" # background is black +fg_purple_16="\033[01;35m" # foreground is boring bold purple +ansi_bold="\033[1m" +ansi_end="\x1b[0m\n" # resets/clears ANSI colors to default + +if [ "$exists_truecolor" = "true" ]; then + #output="$ansi_bold$fg_purple_true$bg_black_true$x1phosura$ansi_end" + output="$ansi_bold$fg_purple_true$x1phosura$ansi_end" +else + # If '24-bit' true color not supported, revert to classic '4-bit' 16 colors + # I'm too lazy to figure out what this would be in 256 colors + output="$fg_purple_16$x1phosura$ansi_end" +fi + +printf "$output" +
A i3/.Xresources

@@ -0,0 +1,85 @@

+ +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +!! !! +!! x1phosuras's .Xresources file !! +!! !! +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +!! Note: use the following command to apply changes: +!! $ xrdb ~/.Xresources + + +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +!! Misc. settings !! +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +! get rid of scrollbar +URxvt*scrollBar: false + +! fix copy/paste BS in urxvt +URxvt.keysym.Shift-Control-V: eval:paste_clipboard +URxvt.keysym.Shift-Control-C: eval:selection_to_clipboard + +! fixes Ctrl-(left or right) doing what I actually want +URxvt.keysym.Control-Up: \033[1;5A +URxvt.keysym.Control-Down: \033[1;5B +URxvt.keysym.Control-Left: \033[1;5D +URxvt.keysym.Control-Right: \033[1;5C + +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +!! Font, colors, and transparency !! +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +! font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html +! Alt. good font: Tamzen, size 16 +URxvt.font: xft:Terminus:pixelsize=14 + +!! color settings generated by a combination of wal and terminal.sexy + +! Real transparency (uses the compositor) +! (depth needs to be EXACTLY 32 for some weird reason) +urxvt*depth: 32 + +! Fake transparency (uses the background picture supplied by feh) +!urxvt*transparent: true +! urxvt*shading: 30 + +! the [90] is the transparency level +*.background: #000000 +*.foreground: #8ff6a8 +*.cursorColor: #8ff6a8 + +! Note: The below color names do not necessarily match the actual colors. +! They represent what colors 0-15 would normally be +! black +*.color0: #232d25 +*.color8: #ac9764 + +! red +*.color1: #900000 +*.color9: #ff0000 + +! green +*.color2: #2df844 +*.color10: #2df844 + +! yellow +*.color3: #b29b38 +*.color11: #b29b38 + +! blue +*.color4: #218376 +*.color12: #218376 + +! magenta +*.color5: #ff2f2f +*.color13: #ff2f2f + +! cyan +*.color6: #ff7b16 +*.color14: #ff7b16 + +! white +*.color7: #f6d98f +*.color15: #f6d98f +
A i3/.Xresources-manjaro

@@ -0,0 +1,111 @@

+!! Xft.dpi: 96 +Xft.dpi: 144 +Xft.antialias: true +Xft.hinting: true +Xft.rgba: rgb +Xft.autohint: false +Xft.hintstyle: hintslight +Xft.lcdfilter: lcddefault + +XTerm*background: #222D31 +XTerm*foreground: #d8d8d8 +XTerm*pointerColor: #1ABB9B +XTerm*faceName: Fixed +XTerm*faceSize: 11 +XTerm*reverseVideo: on +XTerm*selectToClipboard: true + +*background: #222D31 +*foreground: #d8d8d8 +*fading: 8 +*fadeColor: black +*cursorColor: #1ABB9B +*pointerColorBackground: #2B2C2B +*pointerColorForeground: #16A085 + +!! black dark/light +*color0: #222D31 +*color8: #585858 + +!! red dark/light +*color1: #ab4642 +*color9: #ab4642 + +!! green dark/light +*color2: #7E807E +*color10: #8D8F8D + +!! yellow dark/light +*color3: #f7ca88 +*color11: #f7ca88 + +!! blue dark/light +*color4: #7cafc2 +*color12: #7cafc2 + +!! magenta dark/light +*color5: #ba8baf +*color13: #ba8baf + +!! cyan dark/light +*color6: #1ABB9B +*color14: #1ABB9B + +!! white dark/light +*color7: #d8d8d8 +*color15: #f8f8f8 + +Xcursor.theme: xcursor-breeze +Xcursor.size: 0 + +URxvt.font: 9x15,xft:TerminessTTFNerdFontMono + +! alternative font settings with 'terminus': +! URxvt.font: -xos4-terminus-medium-r-normal--16-160-72-72-c-80-iso10646-1 +! URxvt.bold.font: -xos4-terminus-bold-r-normal--16-160-72-72-c-80-iso10646-1 +!! terminus names see end of file! + +URxvt.depth: 32 +URxvt.background: [100]#222D31 +URxvt*scrollBar: false +URxvt*mouseWheelScrollPage: false +URxvt*cursorBlink: true +URxvt*background: black +URxvt*foreground: grey +URxvt*saveLines: 5000 + +! for 'fake' transparency (without Compton) uncomment the following three lines +! URxvt*inheritPixmap: true +! URxvt*transparent: true +! URxvt*shading: 138 + +! Normal copy-paste keybindings without perls +URxvt.iso14755: false +URxvt.keysym.Shift-Control-V: eval:paste_clipboard +URxvt.keysym.Shift-Control-C: eval:selection_to_clipboard +!Xterm escape codes, word by word movement +URxvt.keysym.Control-Left: \033[1;5D +URxvt.keysym.Shift-Control-Left: \033[1;6D +URxvt.keysym.Control-Right: \033[1;5C +URxvt.keysym.Shift-Control-Right: \033[1;6C +URxvt.keysym.Control-Up: \033[1;5A +URxvt.keysym.Shift-Control-Up: \033[1;6A +URxvt.keysym.Control-Down: \033[1;5B +URxvt.keysym.Shift-Control-Down: \033[1;6B + +! The Terminus font uses the following X-names: +! -xos4-terminus-medium-r-normal--12-120-72-72-c-60-iso10646-1 +! -xos4-terminus-medium-r-normal--14-140-72-72-c-80-iso10646-1 +! -xos4-terminus-medium-r-normal--16-160-72-72-c-80-iso10646-1 +! -xos4-terminus-medium-r-normal--20-200-72-72-c-100-iso10646-1 +! -xos4-terminus-medium-r-normal--22-220-72-72-c-110-iso10646-1 +! -xos4-terminus-medium-r-normal--24-240-72-72-c-120-iso10646-1 +! -xos4-terminus-medium-r-normal--28-280-72-72-c-140-iso10646-1 +! -xos4-terminus-medium-r-normal--32-320-72-72-c-160-iso10646-1 +! -xos4-terminus-bold-r-normal--12-120-72-72-c-60-iso10646-1 +! -xos4-terminus-bold-r-normal--14-140-72-72-c-80-iso10646-1 +! -xos4-terminus-bold-r-normal--16-160-72-72-c-80-iso10646-1 +! -xos4-terminus-bold-r-normal--20-200-72-72-c-100-iso10646-1 +! -xos4-terminus-bold-r-normal--24-240-72-72-c-120-iso10646-1 +! -xos4-terminus-bold-r-normal--28-280-72-72-c-140-iso10646-1 +! -xos4-terminus-bold-r-normal--32-320-72-72-c-160-iso10646-1
A i3/.config/alacritty/alacritty.yml

@@ -0,0 +1,624 @@

+# Configuration for Alacritty, the GPU enhanced terminal emulator. + +# Any items in the `env` entry below will be added as +# environment variables. Some entries may override variables +# set by alacritty itself. +env: + # TERM variable + # + # This value is used to set the `$TERM` environment variable for + # each instance of Alacritty. If it is not present, alacritty will + # check the local terminfo database and use `alacritty` if it is + # available, otherwise `xterm-256color` is used. + TERM: xterm-256color + +window: + # Window dimensions (changes require restart) + # + # Specified in number of columns/lines, not pixels. + # If both are `0`, this setting is ignored. +# dimensions: +# columns: 0 +# lines: 0 + + # Window position (changes require restart) + # + # Specified in number of pixels. + # If the position is not set, the window manager will handle the placement. + #position: + # x: 0 + # y: 0 + + # Window padding (changes require restart) + # + # Blank space added around the window in pixels. This padding is scaled + # by DPI and the specified value is always added at both opposing sides. + padding: + x: 0 + y: 0 + + # Spread additional padding evenly around the terminal content. + dynamic_padding: false + + # Allow terminal applications to change Alacritty's window title. + dynamic_title: true + + # Window decorations + # + # Values for `decorations`: + # - full: Borders and title bar + # - none: Neither borders nor title bar + # + # Values for `decorations` (macOS only): + # - transparent: Title bar, transparent background and title bar buttons + # - buttonless: Title bar, transparent background, but no title bar buttons + decorations: full + + # Startup Mode (changes require restart) + # + # Values for `startup_mode`: + # - Windowed + # - Maximized + # - Fullscreen + # + # Values for `startup_mode` (macOS only): + # - SimpleFullscreen + startup_mode: Windowed + + # Window title + #title: Alacritty + + # Window class (Linux only): + #class: Alacritty + +scrolling: + # Maximum number of lines in the scrollback buffer. + # Specifying '0' will disable scrolling. + history: 10000 + + # Number of lines the viewport will move for every line scrolled when + # scrollback is enabled (history > 0). + multiplier: 3 + +# Font configuration (changes require restart) +font: + # Normal (roman) font face + normal: + # Font family + # + # Default: + # - (macOS) Menlo + # - (Linux) monospace + # - (Windows) Consolas + #family: Inconsolata + family: monospace + family: TerminessTTF Nerd Font + + # The `style` can be specified to pick a specific face. + #style: Regular + + # Bold font face + #bold: + # Font family + # + # If the bold family is not specified, it will fall back to the + # value specified for the normal font. + #family: monospace + + # The `style` can be specified to pick a specific face. + #style: Bold + + # Italic font face + #italic: + # Font family + # + # If the italic family is not specified, it will fall back to the + # value specified for the normal font. + #family: monospace + + # The `style` can be specified to pick a specific face. + #style: Italic + + # Point size + size: 8 + + # Offset is the extra space around each character. `offset.y` can be thought of + # as modifying the line spacing, and `offset.x` as modifying the letter spacing. + offset: + x: 0 + y: 0 + + # Glyph offset determines the locations of the glyphs within their cells with + # the default being at the bottom. Increasing `x` moves the glyph to the right, + # increasing `y` moves the glyph upwards. + glyph_offset: + x: 0 + y: 0 + + # Thin stroke font rendering (macOS only) + # + # Thin strokes are suitable for retina displays, but for non-retina screens + # it is recommended to set `use_thin_strokes` to `false` + # + # macOS >= 10.14.x: + # + # If the font quality on non-retina display looks bad then set + # `use_thin_strokes` to `true` and enable font smoothing by running the + # following command: + # `defaults write -g CGFontRenderingFontSmoothingDisabled -bool NO` + # + # This is a global setting and will require a log out or restart to take + # effect. + use_thin_strokes: true + +# If `true`, bold text is drawn using the bright color variants. +draw_bold_text_with_bright_colors: true + +# Colors (Tomorrow Night Bright) +colors: + # Default colors + primary: + background: '0x1e1e1e' + foreground: '0xeaeaea' + + # Bright and dim foreground colors + # + # The dimmed foreground color is calculated automatically if it is not present. + # If the bright foreground color is not set, or `draw_bold_text_with_bright_colors` + # is `false`, the normal foreground color will be used. + #dim_foreground: '0x9a9a9a' + #bright_foreground: '0xffffff' + + # Cursor colors + # + # Colors which should be used to draw the terminal cursor. If these are unset, + # the cursor color will be the inverse of the cell color. + #cursor: + # text: '0x000000' + # cursor: '0xffffff' + + # Selection colors + # + # Colors which should be used to draw the selection area. If selection + # background is unset, selection color will be the inverse of the cell colors. + # If only text is unset the cell text color will remain the same. + #selection: + # text: '0xeaeaea' + # background: '0x404040' + + # Normal colors + normal: + black: '0x000000' + red: '0xd54e53' + green: '0xb9ca4a' + yellow: '0xe6c547' + blue: '0x7aa6da' + magenta: '0xc397d8' + cyan: '0x70c0ba' + white: '0xeaeaea' + + # Bright colors + bright: + black: '0x666666' + red: '0xff3334' + green: '0x9ec400' + yellow: '0xe7c547' + blue: '0x7aa6da' + magenta: '0xb77ee0' + cyan: '0x54ced6' + white: '0xffffff' + + # Dim colors + # + # If the dim colors are not set, they will be calculated automatically based + # on the `normal` colors. + #dim: + # black: '0x000000' + # red: '0x8c3336' + # green: '0x7a8530' + # yellow: '0x97822e' + # blue: '0x506d8f' + # magenta: '0x80638e' + # cyan: '0x497e7a' + # white: '0x9a9a9a' + + # Indexed Colors + # + # The indexed colors include all colors from 16 to 256. + # When these are not set, they're filled with sensible defaults. + # + # Example: + # `- { index: 16, color: '0xff00ff' }` + # + indexed_colors: [] + +# Visual Bell +# +# Any time the BEL code is received, Alacritty "rings" the visual bell. Once +# rung, the terminal background will be set to white and transition back to the +# default background color. You can control the rate of this transition by +# setting the `duration` property (represented in milliseconds). You can also +# configure the transition function by setting the `animation` property. +# +# Values for `animation`: +# - Ease +# - EaseOut +# - EaseOutSine +# - EaseOutQuad +# - EaseOutCubic +# - EaseOutQuart +# - EaseOutQuint +# - EaseOutExpo +# - EaseOutCirc +# - Linear +# +# Specifying a `duration` of `0` will disable the visual bell. +bell: + animation: EaseOut + duration: 0 + color: '0xffffff' + +# Background opacity +# +# Window opacity as a floating point number from `0.0` to `1.0`. +# The value `0.0` is completely transparent and `1.0` is opaque. +#background_opacity: 0.94 +background_opacity: 1 + +# Mouse bindings +# +# Available fields: +# - mouse +# - action +# - mods (optional) +# +# Values for `mouse`: +# - Middle +# - Left +# - Right +# - Numeric identifier such as `5` +# +# All available `mods` and `action` values are documented in the key binding +# section. +mouse_bindings: + - { mouse: Middle, action: PasteSelection } + +mouse: + # Click settings + # + # The `double_click` and `triple_click` settings control the time + # alacritty should wait for accepting multiple clicks as one double + # or triple click. + double_click: { threshold: 300 } + triple_click: { threshold: 300 } + + # If this is `true`, the cursor is temporarily hidden when typing. + hide_when_typing: false + +# url: + # URL launcher + # + # This program is executed when clicking on a text which is recognized as a URL. + # The URL is always added to the command as the last parameter. + # + # When set to `None`, URL launching will be disabled completely. + # + # Default: + # - (macOS) open + # - (Linux) xdg-open + # - (Windows) explorer +# launcher: +# program: None + # program: xdg-open + # args: [] + + # URL modifiers + # + # These are the modifiers that need to be held down for opening URLs when clicking + # on them. The available modifiers are documented in the key binding section. +# modifiers: None + +selection: + #semantic_escape_chars: ",│`|:\"' ()[]{}<>" + + # When set to `true`, selected text will be copied to the primary clipboard. + save_to_clipboard: true + +cursor: + # Cursor style + # + # Values for `style`: + # - ▇ Block + # - _ Underline + # - | Beam + style: Block + + # If this is `true`, the cursor will be rendered as a hollow box when the + # window is not focused. + unfocused_hollow: true + +# Live config reload (changes require restart) +live_config_reload: true + +# Shell +# +# You can set `shell.program` to the path of your favorite shell, e.g. `/bin/fish`. +# Entries in `shell.args` are passed unmodified as arguments to the shell. +# +# Default: +# - (macOS) /bin/bash --login +# - (Linux) user login shell +# - (Windows) powershell +#shell: +# program: /bin/bash +# args: +# - --login + +# Startup directory +# +# Directory the shell is started in. If this is unset, or `None`, the working +# directory of the parent process will be used. +working_directory: None + +# Windows 10 ConPTY backend (Windows only) +# +# This will enable better color support and may resolve other issues, +# however this API and its implementation is still young and so is +# disabled by default, as stability may not be as good as the winpty +# backend. +# +# Alacritty will fall back to the WinPTY automatically if the ConPTY +# backend cannot be initialized. +enable_experimental_conpty_backend: false + +# Send ESC (\x1b) before characters when alt is pressed. +alt_send_esc: true + +debug: + # Display the time it takes to redraw each frame. + render_timer: false + + # Keep the log file after quitting Alacritty. + persistent_logging: false + + # Log level + # + # Values for `log_level`: + # - None + # - Error + # - Warn + # - Info + # - Debug + # - Trace + log_level: Warn + + # Print all received window events. + print_events: false + + # Record all characters and escape sequences as test data. + ref_test: false + +# Key bindings +# +# Key bindings are specified as a list of objects. Each binding will specify a +# key and modifiers required to trigger it, terminal modes where the binding is +# applicable, and what should be done when the key binding fires. It can either +# send a byte sequence to the running application (`chars`), execute a +# predefined action (`action`) or fork and execute a specified command plus +# arguments (`command`). +# +# Bindings are always filled by default, but will be replaced when a new binding +# with the same triggers is defined. To unset a default binding, it can be +# mapped to the `None` action. +# +# Example: +# `- { key: V, mods: Control|Shift, action: Paste }` +# +# Available fields: +# - key +# - mods (optional) +# - chars | action | command (exactly one required) +# - mode (optional) +# +# Values for `key`: +# - `A` -> `Z` +# - `F1` -> `F12` +# - `Key1` -> `Key0` +# +# A full list with available key codes can be found here: +# https://docs.rs/glutin/*/glutin/enum.VirtualKeyCode.html#variants +# +# Instead of using the name of the keys, the `key` field also supports using +# the scancode of the desired key. Scancodes have to be specified as a +# decimal number. +# This command will allow you to display the hex scancodes for certain keys: +# `showkey --scancodes` +# +# Values for `mods`: +# - Command +# - Control +# - Option +# - Super +# - Shift +# - Alt +# +# Multiple `mods` can be combined using `|` like this: `mods: Control|Shift`. +# Whitespace and capitalization is relevant and must match the example. +# +# Values for `chars`: +# The `chars` field writes the specified string to the terminal. This makes +# it possible to pass escape sequences. +# To find escape codes for bindings like `PageUp` ("\x1b[5~"), you can run +# the command `showkey -a` outside of tmux. +# Note that applications use terminfo to map escape sequences back to +# keys. It is therefore required to update the terminfo when +# changing an escape sequence. +# +# Values for `action`: +# - Paste +# - PasteSelection +# - Copy +# - IncreaseFontSize +# - DecreaseFontSize +# - ResetFontSize +# - ScrollPageUp +# - ScrollPageDown +# - ScrollLineUp +# - ScrollLineDown +# - ScrollToTop +# - ScrollToBottom +# - ClearHistory +# - Hide +# - Quit +# - ClearLogNotice +# - SpawnNewInstance +# - ToggleFullscreen +# - None +# +# Values for `action` (macOS only): +# - ToggleSimpleFullscreen: Enters fullscreen without occupying another space +# +# Values for `command`: +# The `command` field must be a map containing a `program` string and +# an `args` array of command line parameter strings. +# +# Example: +# `command: { program: "alacritty", args: ["-e", "vttest"] }` +# +# Values for `mode`: +# - ~AppCursor +# - AppCursor +# - ~AppKeypad +# - AppKeypad +key_bindings: + # (Windows/Linux only) + #- { key: V, mods: Control|Shift, action: Paste } + #- { key: C, mods: Control|Shift, action: Copy } + #- { key: Insert, mods: Shift, action: PasteSelection } + #- { key: Key0, mods: Control, action: ResetFontSize } + #- { key: Equals, mods: Control, action: IncreaseFontSize } + #- { key: Add, mods: Control, action: IncreaseFontSize } + #- { key: Subtract, mods: Control, action: DecreaseFontSize } + #- { key: Minus, mods: Control, action: DecreaseFontSize } + #- { key: Return, mods: Alt, action: ToggleFullscreen } + + # (macOS only) + #- { key: Key0, mods: Command, action: ResetFontSize } + #- { key: Equals, mods: Command, action: IncreaseFontSize } + #- { key: Add, mods: Command, action: IncreaseFontSize } + #- { key: Minus, mods: Command, action: DecreaseFontSize } + #- { key: K, mods: Command, action: ClearHistory } + #- { key: K, mods: Command, chars: "\x0c" } + #- { key: V, mods: Command, action: Paste } + #- { key: C, mods: Command, action: Copy } + #- { key: H, mods: Command, action: Hide } + #- { key: Q, mods: Command, action: Quit } + #- { key: W, mods: Command, action: Quit } + #- { key: F, mods: Command|Control, action: ToggleFullscreen } + + - { key: Paste, action: Paste } + - { key: Copy, action: Copy } + - { key: L, mods: Control, action: ClearLogNotice } + - { key: L, mods: Control, chars: "\x0c" } + - { key: Home, mods: Alt, chars: "\x1b[1;3H" } + - { key: Home, chars: "\x1bOH", mode: AppCursor } + - { key: Home, chars: "\x1b[H", mode: ~AppCursor } + - { key: End, mods: Alt, chars: "\x1b[1;3F" } + - { key: End, chars: "\x1bOF", mode: AppCursor } + - { key: End, chars: "\x1b[F", mode: ~AppCursor } + - { key: PageUp, mods: Shift, action: ScrollPageUp, mode: ~Alt } + - { key: PageUp, mods: Shift, chars: "\x1b[5;2~", mode: Alt } + - { key: PageUp, mods: Control, chars: "\x1b[5;5~" } + - { key: PageUp, mods: Alt, chars: "\x1b[5;3~" } + - { key: PageUp, chars: "\x1b[5~" } + - { key: PageDown, mods: Shift, action: ScrollPageDown, mode: ~Alt } + - { key: PageDown, mods: Shift, chars: "\x1b[6;2~", mode: Alt } + - { key: PageDown, mods: Control, chars: "\x1b[6;5~" } + - { key: PageDown, mods: Alt, chars: "\x1b[6;3~" } + - { key: PageDown, chars: "\x1b[6~" } + - { key: Tab, mods: Shift, chars: "\x1b[Z" } + - { key: Back, chars: "\x7f" } + - { key: Back, mods: Alt, chars: "\x1b\x7f" } + - { key: Insert, chars: "\x1b[2~" } + - { key: Delete, chars: "\x1b[3~" } + - { key: Left, mods: Shift, chars: "\x1b[1;2D" } + - { key: Left, mods: Control, chars: "\x1b[1;5D" } + - { key: Left, mods: Alt, chars: "\x1b[1;3D" } + - { key: Left, chars: "\x1b[D", mode: ~AppCursor } + - { key: Left, chars: "\x1bOD", mode: AppCursor } + - { key: Right, mods: Shift, chars: "\x1b[1;2C" } + - { key: Right, mods: Control, chars: "\x1b[1;5C" } + - { key: Right, mods: Alt, chars: "\x1b[1;3C" } + - { key: Right, chars: "\x1b[C", mode: ~AppCursor } + - { key: Right, chars: "\x1bOC", mode: AppCursor } + - { key: Up, mods: Shift, chars: "\x1b[1;2A" } + - { key: Up, mods: Control, chars: "\x1b[1;5A" } + - { key: Up, mods: Alt, chars: "\x1b[1;3A" } + - { key: Up, chars: "\x1b[A", mode: ~AppCursor } + - { key: Up, chars: "\x1bOA", mode: AppCursor } + - { key: Down, mods: Shift, chars: "\x1b[1;2B" } + - { key: Down, mods: Control, chars: "\x1b[1;5B" } + - { key: Down, mods: Alt, chars: "\x1b[1;3B" } + - { key: Down, chars: "\x1b[B", mode: ~AppCursor } + - { key: Down, chars: "\x1bOB", mode: AppCursor } + - { key: F1, chars: "\x1bOP" } + - { key: F2, chars: "\x1bOQ" } + - { key: F3, chars: "\x1bOR" } + - { key: F4, chars: "\x1bOS" } + - { key: F5, chars: "\x1b[15~" } + - { key: F6, chars: "\x1b[17~" } + - { key: F7, chars: "\x1b[18~" } + - { key: F8, chars: "\x1b[19~" } + - { key: F9, chars: "\x1b[20~" } + - { key: F10, chars: "\x1b[21~" } + - { key: F11, chars: "\x1b[23~" } + - { key: F12, chars: "\x1b[24~" } + - { key: F1, mods: Shift, chars: "\x1b[1;2P" } + - { key: F2, mods: Shift, chars: "\x1b[1;2Q" } + - { key: F3, mods: Shift, chars: "\x1b[1;2R" } + - { key: F4, mods: Shift, chars: "\x1b[1;2S" } + - { key: F5, mods: Shift, chars: "\x1b[15;2~" } + - { key: F6, mods: Shift, chars: "\x1b[17;2~" } + - { key: F7, mods: Shift, chars: "\x1b[18;2~" } + - { key: F8, mods: Shift, chars: "\x1b[19;2~" } + - { key: F9, mods: Shift, chars: "\x1b[20;2~" } + - { key: F10, mods: Shift, chars: "\x1b[21;2~" } + - { key: F11, mods: Shift, chars: "\x1b[23;2~" } + - { key: F12, mods: Shift, chars: "\x1b[24;2~" } + - { key: F1, mods: Control, chars: "\x1b[1;5P" } + - { key: F2, mods: Control, chars: "\x1b[1;5Q" } + - { key: F3, mods: Control, chars: "\x1b[1;5R" } + - { key: F4, mods: Control, chars: "\x1b[1;5S" } + - { key: F5, mods: Control, chars: "\x1b[15;5~" } + - { key: F6, mods: Control, chars: "\x1b[17;5~" } + - { key: F7, mods: Control, chars: "\x1b[18;5~" } + - { key: F8, mods: Control, chars: "\x1b[19;5~" } + - { key: F9, mods: Control, chars: "\x1b[20;5~" } + - { key: F10, mods: Control, chars: "\x1b[21;5~" } + - { key: F11, mods: Control, chars: "\x1b[23;5~" } + - { key: F12, mods: Control, chars: "\x1b[24;5~" } + - { key: F1, mods: Alt, chars: "\x1b[1;6P" } + - { key: F2, mods: Alt, chars: "\x1b[1;6Q" } + - { key: F3, mods: Alt, chars: "\x1b[1;6R" } + - { key: F4, mods: Alt, chars: "\x1b[1;6S" } + - { key: F5, mods: Alt, chars: "\x1b[15;6~" } + - { key: F6, mods: Alt, chars: "\x1b[17;6~" } + - { key: F7, mods: Alt, chars: "\x1b[18;6~" } + - { key: F8, mods: Alt, chars: "\x1b[19;6~" } + - { key: F9, mods: Alt, chars: "\x1b[20;6~" } + - { key: F10, mods: Alt, chars: "\x1b[21;6~" } + - { key: F11, mods: Alt, chars: "\x1b[23;6~" } + - { key: F12, mods: Alt, chars: "\x1b[24;6~" } + - { key: F1, mods: Super, chars: "\x1b[1;3P" } + - { key: F2, mods: Super, chars: "\x1b[1;3Q" } + - { key: F3, mods: Super, chars: "\x1b[1;3R" } + - { key: F4, mods: Super, chars: "\x1b[1;3S" } + - { key: F5, mods: Super, chars: "\x1b[15;3~" } + - { key: F6, mods: Super, chars: "\x1b[17;3~" } + - { key: F7, mods: Super, chars: "\x1b[18;3~" } + - { key: F8, mods: Super, chars: "\x1b[19;3~" } + - { key: F9, mods: Super, chars: "\x1b[20;3~" } + - { key: F10, mods: Super, chars: "\x1b[21;3~" } + - { key: F11, mods: Super, chars: "\x1b[23;3~" } + - { key: F12, mods: Super, chars: "\x1b[24;3~" } + - { key: NumpadEnter, chars: "\n" }
A i3/.config/alacritty/alacritty.yml-default

@@ -0,0 +1,573 @@

+# Configuration for Alacritty, the GPU enhanced terminal emulator. + +# Any items in the `env` entry below will be added as +# environment variables. Some entries may override variables +# set by alacritty itself. +#env: + # TERM variable + # + # This value is used to set the `$TERM` environment variable for + # each instance of Alacritty. If it is not present, alacritty will + # check the local terminfo database and use `alacritty` if it is + # available, otherwise `xterm-256color` is used. + #TERM: xterm-256color + +#window: + # Window dimensions (changes require restart) + # + # Specified in number of columns/lines, not pixels. + # If both are `0`, this setting is ignored. + #dimensions: + # columns: 0 + # lines: 0 + + # Window position (changes require restart) + # + # Specified in number of pixels. + # If the position is not set, the window manager will handle the placement. + #position: + # x: 0 + # y: 0 + + # Window padding (changes require restart) + # + # Blank space added around the window in pixels. This padding is scaled + # by DPI and the specified value is always added at both opposing sides. + #padding: + # x: 0 + # y: 0 + + # Spread additional padding evenly around the terminal content. + #dynamic_padding: false + + # Window decorations + # + # Values for `decorations`: + # - full: Borders and title bar + # - none: Neither borders nor title bar + # + # Values for `decorations` (macOS only): + # - transparent: Title bar, transparent background and title bar buttons + # - buttonless: Title bar, transparent background, but no title bar buttons + #decorations: full + + # Startup Mode (changes require restart) + # + # Values for `startup_mode`: + # - Windowed + # - Maximized + # - Fullscreen + # + # Values for `startup_mode` (macOS only): + # - SimpleFullscreen + #startup_mode: Windowed + + # Window title + #title: Alacritty + + # Window class (Linux/BSD only): + #class: + # Application instance name + #instance: Alacritty + # General application class + #general: Alacritty + + # GTK theme variant (Linux/BSD only) + # + # Override the variant of the GTK theme. Commonly supported values are `dark` and `light`. + # Set this to `None` to use the default theme variant. + #gtk_theme_variant: None + +#scrolling: + # Maximum number of lines in the scrollback buffer. + # Specifying '0' will disable scrolling. + #history: 10000 + + # Number of lines the viewport will move for every line scrolled when + # scrollback is enabled (history > 0). + #multiplier: 3 + +# Spaces per Tab (changes require restart) +# +# This setting defines the width of a tab in cells. +# +# Some applications, like Emacs, rely on knowing about the width of a tab. +# To prevent unexpected behavior in these applications, it's also required to +# change the `it` value in terminfo when altering this setting. +#tabspaces: 8 + +# Font configuration +#font: + # Normal (roman) font face + #normal: + # Font family + # + # Default: + # - (macOS) Menlo + # - (Linux/BSD) monospace + # - (Windows) Consolas + #family: monospace + + # The `style` can be specified to pick a specific face. + #style: Regular + + # Bold font face + #bold: + # Font family + # + # If the bold family is not specified, it will fall back to the + # value specified for the normal font. + #family: monospace + + # The `style` can be specified to pick a specific face. + #style: Bold + + # Italic font face + #italic: + # Font family + # + # If the italic family is not specified, it will fall back to the + # value specified for the normal font. + #family: monospace + + # The `style` can be specified to pick a specific face. + #style: Italic + + # Bold italic font face + #bold_italic: + # Font family + # + # If the bold italic family is not specified, it will fall back to the + # value specified for the normal font. + #family: monospace + + # The `style` can be specified to pick a specific face. + #style: Bold Italic + + # Point size + #size: 11.0 + + # Offset is the extra space around each character. `offset.y` can be thought of + # as modifying the line spacing, and `offset.x` as modifying the letter spacing. + #offset: + # x: 0 + # y: 0 + + # Glyph offset determines the locations of the glyphs within their cells with + # the default being at the bottom. Increasing `x` moves the glyph to the right, + # increasing `y` moves the glyph upwards. + #glyph_offset: + # x: 0 + # y: 0 + + # Thin stroke font rendering (macOS only) + # + # Thin strokes are suitable for retina displays, but for non-retina screens + # it is recommended to set `use_thin_strokes` to `false` + # + # macOS >= 10.14.x: + # + # If the font quality on non-retina display looks bad then set + # `use_thin_strokes` to `true` and enable font smoothing by running the + # following command: + # `defaults write -g CGFontRenderingFontSmoothingDisabled -bool NO` + # + # This is a global setting and will require a log out or restart to take + # effect. + #use_thin_strokes: true + +# If `true`, bold text is drawn using the bright color variants. +#draw_bold_text_with_bright_colors: false + +# Colors (Tomorrow Night Bright) +#colors: + # Default colors + #primary: + # background: '0x000000' + # foreground: '0xeaeaea' + + # Bright and dim foreground colors + # + # The dimmed foreground color is calculated automatically if it is not present. + # If the bright foreground color is not set, or `draw_bold_text_with_bright_colors` + # is `false`, the normal foreground color will be used. + #dim_foreground: '0x9a9a9a' + #bright_foreground: '0xffffff' + + # Cursor colors + # + # Colors which should be used to draw the terminal cursor. If these are unset, + # the cursor color will be the inverse of the cell color. + #cursor: + # text: '0x000000' + # cursor: '0xffffff' + + # Selection colors + # + # Colors which should be used to draw the selection area. If selection + # background is unset, selection color will be the inverse of the cell colors. + # If only text is unset the cell text color will remain the same. + #selection: + # text: '0xeaeaea' + # background: '0x404040' + + # Normal colors + #normal: + # black: '0x000000' + # red: '0xd54e53' + # green: '0xb9ca4a' + # yellow: '0xe6c547' + # blue: '0x7aa6da' + # magenta: '0xc397d8' + # cyan: '0x70c0ba' + # white: '0xeaeaea' + + # Bright colors + #bright: + # black: '0x666666' + # red: '0xff3334' + # green: '0x9ec400' + # yellow: '0xe7c547' + # blue: '0x7aa6da' + # magenta: '0xb77ee0' + # cyan: '0x54ced6' + # white: '0xffffff' + + # Dim colors + # + # If the dim colors are not set, they will be calculated automatically based + # on the `normal` colors. + #dim: + # black: '0x000000' + # red: '0x8c3336' + # green: '0x7a8530' + # yellow: '0x97822e' + # blue: '0x506d8f' + # magenta: '0x80638e' + # cyan: '0x497e7a' + # white: '0x9a9a9a' + + # Indexed Colors + # + # The indexed colors include all colors from 16 to 256. + # When these are not set, they're filled with sensible defaults. + # + # Example: + # `- { index: 16, color: '0xff00ff' }` + # + #indexed_colors: [] + +# Visual Bell +# +# Any time the BEL code is received, Alacritty "rings" the visual bell. Once +# rung, the terminal background will be set to white and transition back to the +# default background color. You can control the rate of this transition by +# setting the `duration` property (represented in milliseconds). You can also +# configure the transition function by setting the `animation` property. +# +# Values for `animation`: +# - Ease +# - EaseOut +# - EaseOutSine +# - EaseOutQuad +# - EaseOutCubic +# - EaseOutQuart +# - EaseOutQuint +# - EaseOutExpo +# - EaseOutCirc +# - Linear +# +# Specifying a `duration` of `0` will disable the visual bell. +#visual_bell: +# animation: EaseOutExpo +# duration: 0 +# color: '0xffffff' + +# Background opacity +# +# Window opacity as a floating point number from `0.0` to `1.0`. +# The value `0.0` is completely transparent and `1.0` is opaque. +#background_opacity: 1.0 + +#selection: + #semantic_escape_chars: ",│`|:\"' ()[]{}<>\t" + + # When set to `true`, selected text will be copied to the primary clipboard. + #save_to_clipboard: false + +# Allow terminal applications to change Alacritty's window title. +#dynamic_title: true + +#cursor: + # Cursor style + # + # Values for `style`: + # - ▇ Block + # - _ Underline + # - | Beam + #style: Block + + # If this is `true`, the cursor will be rendered as a hollow box when the + # window is not focused. + #unfocused_hollow: true + +# Live config reload (changes require restart) +#live_config_reload: true + +# Shell +# +# You can set `shell.program` to the path of your favorite shell, e.g. `/bin/fish`. +# Entries in `shell.args` are passed unmodified as arguments to the shell. +# +# Default: +# - (macOS) /bin/bash --login +# - (Linux/BSD) user login shell +# - (Windows) powershell +#shell: +# program: /bin/bash +# args: +# - --login + +# Startup directory +# +# Directory the shell is started in. If this is unset, or `None`, the working +# directory of the parent process will be used. +#working_directory: None + +# WinPTY backend (Windows only) +# +# Alacritty defaults to using the newer ConPTY backend if it is available, +# since it resolves a lot of bugs and is quite a bit faster. If it is not +# available, the the WinPTY backend will be used instead. +# +# Setting this option to `true` makes Alacritty use the legacy WinPTY backend, +# even if the ConPTY backend is available. +#winpty_backend: false + +# Send ESC (\x1b) before characters when alt is pressed. +#alt_send_esc: true + +#debug: + # Display the time it takes to redraw each frame. + #render_timer: false + + # Keep the log file after quitting Alacritty. + #persistent_logging: false + + # Log level + # + # Values for `log_level`: + # - None + # - Error + # - Warn + # - Info + # - Debug + # - Trace + #log_level: Warn + + # Print all received window events. + #print_events: false + + # Record all characters and escape sequences as test data. + #ref_test: false + +#mouse: + # Click settings + # + # The `double_click` and `triple_click` settings control the time + # alacritty should wait for accepting multiple clicks as one double + # or triple click. + #double_click: { threshold: 300 } + #triple_click: { threshold: 300 } + + # If this is `true`, the cursor is temporarily hidden when typing. + #hide_when_typing: false + + #url: + # URL launcher + # + # This program is executed when clicking on a text which is recognized as a URL. + # The URL is always added to the command as the last parameter. + # + # When set to `None`, URL launching will be disabled completely. + # + # Default: + # - (macOS) open + # - (Linux/BSD) xdg-open + # - (Windows) explorer + #launcher: + # program: xdg-open + # args: [] + + # URL modifiers + # + # These are the modifiers that need to be held down for opening URLs when clicking + # on them. The available modifiers are documented in the key binding section. + #modifiers: None + +# Mouse bindings +# +# Mouse bindings are specified as a list of objects, much like the key +# bindings further below. +# +# To trigger mouse bindings when an application running within Alacritty captures the mouse, the +# `Shift` modifier is automatically added as a requirement. +# +# Each mouse binding will specify a: +# +# - `mouse`: +# +# - Middle +# - Left +# - Right +# - Numeric identifier such as `5` +# +# - `action` (see key bindings) +# +# And optionally: +# +# - `mods` (see key bindings) +#mouse_bindings: +# - { mouse: Middle, action: PasteSelection } + +# Key bindings +# +# Key bindings are specified as a list of objects. For example, this is the +# default paste binding: +# +# `- { key: V, mods: Control|Shift, action: Paste }` +# +# Each key binding will specify a: +# +# - `key`: Identifier of the key pressed +# +# - A-Z +# - F1-F24 +# - Key0-Key9 +# +# A full list with available key codes can be found here: +# https://docs.rs/glutin/*/glutin/event/enum.VirtualKeyCode.html#variants +# +# Instead of using the name of the keys, the `key` field also supports using +# the scancode of the desired key. Scancodes have to be specified as a +# decimal number. This command will allow you to display the hex scancodes +# for certain keys: +# +# `showkey --scancodes`. +# +# Then exactly one of: +# +# - `chars`: Send a byte sequence to the running application +# +# The `chars` field writes the specified string to the terminal. This makes +# it possible to pass escape sequences. To find escape codes for bindings +# like `PageUp` (`"\x1b[5~"`), you can run the command `showkey -a` outside +# of tmux. Note that applications use terminfo to map escape sequences back +# to keys. It is therefore required to update the terminfo when changing an +# escape sequence. +# +# - `action`: Execute a predefined action +# +# - Copy +# - Paste +# - PasteSelection +# - IncreaseFontSize +# - DecreaseFontSize +# - ResetFontSize +# - ScrollPageUp +# - ScrollPageDown +# - ScrollLineUp +# - ScrollLineDown +# - ScrollToTop +# - ScrollToBottom +# - ClearHistory +# - Hide +# - Minimize +# - Quit +# - ToggleFullscreen +# - SpawnNewInstance +# - ClearLogNotice +# - ReceiveChar +# - None +# +# (macOS only): +# - ToggleSimpleFullscreen: Enters fullscreen without occupying another space +# +# - `command`: Fork and execute a specified command plus arguments +# +# The `command` field must be a map containing a `program` string and an +# `args` array of command line parameter strings. For example: +# `{ program: "alacritty", args: ["-e", "vttest"] }` +# +# And optionally: +# +# - `mods`: Key modifiers to filter binding actions +# +# - Command +# - Control +# - Option +# - Super +# - Shift +# - Alt +# +# Multiple `mods` can be combined using `|` like this: +# `mods: Control|Shift`. +# Whitespace and capitalization are relevant and must match the example. +# +# - `mode`: Indicate a binding for only specific terminal reported modes +# +# This is mainly used to send applications the correct escape sequences +# when in different modes. +# +# - AppCursor +# - AppKeypad +# - Alt +# +# A `~` operator can be used before a mode to apply the binding whenever +# the mode is *not* active, e.g. `~Alt`. +# +# Bindings are always filled by default, but will be replaced when a new +# binding with the same triggers is defined. To unset a default binding, it can +# be mapped to the `ReceiveChar` action. Alternatively, you can use `None` for +# a no-op if you do not wish to receive input characters for that binding. +# +# If the same trigger is assigned to multiple actions, all of them are executed +# at once. +#key_bindings: + # (Windows, Linux, and BSD only) + #- { key: V, mods: Control|Shift, action: Paste } + #- { key: C, mods: Control|Shift, action: Copy } + #- { key: Insert, mods: Shift, action: PasteSelection } + #- { key: Key0, mods: Control, action: ResetFontSize } + #- { key: Equals, mods: Control, action: IncreaseFontSize } + #- { key: Add, mods: Control, action: IncreaseFontSize } + #- { key: Subtract, mods: Control, action: DecreaseFontSize } + #- { key: Minus, mods: Control, action: DecreaseFontSize } + + # (Windows only) + #- { key: Return, mods: Alt, action: ToggleFullscreen } + + # (macOS only) + #- { key: Key0, mods: Command, action: ResetFontSize } + #- { key: Equals, mods: Command, action: IncreaseFontSize } + #- { key: Add, mods: Command, action: IncreaseFontSize } + #- { key: Minus, mods: Command, action: DecreaseFontSize } + #- { key: K, mods: Command, action: ClearHistory } + #- { key: K, mods: Command, chars: "\x0c" } + #- { key: V, mods: Command, action: Paste } + #- { key: C, mods: Command, action: Copy } + #- { key: H, mods: Command, action: Hide } + #- { key: M, mods: Command, action: Minimize } + #- { key: Q, mods: Command, action: Quit } + #- { key: W, mods: Command, action: Quit } + #- { key: F, mods: Command|Control, action: ToggleFullscreen } + + #- { key: Paste, action: Paste } + #- { key: Copy, action: Copy } + #- { key: L, mods: Control, action: ClearLogNotice } + #- { key: L, mods: Control, chars: "\x0c" } + #- { key: PageUp, mods: Shift, action: ScrollPageUp, mode: ~Alt } + #- { key: PageDown, mods: Shift, action: ScrollPageDown, mode: ~Alt } + #- { key: Home, mods: Shift, action: ScrollToTop, mode: ~Alt } + #- { key: End, mods: Shift, action: ScrollToBottom, mode: ~Alt } +
A i3/.config/alacritty/nord.yml

@@ -0,0 +1,36 @@

+# Copyright (c) 2017-present Arctic Ice Studio <development@arcticicestudio.com> +# Copyright (c) 2017-present Sven Greb <code@svengreb.de> + +# Project: Nord Alacritty +# Version: 0.1.0 +# Repository: https://github.com/arcticicestudio/nord-alacritty +# License: MIT +# References: +# https://github.com/jwilm/alacritty + +colors: + primary: + background: '0x2E3440' + foreground: '0xD8DEE9' + cursor: + text: '0x2E3440' + cursor: '0xD8DEE9' + normal: + black: '0x3B4252' + red: '0xBF616A' + green: '0xA3BE8C' + yellow: '0xEBCB8B' + blue: '0x81A1C1' + magenta: '0xB48EAD' + cyan: '0x88C0D0' + white: '0xE5E9F0' + bright: + black: '0x4C566A' + red: '0xBF616A' + green: '0xA3BE8C' + yellow: '0xEBCB8B' + blue: '0x81A1C1' + magenta: '0xB48EAD' + cyan: '0x8FBCBB' + white: '0xECEFF4' +
A i3/.config/compton/compton.conf

@@ -0,0 +1,226 @@

+# Thank you code_nomad: http://9m.no/ꪯ鵞 +# and Arch Wiki contributors: https://wiki.archlinux.org/index.php/Compton + +################################# +# +# Backend +# +################################# + +# Backend to use: "xrender" or "glx". +# GLX backend is typically much faster but depends on a sane driver. +backend = "glx"; + +################################# +# +# GLX backend +# +################################# + +glx-no-stencil = true; + +# GLX backend: Copy unmodified regions from front buffer instead of redrawing them all. +# My tests with nvidia-drivers show a 10% decrease in performance when the whole screen is modified, +# but a 20% increase when only 1/4 is. +# My tests on nouveau show terrible slowdown. +glx-copy-from-front = false; + +# GLX backend: Use MESA_copy_sub_buffer to do partial screen update. +# My tests on nouveau shows a 200% performance boost when only 1/4 of the screen is updated. +# May break VSync and is not available on some drivers. +# Overrides --glx-copy-from-front. +# glx-use-copysubbuffermesa = true; + +# GLX backend: Avoid rebinding pixmap on window damage. +# Probably could improve performance on rapid window content changes, but is known to break things on some drivers (LLVMpipe). +# Recommended if it works. +# glx-no-rebind-pixmap = true; + +# GLX backend: GLX buffer swap method we assume. +# Could be undefined (0), copy (1), exchange (2), 3-6, or buffer-age (-1). +# undefined is the slowest and the safest, and the default value. +# copy is fastest, but may fail on some drivers, +# 2-6 are gradually slower but safer (6 is still faster than 0). +# Usually, double buffer means 2, triple buffer means 3. +# buffer-age means auto-detect using GLX_EXT_buffer_age, supported by some drivers. +# Useless with --glx-use-copysubbuffermesa. +# Partially breaks --resize-damage. +# Defaults to undefined. +#glx-swap-method = "undefined"; + +################################# +# +# Shadows +# +################################# + +# Enabled client-side shadows on windows. +shadow = true; +# The blur radius for shadows. (default 12) +shadow-radius = 8; +# The left offset for shadows. (default -15) +shadow-offset-x = -8; +# The top offset for shadows. (default -15) +shadow-offset-y = -8; +# The translucency for shadows. (default .75) +shadow-opacity = 0.5; + +# Set if you want different colour shadows +# shadow-red = 0.0; +# shadow-green = 0.0; +# shadow-blue = 0.0; + +# The shadow exclude options are helpful if you have shadows enabled. Due to the way compton draws its shadows, certain applications will have visual glitches +# (most applications are fine, only apps that do weird things with xshapes or argb are affected). +# This list includes all the affected apps I found in my testing. The "! name~=''" part excludes shadows on any "Unknown" windows, this prevents a visual glitch with the XFWM alt tab switcher. +shadow-exclude = [ + "! name~=''", + "name = 'Notification'", + "name = 'Plank'", + "name = 'Docky'", + "name = 'Kupfer'", + "name = 'xfce4-notifyd'", + "name *= 'VLC'", + "name *= 'compton'", + "name *= 'Chromium'", + "name *= 'Chrome'", + "class_g = 'Firefox' && argb", + "class_g = 'Conky'", + "class_g = 'Kupfer'", + "class_g = 'Synapse'", + "class_g ?= 'Notify-osd'", + "class_g ?= 'Cairo-dock'", + "class_g ?= 'Xfce4-notifyd'", + "class_g ?= 'Xfce4-power-manager'", + "_GTK_FRAME_EXTENTS@:c", + "_NET_WM_STATE@:32a *= '_NET_WM_STATE_HIDDEN'" +]; +# Avoid drawing shadow on all shaped windows (see also: --detect-rounded-corners) +shadow-ignore-shaped = false; + +################################# +# +# Opacity +# +################################# + +inactive-opacity = 1; +active-opacity = 1; +frame-opacity = 1; +inactive-opacity-override = false; + +# Dim inactive windows. (0.0 - 1.0) +# inactive-dim = 0.2; +# Do not let dimness adjust based on window opacity. +# inactive-dim-fixed = true; +# Blur background of transparent windows. Bad performance with X Render backend. GLX backend is preferred. +# blur-background = true; +# Blur background of opaque windows with transparent frames as well. +# blur-background-frame = true; +# Do not let blur radius adjust based on window opacity. +blur-background-fixed = false; +blur-background-exclude = [ + "window_type = 'dock'", + "window_type = 'desktop'" +]; + +################################# +# +# Fading +# +################################# + +# Fade windows during opacity changes. +fading = false; +# The time between steps in a fade in milliseconds. (default 10). +fade-delta = 1; +# Opacity change between steps while fading in. (default 0.028). +fade-in-step = 0.03; +# Opacity change between steps while fading out. (default 0.03). +fade-out-step = 0.03; +# Fade windows in/out when opening/closing +no-fading-openclose = true; + +# Specify a list of conditions of windows that should not be faded. +fade-exclude = [ ]; + +################################# +# +# Other +# +################################# + +# Try to detect WM windows and mark them as active. +mark-wmwin-focused = true; +# Mark all non-WM but override-redirect windows active (e.g. menus). +mark-ovredir-focused = true; +# Use EWMH _NET_WM_ACTIVE_WINDOW to determine which window is focused instead of using FocusIn/Out events. +# Usually more reliable but depends on a EWMH-compliant WM. +use-ewmh-active-win = true; +# Detect rounded corners and treat them as rectangular when --shadow-ignore-shaped is on. +detect-rounded-corners = true; + +# Detect _NET_WM_OPACITY on client windows, useful for window managers not passing _NET_WM_OPACITY of client windows to frame windows. +# This prevents opacity being ignored for some apps. +# For example without this enabled my xfce4-notifyd is 100% opacity no matter what. +detect-client-opacity = true; + +# Specify refresh rate of the screen. +# If not specified or 0, compton will try detecting this with X RandR extension. +refresh-rate = 0; + +# Vertical synchronization: match the refresh rate of the monitor +vsync = true; + +# Enable DBE painting mode, intended to use with VSync to (hopefully) eliminate tearing. +# Reported to have no effect, though. +dbe = false; + +# Limit compton to repaint at most once every 1 / refresh_rate second to boost performance. +# This should not be used with --vsync drm/opengl/opengl-oml as they essentially does --sw-opti's job already, +# unless you wish to specify a lower refresh rate than the actual value. +#sw-opti = true; + +# Unredirect all windows if a full-screen opaque window is detected, to maximize performance for full-screen windows, like games. +# Known to cause flickering when redirecting/unredirecting windows. +unredir-if-possible = false; + +# Specify a list of conditions of windows that should always be considered focused. +focus-exclude = [ ]; + +# Use WM_TRANSIENT_FOR to group windows, and consider windows in the same group focused at the same time. +detect-transient = true; +# Use WM_CLIENT_LEADER to group windows, and consider windows in the same group focused at the same time. +# WM_TRANSIENT_FOR has higher priority if --detect-transient is enabled, too. +detect-client-leader = true; + +################################# +# +# Window type settings +# +################################# + +wintypes: +{ + tooltip = + { + # fade: Fade the particular type of windows. + fade = true; + # shadow: Give those windows shadow + shadow = false; + # opacity: Default opacity for the type of windows. + opacity = 0.85; + # focus: Whether to always consider windows of this type focused. + focus = true; + }; +}; + +###################### +# +# XSync +# See: https://github.com/yshui/compton/commit/b18d46bcbdc35a3b5620d817dd46fbc76485c20d +# +###################### + +# Use X Sync fence to sync clients' draw calls. Needed on nvidia-drivers with GLX backend for some users. +xrender-sync-fence = true;
A i3/.config/i3/brightness.sh

@@ -0,0 +1,30 @@

+#!/bin/sh + +# brightness.sh: this script exists because, on my ThinkPad X1 Yoga, as the +# screen brightness _value_ increases/decreases linearly, actual brightness +# does NOT increase/decrease linearly, so I had to make a hack that would +# inc/dec the value accordingly + +current_brightness="$(xbacklight -get | cut -f1 -d'.')" # convert float->int +level=2 # default level + +if [ "$current_brightness" -lt "1" ]; then # brightness < 1 + level=0.2 +elif [ "$current_brightness" -lt "5" ]; then # brightness < 5 + level=0.8 +elif [ "$current_brightness" -lt "11" ]; then # brightness < 11 + level=1.5 +elif [ "$current_brightness" -lt "21" ]; then # brightness < 21 + level=3 +elif [ "$current_brightness" -lt "51" ]; then # brightness < 51 + level=6 +else # brightness >= 50 + level=10 +fi + +if [ "$1" == "inc" ]; then + xbacklight -inc "$level" +elif [ "$1" == "dec" ]; then + xbacklight -dec "$level" +fi +
A i3/.config/i3/config

@@ -0,0 +1,298 @@

+# This file has been auto-generated by i3-config-wizard(1). +# It will not be overwritten, so edit it as you like. + +# i3 config file (v4) + +############## +# defaults # +############## + +# Note: to get a list of available keys (keysyms) for use in key combos, run +# `xmodmap -pke` + +# get current user (because I don't 100% trust '~' in this config) +#set_from_resource $user echo "$USER" + +# set modifier key to "Windows" key +set $mod Mod4 + +# Font for window titles. Will also be used by the bar unless a different font +# is used in the bar {} block below. +font pango:monospace 8 + +# This font is widely installed, provides lots of unicode glyphs, right-to-left +# text rendering and scalability on retina/hidpi displays (thanks to pango). +#font pango:DejaVu Sans Mono 8 + +# Use Mouse+$mod to drag floating windows to their wanted position +floating_modifier $mod + +# start a terminal +bindsym $mod+Return exec alacritty + +# start alternate terminal +#bindsym $mod+Shift+Return exec urxvt + +# kill focused window +bindsym $mod+Shift+q kill + +# start dmenu (a program launcher) +#bindsym $mod+d exec dmenu_run + +# start Rofi (my dmenu replacement) +bindsym $mod+d exec --no-startup-id rofi -show run + +# change focus +bindsym $mod+j focus left +bindsym $mod+k focus down +bindsym $mod+l focus up +bindsym $mod+semicolon focus right + +# alternatively, you can use the cursor keys: +bindsym $mod+Left focus left +bindsym $mod+Down focus down +bindsym $mod+Up focus up +bindsym $mod+Right focus right + +# move focused window +bindsym $mod+Shift+j move left +bindsym $mod+Shift+k move down +bindsym $mod+Shift+l move up +bindsym $mod+Shift+semicolon move right + +# alternatively, you can use the cursor keys: +bindsym $mod+Shift+Left move left +bindsym $mod+Shift+Down move down +bindsym $mod+Shift+Up move up +bindsym $mod+Shift+Right move right + +# split in horizontal orientation +bindsym $mod+h split h + +# split in vertical orientation +bindsym $mod+v split v + +# enter fullscreen mode for the focused container +bindsym $mod+f fullscreen toggle + +# change container layout (stacked, tabbed, toggle split) +bindsym $mod+s layout stacking +bindsym $mod+w layout tabbed +bindsym $mod+e layout toggle split + +# toggle tiling / floating +bindsym $mod+Shift+space floating toggle + +# change focus between tiling / floating windows +bindsym $mod+space focus mode_toggle + +# focus the parent container +bindsym $mod+a focus parent + +# focus the child container +#bindsym $mod+d focus child + +#navigate workspaces next / previous +bindsym $mod+Ctrl+Right workspace next +bindsym $mod+Ctrl+Left workspace prev + +# Define names for default workspaces for which we configure key bindings later on. +# We use variables to avoid repeating the names in multiple places. +set $ws1 "1" +set $ws2 "2" +set $ws3 "3" +set $ws4 "4" +set $ws5 "5" +set $ws6 "6" +set $ws7 "7" +set $ws8 "8" +set $ws9 "9" +set $ws10 "10" +set $ws11 "11" +set $ws12 "12" + +# switch to workspace +bindsym $mod+1 workspace $ws1 +bindsym $mod+2 workspace $ws2 +bindsym $mod+3 workspace $ws3 +bindsym $mod+4 workspace $ws4 +bindsym $mod+5 workspace $ws5 +bindsym $mod+6 workspace $ws6 +bindsym $mod+7 workspace $ws7 +bindsym $mod+8 workspace $ws8 +bindsym $mod+9 workspace $ws9 +bindsym $mod+0 workspace $ws10 +bindsym $mod+minus workspace $ws11 +bindsym $mod+equal workspace $ws12 + +# move focused container to workspace +bindsym $mod+Shift+1 move container to workspace $ws1 +bindsym $mod+Shift+2 move container to workspace $ws2 +bindsym $mod+Shift+3 move container to workspace $ws3 +bindsym $mod+Shift+4 move container to workspace $ws4 +bindsym $mod+Shift+5 move container to workspace $ws5 +bindsym $mod+Shift+6 move container to workspace $ws6 +bindsym $mod+Shift+7 move container to workspace $ws7 +bindsym $mod+Shift+8 move container to workspace $ws8 +bindsym $mod+Shift+9 move container to workspace $ws9 +bindsym $mod+Shift+0 move container to workspace $ws10 +bindsym $mod+Shift+minus move container to workspace $ws11 +bindsym $mod+Shift+equal move container to workspace $ws12 + +# reload the configuration file +bindsym $mod+Shift+c reload +# restart i3 inplace (preserves your layout/session, can be used to upgrade i3) +bindsym $mod+Shift+r restart +# exit i3 (logs you out of your X session) +bindsym $mod+Shift+e exec "i3-nagbar -t warning -m 'You pressed the exit shortcut. Do you really want to exit i3? This will end your X session.' -B 'Yes, exit i3' 'i3-msg exit'" + + +bindsym $mod+r mode "resize" + +# resize window (you can also use the mouse for that) +mode "resize" { + # These bindings trigger as soon as you enter the resize mode + + # Pressing left will shrink the window’s width. + # Pressing right will grow the window’s width. + # Pressing up will shrink the window’s height. + # Pressing down will grow the window’s height. + bindsym j resize shrink width 2 px or 2 ppt + bindsym k resize grow height 2 px or 2 ppt + bindsym l resize shrink height 2 px or 2 ppt + bindsym semicolon resize grow width 2 px or 2 ppt + + # same bindings, but for the arrow keys + bindsym Left resize shrink width 2 px or 2 ppt + bindsym Down resize grow height 2 px or 2 ppt + bindsym Up resize shrink height 2 px or 2 ppt + bindsym Right resize grow width 2 px or 2 ppt + + # back to normal: Enter or Escape or $mod+r + bindsym Return mode "default" + bindsym Escape mode "default" + bindsym $mod+r mode "default" +} + +# Start i3bar to display a workspace bar (plus the system information i3status +# finds out, if available) +#bar { +# status_command i3status +# position top +# height 25 +#} + +# Start i3bar to display a workspace bar (plus the system information i3status if available) +bar { + i3bar_command i3bar + status_command i3status + position top + +## please set your primary output first. Example: 'xrandr --output eDP1 --primary' +# tray_output primary +# tray_output eDP1 + + #bindsym button4 nop # use to disable + bindsym button4 workspace next + bindsym button5 workspace prev + font xft:URWGothic-Book 16 + strip_workspace_numbers yes + + colors { + background #222D31 + statusline #F9FAF9 + separator #454947 + +# border backgr. text + focused_workspace #F9FAF9 #16a085 #292F34 + active_workspace #595B5B #353836 #FDF6E3 + inactive_workspace #595B5B #222D31 #EEE8D5 + binding_mode #16a085 #2C2C2C #F9FAF9 + urgent_workspace #16a085 #FDF6E3 #E5201D + } +} + +# just in case I want my polubar again +#exec_always --no-startup-id ~/.config/polybar/launch.sh + +# TODO: figure out clipit +#exec --no-startup-id clipit + +############################ +# window border settings # +############################ + +# sets border for default windows, not floating +# default_border pixel 2 +default_border pixel 1 +# floating windows get a 'normal' border +default_floating_border normal +# class border backgr indicator-text +#client.focused #888888 #888888 #111111 +#client.unfocused #222222 #222222 #bbbbbb +#client.focused_inactive #111111 #111111 #bbbbbb +#client.urgent #383a3b #383a3b #ee0000 + + +###################### +# i3 gaps settings # +###################### + +# sets gap size in between individual windows +gaps inner 20 +# sets gap size in between windows and the edge of the monitor +gaps outer 2 + +# remove/add gaps +bindsym $mod+g gaps inner all toggle 20 + +####################### +# set screenlocking # +####################### + +# starts xautolock, which forks to background and listens for user inactivity. +# If inactivity after '-time' minutes, execute '-locker' string as a command +# note: I'm still not sure if this line does anything. I think you might +# just have to run the command by itself one in the shell. +#exec xautolock -detectsleep -noclose -time 12 -locker "$HOME/.config/i3/screenlocker.sh" + +# locks the screen after pressing Mod+Q (Windows + Q in my setup) +bindsym $mod+q exec "$HOME/.config/i3/screenlocker.sh" + +####################################### +# use feh to set desktop background # +####################################### + +# 'desktop' background changed below +# TODO: maybe replace with variable if posssible +#exec_always feh --bg-fill "$HOME/Library/Images/Wallpapers/archer/archer-mallorys-office3.jpg" +exec_always feh --bg-fill "$HOME/Library/Images/Wallpapers/archer/archer-mallorys-office2.jpg" +# runs compositor, needed for effects, (really for st transparency) +#exec --no-startup-id compton -b --config ~/.config/compton/compton.conf +## TODO replace + +##################################################### +# set ThinkPad X1 Yoga volume/brightness controls # +##################################################### + +bindsym XF86AudioRaiseVolume exec --no-startup-id pactl set-sink-volume 0 +5% +bindsym XF86AudioLowerVolume exec --no-startup-id pactl set-sink-volume 0 -5% +bindsym XF86AudioMute exec --no-startup-id pactl set-sink-mute 0 toggle + +# Screen brightness controls +bindsym XF86MonBrightnessUp exec "xbacklight -inc 10; notify-send 'brightness up'" +bindsym XF86MonBrightnessDown exec "xbacklight -dec 10; notify-send 'brightness down'" + + +############################# +# start KDEConnect daemon # +############################# + +#exec /usr/lib/kdeconnectd +# TODO change + +######################## +# moar to be done... # +######################## + +
A i3/.config/i3/config-manjaro-default

@@ -0,0 +1,418 @@

+# i3 config file (v4) +# Please see http://i3wm.org/docs/userguide.html for a complete reference! + +# Set mod key (Mod1=<Alt>, Mod4=<Super>) +set $mod Mod4 + +# set default desktop layout (default is tiling) +# workspace_layout tabbed <stacking|tabbed> + +# Configure border style <normal|1pixel|pixel xx|none|pixel> +default_border pixel 1 +default_floating_border normal + +# Hide borders +hide_edge_borders none + +# change borders +bindsym $mod+u border none +bindsym $mod+y border pixel 1 +bindsym $mod+n border normal + +# Font for window titles. Will also be used by the bar unless a different font +# is used in the bar {} block below. +font xft:URWGothic-Book 11 + +# Use Mouse+$mod to drag floating windows +floating_modifier $mod + +# start a terminal +bindsym $mod+Return exec terminal + +# kill focused window +bindsym $mod+Shift+q kill + +# start program launcher +bindsym $mod+d exec --no-startup-id dmenu_recency + +# launch categorized menu +bindsym $mod+z exec --no-startup-id morc_menu + +################################################################################################ +## sound-section - DO NOT EDIT if you wish to automatically upgrade Alsa -> Pulseaudio later! ## +################################################################################################ + +exec --no-startup-id volumeicon +bindsym $mod+Ctrl+m exec terminal -e 'alsamixer' +#exec --no-startup-id pulseaudio +#exec --no-startup-id pa-applet +#bindsym $mod+Ctrl+m exec pavucontrol + +################################################################################################ + +# Screen brightness controls +bindsym XF86MonBrightnessUp exec "xbacklight -inc 10; notify-send 'brightness up'" +bindsym XF86MonBrightnessDown exec "xbacklight -dec 10; notify-send 'brightness down'" + +# Start Applications +bindsym $mod+Ctrl+b exec terminal -e 'bmenu' +bindsym $mod+F2 exec palemoon +bindsym $mod+F3 exec pcmanfm +# bindsym $mod+F3 exec ranger +bindsym $mod+Shift+F3 exec pcmanfm_pkexec +bindsym $mod+F5 exec terminal -e 'mocp' +bindsym $mod+t exec --no-startup-id pkill picom +bindsym $mod+Ctrl+t exec --no-startup-id picom -b +bindsym $mod+Shift+d --release exec "killall dunst; exec notify-send 'restart dunst'" +bindsym Print exec --no-startup-id i3-scrot +bindsym $mod+Print --release exec --no-startup-id i3-scrot -w +bindsym $mod+Shift+Print --release exec --no-startup-id i3-scrot -s +bindsym $mod+Shift+h exec xdg-open /usr/share/doc/manjaro/i3_help.pdf +bindsym $mod+Ctrl+x --release exec --no-startup-id xkill + +# focus_follows_mouse no + +# change focus +bindsym $mod+j focus left +bindsym $mod+k focus down +bindsym $mod+l focus up +bindsym $mod+semicolon focus right + +# alternatively, you can use the cursor keys: +bindsym $mod+Left focus left +bindsym $mod+Down focus down +bindsym $mod+Up focus up +bindsym $mod+Right focus right + +# move focused window +bindsym $mod+Shift+j move left +bindsym $mod+Shift+k move down +bindsym $mod+Shift+l move up +bindsym $mod+Shift+semicolon move right + +# alternatively, you can use the cursor keys: +bindsym $mod+Shift+Left move left +bindsym $mod+Shift+Down move down +bindsym $mod+Shift+Up move up +bindsym $mod+Shift+Right move right + +# workspace back and forth (with/without active container) +workspace_auto_back_and_forth yes +bindsym $mod+b workspace back_and_forth +bindsym $mod+Shift+b move container to workspace back_and_forth; workspace back_and_forth + +# split orientation +bindsym $mod+h split h;exec notify-send 'tile horizontally' +bindsym $mod+v split v;exec notify-send 'tile vertically' +bindsym $mod+q split toggle + +# toggle fullscreen mode for the focused container +bindsym $mod+f fullscreen toggle + +# change container layout (stacked, tabbed, toggle split) +bindsym $mod+s layout stacking +bindsym $mod+w layout tabbed +bindsym $mod+e layout toggle split + +# toggle tiling / floating +bindsym $mod+Shift+space floating toggle + +# change focus between tiling / floating windows +bindsym $mod+space focus mode_toggle + +# toggle sticky +bindsym $mod+Shift+s sticky toggle + +# focus the parent container +bindsym $mod+a focus parent + +# move the currently focused window to the scratchpad +bindsym $mod+Shift+minus move scratchpad + +# Show the next scratchpad window or hide the focused scratchpad window. +# If there are multiple scratchpad windows, this command cycles through them. +bindsym $mod+minus scratchpad show + +#navigate workspaces next / previous +bindsym $mod+Ctrl+Right workspace next +bindsym $mod+Ctrl+Left workspace prev + +# Workspace names +# to display names or symbols instead of plain workspace numbers you can use +# something like: set $ws1 1:mail +# set $ws2 2: +set $ws1 1 +set $ws2 2 +set $ws3 3 +set $ws4 4 +set $ws5 5 +set $ws6 6 +set $ws7 7 +set $ws8 8 + +# switch to workspace +bindsym $mod+1 workspace $ws1 +bindsym $mod+2 workspace $ws2 +bindsym $mod+3 workspace $ws3 +bindsym $mod+4 workspace $ws4 +bindsym $mod+5 workspace $ws5 +bindsym $mod+6 workspace $ws6 +bindsym $mod+7 workspace $ws7 +bindsym $mod+8 workspace $ws8 + +# Move focused container to workspace +bindsym $mod+Ctrl+1 move container to workspace $ws1 +bindsym $mod+Ctrl+2 move container to workspace $ws2 +bindsym $mod+Ctrl+3 move container to workspace $ws3 +bindsym $mod+Ctrl+4 move container to workspace $ws4 +bindsym $mod+Ctrl+5 move container to workspace $ws5 +bindsym $mod+Ctrl+6 move container to workspace $ws6 +bindsym $mod+Ctrl+7 move container to workspace $ws7 +bindsym $mod+Ctrl+8 move container to workspace $ws8 + +# Move to workspace with focused container +bindsym $mod+Shift+1 move container to workspace $ws1; workspace $ws1 +bindsym $mod+Shift+2 move container to workspace $ws2; workspace $ws2 +bindsym $mod+Shift+3 move container to workspace $ws3; workspace $ws3 +bindsym $mod+Shift+4 move container to workspace $ws4; workspace $ws4 +bindsym $mod+Shift+5 move container to workspace $ws5; workspace $ws5 +bindsym $mod+Shift+6 move container to workspace $ws6; workspace $ws6 +bindsym $mod+Shift+7 move container to workspace $ws7; workspace $ws7 +bindsym $mod+Shift+8 move container to workspace $ws8; workspace $ws8 + +# Open applications on specific workspaces +# assign [class="Thunderbird"] $ws1 +# assign [class="Pale moon"] $ws2 +# assign [class="Pcmanfm"] $ws3 +# assign [class="Skype"] $ws5 + +# Open specific applications in floating mode +for_window [title="alsamixer"] floating enable border pixel 1 +for_window [class="calamares"] floating enable border normal +for_window [class="Clipgrab"] floating enable +for_window [title="File Transfer*"] floating enable +for_window [class="fpakman"] floating enable +for_window [class="Galculator"] floating enable border pixel 1 +for_window [class="GParted"] floating enable border normal +for_window [title="i3_help"] floating enable sticky enable border normal +for_window [class="Lightdm-settings"] floating enable +for_window [class="Lxappearance"] floating enable sticky enable border normal +for_window [class="Manjaro-hello"] floating enable +for_window [class="Manjaro Settings Manager"] floating enable border normal +for_window [title="MuseScore: Play Panel"] floating enable +for_window [class="Nitrogen"] floating enable sticky enable border normal +for_window [class="Oblogout"] fullscreen enable +for_window [class="octopi"] floating enable +for_window [title="About Pale Moon"] floating enable +for_window [class="Pamac-manager"] floating enable +for_window [class="Pavucontrol"] floating enable +for_window [class="qt5ct"] floating enable sticky enable border normal +for_window [class="Qtconfig-qt4"] floating enable sticky enable border normal +for_window [class="Simple-scan"] floating enable border normal +for_window [class="(?i)System-config-printer.py"] floating enable border normal +for_window [class="Skype"] floating enable border normal +for_window [class="Timeset-gui"] floating enable border normal +for_window [class="(?i)virtualbox"] floating enable border normal +for_window [class="Xfburn"] floating enable + +# switch to workspace with urgent window automatically +for_window [urgent=latest] focus + +# reload the configuration file +bindsym $mod+Shift+c reload + +# restart i3 inplace (preserves your layout/session, can be used to upgrade i3) +bindsym $mod+Shift+r restart + +# exit i3 (logs you out of your X session) +bindsym $mod+Shift+e exec "i3-nagbar -t warning -m 'You pressed the exit shortcut. Do you really want to exit i3? This will end your X session.' -b 'Yes, exit i3' 'i3-msg exit'" + +# Set shut down, restart and locking features +bindsym $mod+0 mode "$mode_system" +set $mode_system (l)ock, (e)xit, switch_(u)ser, (s)uspend, (h)ibernate, (r)eboot, (Shift+s)hutdown +mode "$mode_system" { + bindsym l exec --no-startup-id i3exit lock, mode "default" + bindsym s exec --no-startup-id i3exit suspend, mode "default" + bindsym u exec --no-startup-id i3exit switch_user, mode "default" + bindsym e exec --no-startup-id i3exit logout, mode "default" + bindsym h exec --no-startup-id i3exit hibernate, mode "default" + bindsym r exec --no-startup-id i3exit reboot, mode "default" + bindsym Shift+s exec --no-startup-id i3exit shutdown, mode "default" + + # exit system mode: "Enter" or "Escape" + bindsym Return mode "default" + bindsym Escape mode "default" +} + +# Resize window (you can also use the mouse for that) +bindsym $mod+r mode "resize" +mode "resize" { + # These bindings trigger as soon as you enter the resize mode + # Pressing left will shrink the window’s width. + # Pressing right will grow the window’s width. + # Pressing up will shrink the window’s height. + # Pressing down will grow the window’s height. + bindsym j resize shrink width 5 px or 5 ppt + bindsym k resize grow height 5 px or 5 ppt + bindsym l resize shrink height 5 px or 5 ppt + bindsym semicolon resize grow width 5 px or 5 ppt + + # same bindings, but for the arrow keys + bindsym Left resize shrink width 10 px or 10 ppt + bindsym Down resize grow height 10 px or 10 ppt + bindsym Up resize shrink height 10 px or 10 ppt + bindsym Right resize grow width 10 px or 10 ppt + + # exit resize mode: Enter or Escape + bindsym Return mode "default" + bindsym Escape mode "default" +} + +# Lock screen +bindsym $mod+9 exec --no-startup-id blurlock + +# Autostart applications +exec --no-startup-id /usr/lib/polkit-gnome/polkit-gnome-authentication-agent-1 +exec --no-startup-id nitrogen --restore; sleep 1; picom -b +exec --no-startup-id manjaro-hello +exec --no-startup-id nm-applet +exec --no-startup-id xfce4-power-manager +exec --no-startup-id pamac-tray +exec --no-startup-id clipit +# exec --no-startup-id blueman-applet +# exec_always --no-startup-id sbxkb +exec --no-startup-id start_conky_maia +# exec --no-startup-id start_conky_green +exec --no-startup-id xautolock -time 10 -locker blurlock +exec_always --no-startup-id ff-theme-util +exec_always --no-startup-id fix_xcursor + +# Color palette used for the terminal ( ~/.Xresources file ) +# Colors are gathered based on the documentation: +# https://i3wm.org/docs/userguide.html#xresources +# Change the variable name at the place you want to match the color +# of your terminal like this: +# [example] +# If you want your bar to have the same background color as your +# terminal background change the line 362 from: +# background #14191D +# to: +# background $term_background +# Same logic applied to everything else. +set_from_resource $term_background background +set_from_resource $term_foreground foreground +set_from_resource $term_color0 color0 +set_from_resource $term_color1 color1 +set_from_resource $term_color2 color2 +set_from_resource $term_color3 color3 +set_from_resource $term_color4 color4 +set_from_resource $term_color5 color5 +set_from_resource $term_color6 color6 +set_from_resource $term_color7 color7 +set_from_resource $term_color8 color8 +set_from_resource $term_color9 color9 +set_from_resource $term_color10 color10 +set_from_resource $term_color11 color11 +set_from_resource $term_color12 color12 +set_from_resource $term_color13 color13 +set_from_resource $term_color14 color14 +set_from_resource $term_color15 color15 + +# Start i3bar to display a workspace bar (plus the system information i3status if available) +bar { + i3bar_command i3bar + status_command i3status + position top + +## please set your primary output first. Example: 'xrandr --output eDP1 --primary' +# tray_output primary +# tray_output eDP1 + + bindsym button4 nop + bindsym button5 nop +# font xft:URWGothic-Book 11 + strip_workspace_numbers yes + + colors { + background #222D31 + statusline #F9FAF9 + separator #454947 + +# border backgr. text + focused_workspace #F9FAF9 #16a085 #292F34 + active_workspace #595B5B #353836 #FDF6E3 + inactive_workspace #595B5B #222D31 #EEE8D5 + binding_mode #16a085 #2C2C2C #F9FAF9 + urgent_workspace #16a085 #FDF6E3 #E5201D + } +} + +# hide/unhide i3status bar +bindsym $mod+m bar mode toggle + +# Theme colors +# class border backgr. text indic. child_border + client.focused #556064 #556064 #80FFF9 #FDF6E3 + client.focused_inactive #2F3D44 #2F3D44 #1ABC9C #454948 + client.unfocused #2F3D44 #2F3D44 #1ABC9C #454948 + client.urgent #CB4B16 #FDF6E3 #1ABC9C #268BD2 + client.placeholder #000000 #0c0c0c #ffffff #000000 + + client.background #2B2C2B + +############################# +### settings for i3-gaps: ### +############################# + +# Set inner/outer gaps +gaps inner 14 +gaps outer -2 + +# Additionally, you can issue commands with the following syntax. This is useful to bind keys to changing the gap size. +# gaps inner|outer current|all set|plus|minus <px> +# gaps inner all set 10 +# gaps outer all plus 5 + +# Smart gaps (gaps used if only more than one container on the workspace) +smart_gaps on + +# Smart borders (draw borders around container only if it is not the only container on this workspace) +# on|no_gaps (on=always activate and no_gaps=only activate if the gap size to the edge of the screen is 0) +smart_borders on + +# Press $mod+Shift+g to enter the gap mode. Choose o or i for modifying outer/inner gaps. Press one of + / - (in-/decrement for current workspace) or 0 (remove gaps for current workspace). If you also press Shift with these keys, the change will be global for all workspaces. +set $mode_gaps Gaps: (o) outer, (i) inner +set $mode_gaps_outer Outer Gaps: +|-|0 (local), Shift + +|-|0 (global) +set $mode_gaps_inner Inner Gaps: +|-|0 (local), Shift + +|-|0 (global) +bindsym $mod+Shift+g mode "$mode_gaps" + +mode "$mode_gaps" { + bindsym o mode "$mode_gaps_outer" + bindsym i mode "$mode_gaps_inner" + bindsym Return mode "default" + bindsym Escape mode "default" +} +mode "$mode_gaps_inner" { + bindsym plus gaps inner current plus 5 + bindsym minus gaps inner current minus 5 + bindsym 0 gaps inner current set 0 + + bindsym Shift+plus gaps inner all plus 5 + bindsym Shift+minus gaps inner all minus 5 + bindsym Shift+0 gaps inner all set 0 + + bindsym Return mode "default" + bindsym Escape mode "default" +} +mode "$mode_gaps_outer" { + bindsym plus gaps outer current plus 5 + bindsym minus gaps outer current minus 5 + bindsym 0 gaps outer current set 0 + + bindsym Shift+plus gaps outer all plus 5 + bindsym Shift+minus gaps outer all minus 5 + bindsym Shift+0 gaps outer all set 0 + + bindsym Return mode "default" + bindsym Escape mode "default" +}
A i3/.config/i3/old_i3_config/battlemode.sh

@@ -0,0 +1,42 @@

+#!/usr/bin/env bash + +# battlemode.sh +# written by x1phosura +# +# This shell script merely switches i3 configs and restarts i3 to apply the +# changes, but one of the configs is a so-called "battlemode," which is +# sorta exciting I guess. I completely stole this idea from my friend Ethan, +# a fellow Arch i3 dweeb, and I'm really only writing this (besides it being +# cool) because I wanna beat him to it, in case he hasn't implemented his own +# yet. + +# This battlemode script is also totally expandable in the future. One could +# add multiple different modes, each with their own file, and other stuff too +# +# Note: there is no 'include' directive or other way to include configurations +# from other files in i3. Technically there's a thing for Xresources, but +# that limits you to Xresources, and is still somewhat limiting. So while this +# isn't the ideal way to implement a "battle mode," it's the most elegant +# solution I could think of given i3's limitation on sourcing configs +# elsewhere. + + +# directory where i3 configs are stored +I3CONFDIR="/home/$HOME/.config/i3" + +# perform the 'ol switcheroo +if [ -e "$I3CONFDIR"/config ]; then + mv "$I3CONFDIR"/config "$I3CONFDIR"/config.temp + + if [ -e "$I3CONFDIR"/config.other ]; then + mv "$I3CONFDIR"/config.other "$I3CONFDIR"/config + mv "$I3CONFDIR"/config.temp "$I3CONFDIR"/config.other + else + mv "$I3CONFDIR"/config.temp "$I3CONFDIR"/config + fi + + # reloads and restarts i3 + i3-msg reload + i3-msg restart +fi +
A i3/.config/i3/old_i3_config/config

@@ -0,0 +1,235 @@

+# This file has been auto-generated by i3-config-wizard(1). +# It will not be overwritten, so edit it as you like. + +# i3 config file (v4) + +# get current user +set_from_resource $user echo "$USER" + +set $mod Mod4 + +# Font for window titles. Will also be used by the bar unless a different font +# is used in the bar {} block below. +font pango:monospace 8 + +# This font is widely installed, provides lots of unicode glyphs, right-to-left +# text rendering and scalability on retina/hidpi displays (thanks to pango). +#font pango:DejaVu Sans Mono 8 + +# Use Mouse+$mod to drag floating windows to their wanted position +floating_modifier $mod + +# start a terminal +bindsym $mod+Return exec st +bindsym $mod+Shift+Return exec urxvt + +# kill focused window +bindsym $mod+Shift+q kill + +# start dmenu (a program launcher) +bindsym $mod+d exec --no-startup-id dmenu_run + +# change focus +bindsym $mod+j focus left +bindsym $mod+k focus down +bindsym $mod+l focus up +bindsym $mod+semicolon focus right + +# alternatively, you can use the cursor keys: +bindsym $mod+Left focus left +bindsym $mod+Down focus down +bindsym $mod+Up focus up +bindsym $mod+Right focus right + +# move focused window +bindsym $mod+Shift+j move left +bindsym $mod+Shift+k move down +bindsym $mod+Shift+l move up +bindsym $mod+Shift+semicolon move right + +# alternatively, you can use the cursor keys: +bindsym $mod+Shift+Left move left +bindsym $mod+Shift+Down move down +bindsym $mod+Shift+Up move up +bindsym $mod+Shift+Right move right + +# split in horizontal orientation +bindsym $mod+h split h + +# split in vertical orientation +bindsym $mod+v split v + +# enter fullscreen mode for the focused container +bindsym $mod+f fullscreen toggle + +# change container layout (stacked, tabbed, toggle split) +bindsym $mod+s layout stacking +bindsym $mod+w layout tabbed +bindsym $mod+e layout toggle split + +# toggle tiling / floating +bindsym $mod+Shift+space floating toggle + +# change focus between tiling / floating windows +bindsym $mod+space focus mode_toggle + +# focus the parent container +bindsym $mod+a focus parent + +# focus the child container +#bindsym $mod+d focus child + +# Define names for default workspaces for which we configure key bindings later on. +# We use variables to avoid repeating the names in multiple places. +set $ws1 "1" +set $ws2 "2" +set $ws3 "3" +set $ws4 "4" +set $ws5 "5" +set $ws6 "6" +set $ws7 "7" +set $ws8 "8" +set $ws9 "9" +set $ws10 "10" + +# switch to workspace +bindsym $mod+1 workspace $ws1 +bindsym $mod+2 workspace $ws2 +bindsym $mod+3 workspace $ws3 +bindsym $mod+4 workspace $ws4 +bindsym $mod+5 workspace $ws5 +bindsym $mod+6 workspace $ws6 +bindsym $mod+7 workspace $ws7 +bindsym $mod+8 workspace $ws8 +bindsym $mod+9 workspace $ws9 +bindsym $mod+0 workspace $ws10 + +# move focused container to workspace +bindsym $mod+Shift+1 move container to workspace $ws1 +bindsym $mod+Shift+2 move container to workspace $ws2 +bindsym $mod+Shift+3 move container to workspace $ws3 +bindsym $mod+Shift+4 move container to workspace $ws4 +bindsym $mod+Shift+5 move container to workspace $ws5 +bindsym $mod+Shift+6 move container to workspace $ws6 +bindsym $mod+Shift+7 move container to workspace $ws7 +bindsym $mod+Shift+8 move container to workspace $ws8 +bindsym $mod+Shift+9 move container to workspace $ws9 +bindsym $mod+Shift+0 move container to workspace $ws10 + +# reload the configuration file +bindsym $mod+Shift+c reload +# restart i3 inplace (preserves your layout/session, can be used to upgrade i3) +bindsym $mod+Shift+r restart +# exit i3 (logs you out of your X session) +bindsym $mod+Shift+e exec "i3-nagbar -t warning -m 'You pressed the exit shortcut. Do you really want to exit i3? This will end your X session.' -b 'Yes, exit i3' 'i3-msg exit'" + +# resize window (you can also use the mouse for that) +mode "resize" { + # These bindings trigger as soon as you enter the resize mode + + # Pressing left will shrink the window’s width. + # Pressing right will grow the window’s width. + # Pressing up will shrink the window’s height. + # Pressing down will grow the window’s height. + bindsym j resize shrink width 5 px or 5 ppt + bindsym k resize grow height 5 px or 5 ppt + bindsym l resize shrink height 5 px or 5 ppt + bindsym semicolon resize grow width 5 px or 5 ppt + + # same bindings, but for the arrow keys + bindsym Left resize shrink width 5 px or 5 ppt + bindsym Down resize grow height 5 px or 5 ppt + bindsym Up resize shrink height 5 px or 5 ppt + bindsym Right resize grow width 5 px or 5 ppt + + # back to normal: Enter or Escape or $mod+r + bindsym Return mode "default" + bindsym Escape mode "default" + bindsym $mod+r mode "default" +} + +bindsym $mod+r mode "resize" + +# Start i3bar to display a workspace bar (plus the system information i3status +# finds out, if available) +bar { + status_command i3status + position top + height 25 + font pango:DejaVu Sans Mono 9 + colors { + background #1a1a1a + } +} + +############################## +# window border settings # +############################## + +# sets border for default windows, not floating +default_border pixel 2 +# floating windows get a 'normal' border +default_floating_border normal +# class border backgr indicator-text +client.focused #888888 #888888 #111111 +client.unfocused #222222 #222222 #bbbbbb +client.focused_inactive #111111 #111111 #bbbbbb +client.urgent #383a3b #383a3b #ee0000 + + +######################### +# i3 gaps settings # +######################### + +# sets gap size in between individual windows +gaps inner 20 +# sets gap size in between windows and the edge of the monitor +gaps outer 2 + + +######################################### +# use feh to set desktop background # +######################################### + +# 'desktop' background changed below +#exec_always feh --bg-fill '/home/$user/Pictures/Backgrounds/rainbow/rainbow-stripe-DARK.jpg' +exec_always feh --bg-fill '/home/$user/Pictures/Wallpapers/rainbow/rainbow-triangles1.jpg' +# runs compositor, needed for effects, (really for st transparency) +exec compton + + +############################# +# Pulse Audio controls # +############################# + +# increase sound volume +bindsym XF86AudioRaiseVolume exec --no-startup-id pactl set-sink-volume 0 +5% +# decrease sound volume +bindsym XF86AudioLowerVolume exec --no-startup-id pactl set-sink-volume 0 -5% +# mute sound +bindsym XF86AudioMute exec --no-startup-id pactl set-sink-mute 0 toggle + + +######################## +# Screen-locking # +######################## + +# starts xautolock, which forks to background and listens for user inactivity. +# If inactivity after '-time' minutes, execute '-locker' string as a command +# note: I'm still not sure if this line does anything. I think you might +# just have to run the command by itself one in the shell. +exec xautolock -detectsleep -noclose -time 12 -locker "$HOME/.config/i3/screenlocker.sh" + +# locks the screen after pressing Mod+Q (Windows + Q in my setup) +bindsym $mod+q exec "$HOME/.config/i3/screenlocker.sh" + + +##################### +# "Battle mode" # +##################### + +# runs a shell script, which switches the i3 config file and restarts i3, +# putting it into "battle mode." To go back, run "battle" mode again, +# which will run the script again and switch configs +bindsym XF86Launch1 exec --no-startup-id "$HOME/.config/i3/battlemode.sh" +
A i3/.config/i3/old_i3_config/config.other

@@ -0,0 +1,235 @@

+# This file has been auto-generated by i3-config-wizard(1). +# It will not be overwritten, so edit it as you like. + +# i3 config file (v4) + +# get current user +set_from_resource $user echo "$USER" + +set $mod Mod4 + +# Font for window titles. Will also be used by the bar unless a different font +# is used in the bar {} block below. +font pango:monospace 8 + +# This font is widely installed, provides lots of unicode glyphs, right-to-left +# text rendering and scalability on retina/hidpi displays (thanks to pango). +#font pango:DejaVu Sans Mono 8 + +# Use Mouse+$mod to drag floating windows to their wanted position +floating_modifier $mod + +# start a terminal +bindsym $mod+Return exec st +bindsym $mod+Shift+Return exec urxvt + +# kill focused window +bindsym $mod+Shift+q kill + +# start dmenu (a program launcher) +bindsym $mod+d exec --no-startup-id dmenu_run + +# change focus +bindsym $mod+j focus left +bindsym $mod+k focus down +bindsym $mod+l focus up +bindsym $mod+semicolon focus right + +# alternatively, you can use the cursor keys: +bindsym $mod+Left focus left +bindsym $mod+Down focus down +bindsym $mod+Up focus up +bindsym $mod+Right focus right + +# move focused window +bindsym $mod+Shift+j move left +bindsym $mod+Shift+k move down +bindsym $mod+Shift+l move up +bindsym $mod+Shift+semicolon move right + +# alternatively, you can use the cursor keys: +bindsym $mod+Shift+Left move left +bindsym $mod+Shift+Down move down +bindsym $mod+Shift+Up move up +bindsym $mod+Shift+Right move right + +# split in horizontal orientation +bindsym $mod+h split h + +# split in vertical orientation +bindsym $mod+v split v + +# enter fullscreen mode for the focused container +bindsym $mod+f fullscreen toggle + +# change container layout (stacked, tabbed, toggle split) +bindsym $mod+s layout stacking +bindsym $mod+w layout tabbed +bindsym $mod+e layout toggle split + +# toggle tiling / floating +bindsym $mod+Shift+space floating toggle + +# change focus between tiling / floating windows +bindsym $mod+space focus mode_toggle + +# focus the parent container +bindsym $mod+a focus parent + +# focus the child container +#bindsym $mod+d focus child + +# Define names for default workspaces for which we configure key bindings later on. +# We use variables to avoid repeating the names in multiple places. +set $ws1 "1" +set $ws2 "2" +set $ws3 "3" +set $ws4 "4" +set $ws5 "5" +set $ws6 "6" +set $ws7 "7" +set $ws8 "8" +set $ws9 "9" +set $ws10 "10" + +# switch to workspace +bindsym $mod+1 workspace $ws1 +bindsym $mod+2 workspace $ws2 +bindsym $mod+3 workspace $ws3 +bindsym $mod+4 workspace $ws4 +bindsym $mod+5 workspace $ws5 +bindsym $mod+6 workspace $ws6 +bindsym $mod+7 workspace $ws7 +bindsym $mod+8 workspace $ws8 +bindsym $mod+9 workspace $ws9 +bindsym $mod+0 workspace $ws10 + +# move focused container to workspace +bindsym $mod+Shift+1 move container to workspace $ws1 +bindsym $mod+Shift+2 move container to workspace $ws2 +bindsym $mod+Shift+3 move container to workspace $ws3 +bindsym $mod+Shift+4 move container to workspace $ws4 +bindsym $mod+Shift+5 move container to workspace $ws5 +bindsym $mod+Shift+6 move container to workspace $ws6 +bindsym $mod+Shift+7 move container to workspace $ws7 +bindsym $mod+Shift+8 move container to workspace $ws8 +bindsym $mod+Shift+9 move container to workspace $ws9 +bindsym $mod+Shift+0 move container to workspace $ws10 + +# reload the configuration file +bindsym $mod+Shift+c reload +# restart i3 inplace (preserves your layout/session, can be used to upgrade i3) +bindsym $mod+Shift+r restart +# exit i3 (logs you out of your X session) +bindsym $mod+Shift+e exec "i3-nagbar -t warning -m 'You pressed the exit shortcut. Do you really want to exit i3? This will end your X session.' -b 'Yes, exit i3' 'i3-msg exit'" + +# resize window (you can also use the mouse for that) +mode "resize" { + # These bindings trigger as soon as you enter the resize mode + + # Pressing left will shrink the window’s width. + # Pressing right will grow the window’s width. + # Pressing up will shrink the window’s height. + # Pressing down will grow the window’s height. + bindsym j resize shrink width 5 px or 5 ppt + bindsym k resize grow height 5 px or 5 ppt + bindsym l resize shrink height 5 px or 5 ppt + bindsym semicolon resize grow width 5 px or 5 ppt + + # same bindings, but for the arrow keys + bindsym Left resize shrink width 5 px or 5 ppt + bindsym Down resize grow height 5 px or 5 ppt + bindsym Up resize shrink height 5 px or 5 ppt + bindsym Right resize grow width 5 px or 5 ppt + + # back to normal: Enter or Escape or $mod+r + bindsym Return mode "default" + bindsym Escape mode "default" + bindsym $mod+r mode "default" +} + +bindsym $mod+r mode "resize" + +# Start i3bar to display a workspace bar (plus the system information i3status +# finds out, if available) +bar { + status_command i3status + position top + height 25 + font pango:DejaVu Sans Mono 9 + colors { + background #1a1a1a + } +} + +############################## +# window border settings # +############################## + +# sets border for default windows, not floating +default_border pixel 2 +# floating windows get a 'normal' border +default_floating_border normal +# class border backgr indicator-text +client.focused #888888 #888888 #111111 +client.unfocused #222222 #222222 #bbbbbb +client.focused_inactive #111111 #111111 #bbbbbb +client.urgent #383a3b #383a3b #ee0000 + + +######################### +# i3 gaps settings # +######################### + +# sets gap size in between individual windows +gaps inner 20 +# sets gap size in between windows and the edge of the monitor +gaps outer 2 + + +######################################### +# use feh to set desktop background # +######################################### + +# 'desktop' background changed below +exec_always feh --bg-fill '/home/$user/Pictures/Wallpapers/rainbow/rainbow-stripe-DARK.jpg' +#exec_always feh --bg-fill '/home/$user/Pictures/Backgrounds/rainbow/rainbow-triangles1.jpg' +# runs compositor, needed for effects, (really for st transparency) +exec compton + + +############################# +# Pulse Audio controls # +############################# + +# increase sound volume +bindsym XF86AudioRaiseVolume exec --no-startup-id pactl set-sink-volume 0 +5% +# decrease sound volume +bindsym XF86AudioLowerVolume exec --no-startup-id pactl set-sink-volume 0 -5% +# mute sound +bindsym XF86AudioMute exec --no-startup-id pactl set-sink-mute 0 toggle + + +######################## +# Screen-locking # +######################## + +# starts xautolock, which forks to background and listens for user inactivity. +# If inactivity after '-time' minutes, execute '-locker' string as a command +# note: I'm still not sure if this line does anything. I think you might +# just have to run the command by itself one in the shell. +exec xautolock -detectsleep -noclose -time 12 -locker "$HOME/.config/i3/screenlocker.sh" + +# locks the screen after pressing Mod+Q (Windows + Q in my setup) +bindsym $mod+q exec "$HOME/.config/i3/screenlocker.sh" + + +##################### +# "Battle mode" # +##################### + +# runs a shell script, which switches the i3 config file and restarts i3, +# putting it into "battle mode." To go back, run "battle" mode again, +# which will run the script again and switch configs +bindsym XF86Launch1 exec --no-startup-id "$HOME/.config/i3/battlemode.sh" +
A i3/.config/i3/old_i3_config/screenlocker.sh

@@ -0,0 +1,60 @@

+#!/usr/bin/env bash + +# script for locking my screen on Arch using i3lock +# thanks to http://www.michaelabrahamsen.com/posts/custom-lockscreen-i3lock/ + +# set icon and temporary photo location +icon="$HOME/.config/i3/icon.png" +tmpbg='/tmp/screenshot-temp.png' + +# cleans up if screenshot already exists because scrot won't overwrite +rm -f $tmpbg + +# takes a screenshot of the current screen +scrot "$tmpbg" + +# blur the screenshot by resizing and scaling back up +convert "$tmpbg" -filter Gaussian -thumbnail 20% -sample 500% "$tmpbg" + +# overlay the icon onto the temporary screenshot +convert "$tmpbg" "$icon" -gravity center -composite "$tmpbg" + + +# thank you to https://github.com/PandorasFox/i3lock-color/blob/master/lock.sh + +# colors for i3lock-color +B='#00000000' # blank or 'nothing' +D='#aaaaaacc' # default +W='#dd0000ff' # wrong red +V='#22bb88ff' # verifying + +# lock the screen with the blurred picture AND lock icon settings +i3lock \ +--insidevercolor=$V \ +--ringvercolor=$V \ +\ +--insidewrongcolor=$W \ +--ringwrongcolor=$W \ +\ +--insidecolor=$B \ +--ringcolor=$D \ +--linecolor=$B \ +--separatorcolor=$D \ +\ +--timecolor=$B \ +--datecolor=$B \ +\ +--verifcolor=$B \ +--wrongcolor=$B \ +--keyhlcolor='4466ccff' \ +--bshlcolor='000000ff' \ +\ +--screen 1 \ +--indicator \ +--indpos="x+40:h-840" \ +--verif-align 1 \ +--wrong-align 1 \ +--radius=25 \ +--ring-width=4 \ +-i "$tmpbg" +
A i3/.config/i3/old_i3_config/set-screenlocking-for-sleep.sh

@@ -0,0 +1,32 @@

+#!/usr/bin/env bash + +sleep_lock_service_file="/etc/systemd/system/screenlocker.service" + +if [ "$1" = "set" ] +then + touch "$sleep_lock_service_file" + + echo "[Unit] +Description=Starts i3lock on suspend +Before=sleep.target + +[Service] +User=$USER +Type=forking +Environment=DISPLAY=:0 +ExecStart=/home/$USER/.config/i3/screenlocker.sh + +[Install] +WantedBy=sleep.target" > "$sleep_lock_service_file" + systemctl enable screenlocker.service + printf "Screenlocking upon closed lid enabled.\n" +elif [ "$1" = "unset" ] +then + systemctl disable screenlocker.service + rm $sleep_lock_service_file + printf "Screenlocking upon closed lid disabled.\n" + +else + printf "Invalid arguments. Use 'set' or 'unset'.\n" +fi +
A i3/.config/i3/screenlocker.sh

@@ -0,0 +1,62 @@

+#!/usr/bin/env bash + +# script for locking my screen on Arch using i3lock +# x1phosura +# thanks to http://www.michaelabrahamsen.com/posts/custom-lockscreen-i3lock/ + +# set icon and temporary photo location +icon="$HOME/.config/i3/icon.png" +tmpbg='/tmp/screenshot-temp.png' + +# cleans up if screenshot already exists because scrot won't overwrite +rm -f $tmpbg + +# takes a screenshot of the current screen (relies on 'scrot' package) +scrot "$tmpbg" + +# blur the screenshot by resizing and scaling back up (relies on 'imagemagick') +convert "$tmpbg" -filter Gaussian -thumbnail 20% -sample 500% "$tmpbg" + +# overlay the icon onto the temporary screenshot +convert "$tmpbg" "$icon" -gravity center -composite "$tmpbg" + + +# thank you to https://github.com/PandorasFox/i3lock-color/blob/master/lock.sh + +# colors for i3lock-color +B='#00000000' # blank or 'nothing' +D='#aaaaaacc' # default +W='#dd0000ff' # wrong red +V='#22bb88ff' # verifying + +# lock the screen with the blurred picture AND lock icon settings +i3lock \ +--insidever-color=$V \ +--ringver-color=$V \ +\ +--insidewrong-color=$W \ +--ringwrong-color=$W \ +\ +--inside-color=$B \ +--ring-color=$D \ +--line-color=$B \ +--separator-color=$D \ +\ +--time-color=$B \ +--date-color=$B \ +\ +--verif-color=$B \ +--wrong-color=$B \ +--keyhl-color='4466ccff' \ +--bshl-color='000000ff' \ +\ +--screen 1 \ +--indicator \ +--ind-pos="x+1280:h-710" \ +--verif-align 1 \ +--wrong-align 1 \ +--radius=100 \ +--ring-width=4 \ +-i "$tmpbg" +# --image="$tmpbg" +
A i3/.config/i3/set-screenlocking-for-sleep.sh

@@ -0,0 +1,32 @@

+#!/usr/bin/env bash + +sleep_lock_service_file="/etc/systemd/system/screenlocker.service" + +screenlocker_file_contents="[Unit] +Description=Starts i3lock on suspend +Before=sleep.target + +[Service] +User=$USER +Type=forking +Environment=DISPLAY=:0 +ExecStart=/home/$USER/.config/i3/screenlocker.sh + +[Install] +WantedBy=sleep.target" + + +if [ "$1" = "set" ]; then + touch "$sleep_lock_service_file" + echo "$screenlocker_file_contents" > "$sleep_lock_service_file" + systemctl enable screenlocker.service + printf "Screenlocking upon closed lid enabled.\n" +elif [ "$1" = "unset" ]; then + systemctl disable screenlocker.service + rm "$sleep_lock_service_file" + printf "Screenlocking upon closed lid disabled.\n" + +else + printf "Invalid arguments. Use 'set' or 'unset'.\n" +fi +
A i3/.config/i3status/config

@@ -0,0 +1,82 @@

+# i3status configuration file. +# see "man i3status" for documentation. + +# It is important that this file is edited as UTF-8. +# The following line should contain a sharp s: +# ß +# If the above line is not correctly displayed, fix your editor first! + +general { + colors = true + interval = 5 + color_good = "#2AA198" + color_bad = "#586E75" + color_degraded = "#DC322F" +} + +# order += "ipv6" +order += "wireless _first_" +order += "ethernet _first_" +order += "cpu_usage" +order += "memory" +# order += "disk /" +# order += "disk /home" +order += "battery all" +# order += "load" +order += "tztime local" + +#wireless wlp4s0 { +wireless _first_ { + format_up = "W: (%quality at %essid, %bitrate) %ip" + format_down = "W: down" +} + +ethernet _first_ { +# if you use %speed, i3status requires root privileges + format_up = " lan: %ip %speed " + format_down = "" +} + +cpu_usage { + format = " cpu %usage " +} + +load { + format = " load %1min " + # max_threshold = 0.3 +} + +disk "/" { + # format = " hdd %avail " + format = " ⛁ %avail " +} + +battery all { + # format = "%status %percentage %remaining %emptytime" + format = " %status %percentage" + format_down = "No battery" + last_full_capacity = true + integer_battery_capacity = true + # status_chr = "" + status_chr = "⚡" + # status_bat = "bat" + # status_bat = "☉" + status_bat = "" + # status_unk = "?" + status_unk = "" + # status_full = "" + status_full = "☻" + low_threshold = 15 + threshold_type = time +} + +memory { + format = "%used | %available" + threshold_degraded = "1G" + format_degraded = "MEMORY < %available" +} + +tztime local { + format = "%Y-%m-%d %H:%M:%S" + #format = " %d.%m. %H:%M " +}
A i3/.config/picom/picom.conf

@@ -0,0 +1,267 @@

+# Thank you code_nomad: http://9m.no/ꪯ鵞 +# and Arch Wiki contributors: https://wiki.archlinux.org/index.php/Compton + +################################# +# +# Backend +# +################################# + +# Backend to use: "xrender" or "glx". +# GLX backend is typically much faster but depends on a sane driver. +backend = "glx"; + +################################# +# +# GLX backend +# +################################# + +glx-no-stencil = true; + +# GLX backend: Copy unmodified regions from front buffer instead of redrawing them all. +# My tests with nvidia-drivers show a 10% decrease in performance when the whole screen is modified, +# but a 20% increase when only 1/4 is. +# My tests on nouveau show terrible slowdown. +glx-copy-from-front = false; + +# GLX backend: Use MESA_copy_sub_buffer to do partial screen update. +# My tests on nouveau shows a 200% performance boost when only 1/4 of the screen is updated. +# May break VSync and is not available on some drivers. +# Overrides --glx-copy-from-front. +# glx-use-copysubbuffermesa = true; + +# GLX backend: Avoid rebinding pixmap on window damage. +# Probably could improve performance on rapid window content changes, but is known to break things on some drivers (LLVMpipe). +# Recommended if it works. +# glx-no-rebind-pixmap = true; + +# GLX backend: GLX buffer swap method we assume. +# Could be undefined (0), copy (1), exchange (2), 3-6, or buffer-age (-1). +# undefined is the slowest and the safest, and the default value. +# copy is fastest, but may fail on some drivers, +# 2-6 are gradually slower but safer (6 is still faster than 0). +# Usually, double buffer means 2, triple buffer means 3. +# buffer-age means auto-detect using GLX_EXT_buffer_age, supported by some drivers. +# Useless with --glx-use-copysubbuffermesa. +# Partially breaks --resize-damage. +# Defaults to undefined. +#glx-swap-method = "undefined"; #deprecated ! +#use-damage = true + +################################# +# +# Shadows +# +################################# + +# Enabled client-side shadows on windows. +shadow = true; +# The blur radius for shadows. (default 12) +shadow-radius = 5; +# The left offset for shadows. (default -15) +shadow-offset-x = 1; +# The top offset for shadows. (default -15) +shadow-offset-y = 1; +# The translucency for shadows. (default .75) +shadow-opacity = 0.3; + +# Set if you want different colour shadows +# shadow-red = 0.0; +# shadow-green = 0.0; +# shadow-blue = 0.0; + +# The shadow exclude options are helpful if you have shadows enabled. Due to the way picom draws its shadows, certain applications will have visual glitches +# (most applications are fine, only apps that do weird things with xshapes or argb are affected). +# This list includes all the affected apps I found in my testing. The "! name~=''" part excludes shadows on any "Unknown" windows, this prevents a visual glitch with the XFWM alt tab switcher. +shadow-exclude = [ + "! name~=''", + "name = 'Notification'", + "name = 'Plank'", + "name = 'Docky'", + "name = 'Kupfer'", + "name = 'xfce4-notifyd'", + "name *= 'VLC'", + "name *= 'compton'", + "name *= 'picom'", + "name *= 'Chromium'", + "name *= 'Chrome'", + "class_g = 'Firefox' && argb", + "class_g = 'Conky'", + "class_g = 'Kupfer'", + "class_g = 'Synapse'", + "class_g ?= 'Notify-osd'", + "class_g ?= 'Cairo-dock'", + "class_g ?= 'Xfce4-notifyd'", + "class_g ?= 'Xfce4-power-manager'", + "class_g ?= 'Dmenu'", +# "class_g ?= 'Dunst'", +# disables shadows on i3 frames + "class_g ?= 'i3-frame'", + "_GTK_FRAME_EXTENTS@:c", + "_NET_WM_STATE@:32a *= '_NET_WM_STATE_HIDDEN'" +]; +# Avoid drawing shadow on all shaped windows (see also: --detect-rounded-corners) +shadow-ignore-shaped = false; + +################################# +# +# Opacity +# +################################# + +inactive-opacity = 1; +active-opacity = 1; +frame-opacity = 1; +inactive-opacity-override = false; + +# Dim inactive windows. (0.0 - 1.0) +# inactive-dim = 0.2; +# Do not let dimness adjust based on window opacity. +# inactive-dim-fixed = true; +# Blur background of transparent windows. Bad performance with X Render backend. GLX backend is preferred. +# blur-background = true; +# Blur background of opaque windows with transparent frames as well. +# blur-background-frame = true; +# Do not let blur radius adjust based on window opacity. +blur-background-fixed = false; +blur-background-exclude = [ + "window_type = 'dock'", + "window_type = 'desktop'" +]; + +################################# +# +# Fading +# +################################# + +# Fade windows during opacity changes. +fading = false; +# The time between steps in a fade in milliseconds. (default 10). +fade-delta = 1; +# Opacity change between steps while fading in. (default 0.028). +fade-in-step = 0.03; +# Opacity change between steps while fading out. (default 0.03). +fade-out-step = 0.03; +# Fade windows in/out when opening/closing +# no-fading-openclose = true; + +# Specify a list of conditions of windows that should not be faded. +fade-exclude = [ ]; + +################################# +# +# Other +# +################################# + +# Try to detect WM windows and mark them as active. +mark-wmwin-focused = true; +# Mark all non-WM but override-redirect windows active (e.g. menus). +mark-ovredir-focused = true; +# Use EWMH _NET_WM_ACTIVE_WINDOW to determine which window is focused instead of using FocusIn/Out events. +# Usually more reliable but depends on a EWMH-compliant WM. +use-ewmh-active-win = true; +# Detect rounded corners and treat them as rectangular when --shadow-ignore-shaped is on. +detect-rounded-corners = true; + +# Detect _NET_WM_OPACITY on client windows, useful for window managers not passing _NET_WM_OPACITY of client windows to frame windows. +# This prevents opacity being ignored for some apps. +# For example without this enabled my xfce4-notifyd is 100% opacity no matter what. +detect-client-opacity = true; + +# Specify refresh rate of the screen. +# If not specified or 0, picom will try detecting this with X RandR extension. +refresh-rate = 0; + +# Vertical synchronization: match the refresh rate of the monitor +vsync = false; + +# Enable DBE painting mode, intended to use with VSync to (hopefully) eliminate tearing. +# Reported to have no effect, though. +dbe = false; + +# Limit picom to repaint at most once every 1 / refresh_rate second to boost performance. +# This should not be used with --vsync drm/opengl/opengl-oml as they essentially does --sw-opti's job already, +# unless you wish to specify a lower refresh rate than the actual value. +#sw-opti = true; + +# Unredirect all windows if a full-screen opaque window is detected, to maximize performance for full-screen windows, like games. +# Known to cause flickering when redirecting/unredirecting windows. +unredir-if-possible = true; + +# Specify a list of conditions of windows that should always be considered focused. +focus-exclude = [ "class_g = 'Cairo-clock'" ]; + +# Use WM_TRANSIENT_FOR to group windows, and consider windows in the same group focused at the same time. +detect-transient = true; +# Use WM_CLIENT_LEADER to group windows, and consider windows in the same group focused at the same time. +# WM_TRANSIENT_FOR has higher priority if --detect-transient is enabled, too. +detect-client-leader = true; + +################################# +# +# Window type settings +# +################################# + +wintypes : +{ + tooltip : + { + fade = true; + shadow = false; + opacity = 0.85; + focus = true; + }; + fullscreen : + { + fade = true; + shadow = false; + opacity = 1; + focus = true; + }; +}; + +###################### +# +# XSync +# See: https://github.com/yshui/picom/commit/b18d46bcbdc35a3b5620d817dd46fbc76485c20d +# +###################### + +# Use X Sync fence to sync clients' draw calls. Needed on nvidia-drivers with GLX backend for some users. +xrender-sync-fence = true; + +#opacity-rule = [ +#"99:name *?= 'Call'", +#"99:class_g = 'Chromium'", +#"99:name *?= 'Conky'", +#"99:class_g = 'Darktable'", +#"50:class_g = 'Dmenu'", +#"99:name *?= 'Event'", +#"99:class_g = 'Firefox'", +#"99:class_g = 'GIMP'", +#"99:name *?= 'Image'", +#"99:class_g = 'Lazpaint'", +#"99:class_g = 'Midori'", +#"99:name *?= 'Minitube'", +#"99:class_g = 'Mousepad'", +#"99:name *?= 'MuseScore'", +#"90:name *?= 'Page Info'", +#"99:name *?= 'Pale Moon'", +#"90:name *?= 'Panel'", +#"99:class_g = 'Pinta'", +#"90:name *?= 'Restart'", +#"99:name *?= 'sudo'", +#"99:name *?= 'Screenshot'", +#"99:class_g = 'Viewnior'", +#"99:class_g = 'VirtualBox'", +#"99:name *?= 'VLC'", +#"99:name *?= 'Write'", +#"93:class_g = 'URxvt' && !_NET_WM_STATE@:32a", +#"0:_NET_WM_STATE@:32a *= '_NET_WM_STATE_HIDDEN'", +#"96:_NET_WM_STATE@:32a *= '_NET_WM_STATE_STICKY'" +#]; +
A i3/.config/polybar/config

@@ -0,0 +1,112 @@

+;;;;;;;;;;;;;;;;;;;;;;;;; +; x1phosura's polybar ; +;;;;;;;;;;;;;;;;;;;;;;;;; + +; preconfigured modules in /usr/share/doc/polybar/config + +[bar/top] +;width = 90% +height = 3% +;offset-x = 20% +;offset-y = 20% +fixed-center = false + +font-0 = "Inconsolata:size=16;0" +; font-1 = "Inconsolata:size=16;0" + +modules-left = i3 +modules-right = cpu wireless-network battery date time +module-margin = 1 + +scroll-up = "#i3.prev" +scroll-down = "#i3.next" +wm-restack = i3 + + +;;;;;;;;;;;;; +; modules ; +;;;;;;;;;;;;; + +[module/i3] +type = internal/i3 +format = <label-state> <label-mode> +pin-workspaces = true +;index-sort = true +; clicking and scrolling features of i3 module +enable-click = true +; false because scroll handler defined in bar/top, so the whole bar is affected +enable-scroll = false +; true would make this annoying, trust me +wrapping-scroll = false + +; still working on this part of the config... +;label-dimmed-underline = #ffffff +label-focused = "%name%" +label-focused-foreground = #000000 +label-focused-background = #68c0e0 +;label-focused-underline = #${colors.accent} +label-focused-underline = #000000 +label-focused-padding = 1 +label-unfocused = "%name%" +;label-unfocused-underline = #555555 +label-unfocused-padding = 1 +label-urgent = "%name%" +label-urgent-foreground = #000000 +label-urgent-background = #bd2c40 +;label-urgent-underline = #9b0a20 +label-urgent-padding = 1 +label-visible = "%name%" +label-visible-foreground = #55ffff +label-visible-padding = 1 + + +[module/cpu] +type = internal/cpu +interval = 2 +label = CPU %percentage%% + + +;; placeholder for RAM +;; [module/memory] +;; type = internal/memory +;; interval = 4 +;; format = <label> <bar-used> +;; label = RAM %gb_used%/%gb_free% + + +;; wireless device +[module/wireless-network] +type = internal/network +interface = wlp4s0 +interval = 1 +format-connected = <label-connected> +format-disconnected = <label-disconnected> +label-connected = [%signal%] %essid% (%local_ip%) %downspeed% v, %upspeed% ^ +label-disconnected = not connected + + +;; placeholder for ethernet device +; [module/wired-network] +; type = internal/network + + +[module/battery] +type = internal/battery +full-at = 100 +label-charging = CHRG %percentage%% +label-discharging = BATT %percentage%% +format-charging = <label-charging> +format-discharging = <label-discharging> +; format-full = + + +[module/date] +type = internal/date +date = %b %e, %Y + + +[module/time] +type = internal/date +interval = 5.0 +date = %H:%M:%S +
A i3/.config/polybar/config.briana

@@ -0,0 +1,85 @@

+ +[bar/top] +monitor = eDP-1 +width = 50% +height = 5% +offset-x = 25% +offset-y = 2% +fixed-center = false +bottom = false +wm-restack = i3 + +background = #ffffff +foreground = #000000 +linecolor = #1b00f2 + +spacing = 1 +lineheight = 1 +padding = 4% + +font-0 = artwiz lime:pixelsize=10:antialias=false;1 +font-1 = DejaVuSans Mono for Powerline:pixelsize=10:antialias=false;1 +font-2 = FontAwesome:pixelsize=10:antialias=false;1 + +modules-left = volume +modules-right = battery memory cpu +modules-center = date + +module-margin = 2 + +[module/cpu] +type = internal/cpu +interval = 2 +label = CPU %percentage% + + +[module/memory] +type = internal/memory +interval = 2 +label = RAM %percentage_used% + + +[module/volume] +type = internal/alsa + +format-volume = <label-volume> <bar-volume> +label-volume = "VOL" +label-volume-foreground = #90233f + +format-muted-foreground = #90233f +format-muted = <label-muted> <bar-volume> +label-muted = "MUT" + +bar-volume-width = 10 +bar-volume-foreground-0 = #635370 +bar-volume-foreground-1 = #635370 +bar-volume-foreground-2 = #7E6B8E +bar-volume-foreground-3 = #9C83AF +bar-volume-foreground-4 = #B195C6 +bar-volume-foreground-5 = #C5A6DD +bar-volume-foreground-6 = #E1BDFC +bar-volume-gradient = true +bar-volume-indicator = +bar-volume-indicator-font = 2 +bar-volume-fill = • +bar-volume-fill-font = 2 +bar-volume-empty = · +bar-volume-empty-font = 2 +bar-volume-empty-foreground = #666666 + +[module/battery] +type = internal/battery +full-at = 98 + +format-charging = <label-charging> +format-discharging = <label-discharging> +format-full = + +label-charging = BATT %percentage% +label-discharging = BATT %percentage% + + +[module/date] +type = internal/date +date = %m-%d-%Y %H:%M +interval = 5
A i3/.config/polybar/config.example

@@ -0,0 +1,423 @@

+;========================================================== +; +; +; ██████╗ ██████╗ ██╗ ██╗ ██╗██████╗ █████╗ ██████╗ +; ██╔══██╗██╔═══██╗██║ ╚██╗ ██╔╝██╔══██╗██╔══██╗██╔══██╗ +; ██████╔╝██║ ██║██║ ╚████╔╝ ██████╔╝███████║██████╔╝ +; ██╔═══╝ ██║ ██║██║ ╚██╔╝ ██╔══██╗██╔══██║██╔══██╗ +; ██║ ╚██████╔╝███████╗██║ ██████╔╝██║ ██║██║ ██║ +; ╚═╝ ╚═════╝ ╚══════╝╚═╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝ +; +; +; To learn more about how to configure Polybar +; go to https://github.com/jaagr/polybar +; +; The README contains alot of information +; +;========================================================== + +[colors] +;background = ${xrdb:color0:#222} +background = #222 +background-alt = #444 +;foreground = ${xrdb:color7:#222} +foreground = #dfdfdf +foreground-alt = #555 +primary = #ffb52a +secondary = #e60053 +alert = #bd2c40 + +[bar/example] +;monitor = ${env:MONITOR:HDMI-1} +width = 100% +height = 27 +;offset-x = 1% +;offset-y = 1% +radius = 6.0 +fixed-center = false + +background = ${colors.background} +foreground = ${colors.foreground} + +line-size = 3 +line-color = #f00 + +border-size = 4 +border-color = #00000000 + +padding-left = 0 +padding-right = 2 + +module-margin-left = 1 +module-margin-right = 2 + +font-0 = fixed:pixelsize=10;1 +font-1 = unifont:fontformat=truetype:size=8:antialias=false;0 +font-2 = siji:pixelsize=10;1 + +modules-left = bspwm i3 +modules-center = +modules-right = filesystem xbacklight alsa pulseaudio xkeyboard memory cpu wlan eth battery temperature date powermenu + +tray-position = right +tray-padding = 2 +;tray-background = #0063ff + +;wm-restack = bspwm +;wm-restack = i3 + +;override-redirect = true + +;scroll-up = bspwm-desknext +;scroll-down = bspwm-deskprev + +;scroll-up = i3wm-wsnext +;scroll-down = i3wm-wsprev + +cursor-click = pointer +cursor-scroll = ns-resize + +[module/xwindow] +type = internal/xwindow +label = %title:0:30:...% + +[module/xkeyboard] +type = internal/xkeyboard +blacklist-0 = num lock + +format-prefix = " " +format-prefix-foreground = ${colors.foreground-alt} +format-prefix-underline = ${colors.secondary} + +label-layout = %layout% +label-layout-underline = ${colors.secondary} + +label-indicator-padding = 2 +label-indicator-margin = 1 +label-indicator-background = ${colors.secondary} +label-indicator-underline = ${colors.secondary} + +[module/filesystem] +type = internal/fs +interval = 25 + +mount-0 = / + +label-mounted = %{F#0a81f5}%mountpoint%%{F-}: %percentage_used%% +label-unmounted = %mountpoint% not mounted +label-unmounted-foreground = ${colors.foreground-alt} + +[module/bspwm] +type = internal/bspwm + +label-focused = %index% +label-focused-background = ${colors.background-alt} +label-focused-underline= ${colors.primary} +label-focused-padding = 2 + +label-occupied = %index% +label-occupied-padding = 2 + +label-urgent = %index%! +label-urgent-background = ${colors.alert} +label-urgent-padding = 2 + +label-empty = %index% +label-empty-foreground = ${colors.foreground-alt} +label-empty-padding = 2 + +; Separator in between workspaces +; label-separator = | + +[module/i3] +type = internal/i3 +format = <label-state> <label-mode> +index-sort = true +wrapping-scroll = false + +; Only show workspaces on the same output as the bar +;pin-workspaces = true + +label-mode-padding = 2 +label-mode-foreground = #000 +label-mode-background = ${colors.primary} + +; focused = Active workspace on focused monitor +label-focused = %index% +label-focused-background = ${module/bspwm.label-focused-background} +label-focused-underline = ${module/bspwm.label-focused-underline} +label-focused-padding = ${module/bspwm.label-focused-padding} + +; unfocused = Inactive workspace on any monitor +label-unfocused = %index% +label-unfocused-padding = ${module/bspwm.label-occupied-padding} + +; visible = Active workspace on unfocused monitor +label-visible = %index% +label-visible-background = ${self.label-focused-background} +label-visible-underline = ${self.label-focused-underline} +label-visible-padding = ${self.label-focused-padding} + +; urgent = Workspace with urgency hint set +label-urgent = %index% +label-urgent-background = ${module/bspwm.label-urgent-background} +label-urgent-padding = ${module/bspwm.label-urgent-padding} + +; Separator in between workspaces +; label-separator = | + + +[module/mpd] +type = internal/mpd +format-online = <label-song> <icon-prev> <icon-stop> <toggle> <icon-next> + +icon-prev =  +icon-stop =  +icon-play =  +icon-pause =  +icon-next =  + +label-song-maxlen = 25 +label-song-ellipsis = true + +[module/xbacklight] +type = internal/xbacklight + +format = <label> <bar> +label = BL + +bar-width = 10 +bar-indicator = | +bar-indicator-foreground = #fff +bar-indicator-font = 2 +bar-fill = ─ +bar-fill-font = 2 +bar-fill-foreground = #9f78e1 +bar-empty = ─ +bar-empty-font = 2 +bar-empty-foreground = ${colors.foreground-alt} + +[module/backlight-acpi] +inherit = module/xbacklight +type = internal/backlight +card = intel_backlight + +[module/cpu] +type = internal/cpu +interval = 2 +format-prefix = " " +format-prefix-foreground = ${colors.foreground-alt} +format-underline = #f90000 +label = %percentage:2%% + +[module/memory] +type = internal/memory +interval = 2 +format-prefix = " " +format-prefix-foreground = ${colors.foreground-alt} +format-underline = #4bffdc +label = %percentage_used%% + +[module/wlan] +type = internal/network +interface = wlp3s0 +interval = 3.0 + +format-connected = <ramp-signal> <label-connected> +format-connected-underline = #9f78e1 +label-connected = %essid% + +format-disconnected = +;format-disconnected = <label-disconnected> +;format-disconnected-underline = ${self.format-connected-underline} +;label-disconnected = %ifname% disconnected +;label-disconnected-foreground = ${colors.foreground-alt} + +ramp-signal-0 =  +ramp-signal-1 =  +ramp-signal-2 =  +ramp-signal-3 =  +ramp-signal-4 =  +ramp-signal-foreground = ${colors.foreground-alt} + +[module/eth] +type = internal/network +interface = enp0s31f6 +interval = 3.0 + +format-connected-underline = #55aa55 +format-connected-prefix = " " +format-connected-prefix-foreground = ${colors.foreground-alt} +label-connected = %local_ip% + +format-disconnected = +;format-disconnected = <label-disconnected> +;format-disconnected-underline = ${self.format-connected-underline} +;label-disconnected = %ifname% disconnected +;label-disconnected-foreground = ${colors.foreground-alt} + +[module/date] +type = internal/date +interval = 5 + +date = +date-alt = " %Y-%m-%d" + +time = %H:%M +time-alt = %H:%M:%S + +format-prefix =  +format-prefix-foreground = ${colors.foreground-alt} +format-underline = #0a6cf5 + +label = %date% %time% + +[module/pulseaudio] +type = internal/pulseaudio + +format-volume = <label-volume> <bar-volume> +label-volume = VOL %percentage%% +label-volume-foreground = ${root.foreground} + +label-muted = 🔇 muted +label-muted-foreground = #666 + +bar-volume-width = 10 +bar-volume-foreground-0 = #55aa55 +bar-volume-foreground-1 = #55aa55 +bar-volume-foreground-2 = #55aa55 +bar-volume-foreground-3 = #55aa55 +bar-volume-foreground-4 = #55aa55 +bar-volume-foreground-5 = #f5a70a +bar-volume-foreground-6 = #ff5555 +bar-volume-gradient = false +bar-volume-indicator = | +bar-volume-indicator-font = 2 +bar-volume-fill = ─ +bar-volume-fill-font = 2 +bar-volume-empty = ─ +bar-volume-empty-font = 2 +bar-volume-empty-foreground = ${colors.foreground-alt} + +[module/alsa] +type = internal/alsa + +format-volume = <label-volume> <bar-volume> +label-volume = VOL +label-volume-foreground = ${root.foreground} + +format-muted-prefix = " " +format-muted-foreground = ${colors.foreground-alt} +label-muted = sound muted + +bar-volume-width = 10 +bar-volume-foreground-0 = #55aa55 +bar-volume-foreground-1 = #55aa55 +bar-volume-foreground-2 = #55aa55 +bar-volume-foreground-3 = #55aa55 +bar-volume-foreground-4 = #55aa55 +bar-volume-foreground-5 = #f5a70a +bar-volume-foreground-6 = #ff5555 +bar-volume-gradient = false +bar-volume-indicator = | +bar-volume-indicator-font = 2 +bar-volume-fill = ─ +bar-volume-fill-font = 2 +bar-volume-empty = ─ +bar-volume-empty-font = 2 +bar-volume-empty-foreground = ${colors.foreground-alt} + +[module/battery] +type = internal/battery +battery = BAT0 +adapter = ADP1 +full-at = 98 + +format-charging = <animation-charging> <label-charging> +format-charging-underline = #ffb52a + +format-discharging = <animation-discharging> <label-discharging> +format-discharging-underline = ${self.format-charging-underline} + +format-full-prefix = " " +format-full-prefix-foreground = ${colors.foreground-alt} +format-full-underline = ${self.format-charging-underline} + +ramp-capacity-0 =  +ramp-capacity-1 =  +ramp-capacity-2 =  +ramp-capacity-foreground = ${colors.foreground-alt} + +animation-charging-0 =  +animation-charging-1 =  +animation-charging-2 =  +animation-charging-foreground = ${colors.foreground-alt} +animation-charging-framerate = 750 + +animation-discharging-0 =  +animation-discharging-1 =  +animation-discharging-2 =  +animation-discharging-foreground = ${colors.foreground-alt} +animation-discharging-framerate = 750 + +[module/temperature] +type = internal/temperature +thermal-zone = 0 +warn-temperature = 60 + +format = <ramp> <label> +format-underline = #f50a4d +format-warn = <ramp> <label-warn> +format-warn-underline = ${self.format-underline} + +label = %temperature-c% +label-warn = %temperature-c% +label-warn-foreground = ${colors.secondary} + +ramp-0 =  +ramp-1 =  +ramp-2 =  +ramp-foreground = ${colors.foreground-alt} + +[module/powermenu] +type = custom/menu + +expand-right = true + +format-spacing = 1 + +label-open =  +label-open-foreground = ${colors.secondary} +label-close =  cancel +label-close-foreground = ${colors.secondary} +label-separator = | +label-separator-foreground = ${colors.foreground-alt} + +menu-0-0 = reboot +menu-0-0-exec = menu-open-1 +menu-0-1 = power off +menu-0-1-exec = menu-open-2 + +menu-1-0 = cancel +menu-1-0-exec = menu-open-0 +menu-1-1 = reboot +menu-1-1-exec = sudo reboot + +menu-2-0 = power off +menu-2-0-exec = sudo poweroff +menu-2-1 = cancel +menu-2-1-exec = menu-open-0 + +[settings] +screenchange-reload = true +;compositing-background = xor +;compositing-background = screen +;compositing-foreground = source +;compositing-border = over +;pseudo-transparency = false + +[global/wm] +margin-top = 5 +margin-bottom = 5 + +; vim:ft=dosini
A i3/.config/polybar/launch.sh

@@ -0,0 +1,15 @@

+#!/usr/bin/env sh + +# stolen from Arch wiki + +# Terminate already running bar instances +killall -q polybar + +# Wait until the processes have been shut down +while pgrep -u $UID -x polybar >/dev/null; do sleep 1; done + +# Launch polybar +polybar top & + +echo "Polybar launched..." +
A i3/.config/redshift/redshift.conf

@@ -0,0 +1,8 @@

+ +[manual] +; approx. lattitude/longitude fro Rochester, NY +lat=43 +lon=77 + +; TODO: comment out other lattitude/longitudes to use +
A i3/.config/rofi/colors-rofi-dark-mine.rasi

@@ -0,0 +1,163 @@

+* { + active-background: #538C71; + active-foreground: @foreground; + normal-background: @background; + normal-foreground: @foreground; + urgent-background: #877763; + urgent-foreground: @foreground; + + alternate-active-background: @background; + alternate-active-foreground: @foreground; + alternate-normal-background: @background; + alternate-normal-foreground: @foreground; + alternate-urgent-background: @background; + alternate-urgent-foreground: @foreground; + + /* CHANGE */ + selected-active-background: #877763; + selected-active-foreground: @foreground; + selected-normal-background: #006699; /* higlighted list entry */ + selected-normal-foreground: @foreground; + selected-urgent-background: #91B234; + selected-urgent-foreground: @foreground; + + background-color: @background; + background: #000000; + /* background: #1b1b1b; */ + foreground: #c7c9c6; + border-color: @background; + spacing: 2; +} + +#window { + background-color: @background; + border: 0; + padding: 2.5ch; +} + +#mainbox { + border: 0; + padding: 0; +} + +#message { + border: 2px 0px 0px; + border-color: @border-color; + padding: 1px; +} + +#textbox { + text-color: @foreground; +} + +#inputbar { + children: [ prompt,textbox-prompt-colon,entry,case-indicator ]; +} + +#textbox-prompt-colon { + expand: false; + str: ":"; + margin: 0px 0.3em 0em 0em; + text-color: @normal-foreground; +} + +#listview { + fixed-height: 0; + border: 2px 0px 0px; + border-color: @border-color; + spacing: 2px; + scrollbar: true; + padding: 2px 0px 0px; +} + +#element { + border: 0; + padding: 1px; +} + +#element.normal.normal { + background-color: @normal-background; + text-color: @normal-foreground; +} + +#element.normal.urgent { + background-color: @urgent-background; + text-color: @urgent-foreground; +} + +#element.normal.active { + background-color: @active-background; + text-color: @active-foreground; +} + +#element.selected.normal { + background-color: @selected-normal-background; + text-color: @selected-normal-foreground; +} + +#element.selected.urgent { + background-color: @selected-urgent-background; + text-color: @selected-urgent-foreground; +} + +#element.selected.active { + background-color: @selected-active-background; + text-color: @selected-active-foreground; +} + +#element.alternate.normal { + background-color: @alternate-normal-background; + text-color: @alternate-normal-foreground; +} + +#element.alternate.urgent { + background-color: @alternate-urgent-background; + text-color: @alternate-urgent-foreground; +} + +#element.alternate.active { + background-color: @alternate-active-background; + text-color: @alternate-active-foreground; +} + +#scrollbar { + width: 4px; + border: 0; + handle-width: 8px; + padding: 0; +} + +#sidebar { + border: 2px 0px 0px; + border-color: @border-color; +} + +#button { + text-color: @normal-foreground; +} + +#button.selected { + background-color: @selected-normal-background; + text-color: @selected-normal-foreground; +} + +#inputbar { + spacing: 0; + text-color: @normal-foreground; + padding: 1px; +} + +#case-indicator { + spacing: 0; + text-color: @normal-foreground; +} + +#entry { + spacing: 0; + text-color: @normal-foreground; +} + +#prompt { + spacing: 0; + text-color: @normal-foreground; +}
A i3/.config/rofi/colors-rofi-dark-olive.rasi

@@ -0,0 +1,161 @@

+* { + active-background: #718C53; + active-foreground: @foreground; + normal-background: @background; + normal-foreground: @foreground; + urgent-background: #877763; + urgent-foreground: @foreground; + + alternate-active-background: @background; + alternate-active-foreground: @foreground; + alternate-normal-background: @background; + alternate-normal-foreground: @foreground; + alternate-urgent-background: @background; + alternate-urgent-foreground: @foreground; + + selected-active-background: #877763; + selected-active-foreground: @foreground; + selected-normal-background: #718C53; + selected-normal-foreground: @foreground; + selected-urgent-background: #91B234; + selected-urgent-foreground: @foreground; + + background-color: @background; + background: #1b1910; + foreground: #c7c9c6; + border-color: @background; + spacing: 2; +} + +#window { + background-color: @background; + border: 0; + padding: 2.5ch; +} + +#mainbox { + border: 0; + padding: 0; +} + +#message { + border: 2px 0px 0px; + border-color: @border-color; + padding: 1px; +} + +#textbox { + text-color: @foreground; +} + +#inputbar { + children: [ prompt,textbox-prompt-colon,entry,case-indicator ]; +} + +#textbox-prompt-colon { + expand: false; + str: ":"; + margin: 0px 0.3em 0em 0em; + text-color: @normal-foreground; +} + +#listview { + fixed-height: 0; + border: 2px 0px 0px; + border-color: @border-color; + spacing: 2px; + scrollbar: true; + padding: 2px 0px 0px; +} + +#element { + border: 0; + padding: 1px; +} + +#element.normal.normal { + background-color: @normal-background; + text-color: @normal-foreground; +} + +#element.normal.urgent { + background-color: @urgent-background; + text-color: @urgent-foreground; +} + +#element.normal.active { + background-color: @active-background; + text-color: @active-foreground; +} + +#element.selected.normal { + background-color: @selected-normal-background; + text-color: @selected-normal-foreground; +} + +#element.selected.urgent { + background-color: @selected-urgent-background; + text-color: @selected-urgent-foreground; +} + +#element.selected.active { + background-color: @selected-active-background; + text-color: @selected-active-foreground; +} + +#element.alternate.normal { + background-color: @alternate-normal-background; + text-color: @alternate-normal-foreground; +} + +#element.alternate.urgent { + background-color: @alternate-urgent-background; + text-color: @alternate-urgent-foreground; +} + +#element.alternate.active { + background-color: @alternate-active-background; + text-color: @alternate-active-foreground; +} + +#scrollbar { + width: 4px; + border: 0; + handle-width: 8px; + padding: 0; +} + +#sidebar { + border: 2px 0px 0px; + border-color: @border-color; +} + +#button { + text-color: @normal-foreground; +} + +#button.selected { + background-color: @selected-normal-background; + text-color: @selected-normal-foreground; +} + +#inputbar { + spacing: 0; + text-color: @normal-foreground; + padding: 1px; +} + +#case-indicator { + spacing: 0; + text-color: @normal-foreground; +} + +#entry { + spacing: 0; + text-color: @normal-foreground; +} + +#prompt { + spacing: 0; + text-color: @normal-foreground; +}
A i3/.config/rofi/config.rasi

@@ -0,0 +1,163 @@

+* { + active-background: #538C71; + active-foreground: @foreground; + normal-background: @background; + normal-foreground: @foreground; + urgent-background: #877763; + urgent-foreground: @foreground; + + alternate-active-background: @background; + alternate-active-foreground: @foreground; + alternate-normal-background: @background; + alternate-normal-foreground: @foreground; + alternate-urgent-background: @background; + alternate-urgent-foreground: @foreground; + + /* CHANGE */ + selected-active-background: #877763; + selected-active-foreground: @foreground; + selected-normal-background: #006699; /* higlighted list entry */ + selected-normal-foreground: @foreground; + selected-urgent-background: #91B234; + selected-urgent-foreground: @foreground; + + background-color: @background; + background: #000000; + /* background: #1b1b1b; */ + foreground: #c7c9c6; + border-color: @background; + spacing: 2; +} + +#window { + background-color: @background; + border: 0; + padding: 2.5ch; +} + +#mainbox { + border: 0; + padding: 0; +} + +#message { + border: 2px 0px 0px; + border-color: @border-color; + padding: 1px; +} + +#textbox { + text-color: @foreground; +} + +#inputbar { + children: [ prompt,textbox-prompt-colon,entry,case-indicator ]; +} + +#textbox-prompt-colon { + expand: false; + str: ":"; + margin: 0px 0.3em 0em 0em; + text-color: @normal-foreground; +} + +#listview { + fixed-height: 0; + border: 2px 0px 0px; + border-color: @border-color; + spacing: 2px; + scrollbar: true; + padding: 2px 0px 0px; +} + +#element { + border: 0; + padding: 1px; +} + +#element.normal.normal { + background-color: @normal-background; + text-color: @normal-foreground; +} + +#element.normal.urgent { + background-color: @urgent-background; + text-color: @urgent-foreground; +} + +#element.normal.active { + background-color: @active-background; + text-color: @active-foreground; +} + +#element.selected.normal { + background-color: @selected-normal-background; + text-color: @selected-normal-foreground; +} + +#element.selected.urgent { + background-color: @selected-urgent-background; + text-color: @selected-urgent-foreground; +} + +#element.selected.active { + background-color: @selected-active-background; + text-color: @selected-active-foreground; +} + +#element.alternate.normal { + background-color: @alternate-normal-background; + text-color: @alternate-normal-foreground; +} + +#element.alternate.urgent { + background-color: @alternate-urgent-background; + text-color: @alternate-urgent-foreground; +} + +#element.alternate.active { + background-color: @alternate-active-background; + text-color: @alternate-active-foreground; +} + +#scrollbar { + width: 4px; + border: 0; + handle-width: 8px; + padding: 0; +} + +#sidebar { + border: 2px 0px 0px; + border-color: @border-color; +} + +#button { + text-color: @normal-foreground; +} + +#button.selected { + background-color: @selected-normal-background; + text-color: @selected-normal-foreground; +} + +#inputbar { + spacing: 0; + text-color: @normal-foreground; + padding: 1px; +} + +#case-indicator { + spacing: 0; + text-color: @normal-foreground; +} + +#entry { + spacing: 0; + text-color: @normal-foreground; +} + +#prompt { + spacing: 0; + text-color: @normal-foreground; +}
A i3/.config/rofi/old-BlackTheme.rasi

@@ -0,0 +1,127 @@

+/** + * Black Theme (modified Pop-Dark) + * Original author: Primetoxinz + */ + +* { + text-color: #f2f2f2; + background-color: #141414; + lightbg: #534c48; + red: #f15d22; + orange: #faa41a; + blue: #48b9c7; + + font: "Inconsolata 16"; + + selected-normal-foreground: @background-color; + normal-foreground: @foreground; + alternate-normal-background: @background; + selected-urgent-foreground: @foreground; + urgent-foreground: @foreground; + alternate-urgent-background: @background; + active-foreground: @foreground; + selected-active-foreground: @foreground; + alternate-normal-foreground: @foreground; + alternate-active-background: @blue; + bordercolor: @foreground; + normal-background: @background; + selected-normal-background: @blue; + separatorcolor: @orange; + spacing: 2; + urgent-background: @red; + alternate-urgent-foreground: @foreground; + selected-urgent-background: @red; + alternate-active-foreground: @foreground; + selected-active-background: @blue; + active-background: @orange; +} +#window { + border: 0; + width: 24%; /* control size of window */ + text-color: @foreground; + background-color: rgba ( 0, 0, 0, 0 % ); + padding: 5; + text-color: @bordercolor; + background-color: @background; +} +#mainbox { + border: 0; + padding: 0; +} +#message { + border: 1px dash 0px 0px ; + text-color: @separatorcolor; + padding: 2px 0px 0px ; +} +#textbox { + text-color: @foreground; +} +#listview { + fixed-height: 0; + border: 2px 0px 0px ; + padding: 2px 0px 0px ; + text-color: @separatorcolor; +} +#element { + border: 0; +} +#element.normal.normal { + text-color: @normal-foreground; + background-color: @normal-background; +} +#element.normal.urgent { + text-color: @urgent-foreground; + background-color: @urgent-background; +} +#element.normal.active { + text-color: @active-foreground; + background-color: @active-background; +} +#element.selected.normal { + text-color: @selected-normal-foreground; + background-color: @selected-normal-background; +} +#element.selected.urgent { + text-color: @selected-urgent-foreground; + background-color: @selected-urgent-background; +} +#element.selected.active { + text-color: @selected-active-foreground; + background-color: @selected-active-background; +} +#element.alternate.normal { + text-color: @alternate-normal-foreground; + background-color: @alternate-normal-background; +} +#element.alternate.urgent { + text-color: @alternate-urgent-foreground; + background-color: @alternate-urgent-background; +} +#element.alternate.active { + text-color: @alternate-active-foreground; + background-color: @alternate-active-background; +} +#sidebar { + border: 1px dash 0px 0px ; +} +#button selected { + text-color: @selected-normal-foreground; + background-color: @selected-normal-background; +} +#inputbar { + spacing: 0; + border: 0px ; +} +#button normal { + text-color: @foreground; +} + +#inputbar { + children: [ prompt,textbox-prompt-colon,entry,case-indicator ]; +} +#textbox-prompt-colon { + expand: false; + str: ":"; + margin: 0px 0.3em 0em 0em ; + text-color: @normal-foreground; +}
A i3/.xinitrc

@@ -0,0 +1,71 @@

+#!/bin/bash +# +# ~/.xinitrc +# +# Executed by startx (run your window manager from here) + +userresources=$HOME/.Xresources +usermodmap=$HOME/.Xmodmap +sysresources=/etc/X11/xinit/.Xresources +sysmodmap=/etc/X11/xinit/.Xmodmap + +DEFAULT_SESSION='i3 --shmlog-size 8000000' + +# merge in defaults and keymaps + +if [ -f $sysresources ]; then + xrdb -merge $sysresources +fi + +if [ -f $sysmodmap ]; then + xmodmap $sysmodmap +fi + +if [ -f "$userresources" ]; then + xrdb -merge "$userresources" +fi + +if [ -f "$usermodmap" ]; then + xmodmap "$usermodmap" +fi + +# start some nice programs + +if [ -d /etc/X11/xinit/xinitrc.d ] ; then + for f in /etc/X11/xinit/xinitrc.d/?*.sh ; do + [ -x "$f" ] && . "$f" + done + unset f +fi + +get_session(){ + #local dbus_args=(--sh-syntax --exit-with-session) # <-- broken, use below + local dbus_args=(--sh-syntax) + case $1 in + awesome) dbus_args+=(awesome) ;; + bspwm) dbus_args+=(bspwm-session) ;; + budgie) dbus_args+=(budgie-desktop) ;; + cinnamon) dbus_args+=(cinnamon-session) ;; + deepin) dbus_args+=(startdde) ;; + enlightenment) dbus_args+=(enlightenment_start) ;; + fluxbox) dbus_args+=(startfluxbox) ;; + gnome) dbus_args+=(gnome-session) ;; + i3|i3wm) dbus_args+=(i3 --shmlog-size 0) ;; + jwm) dbus_args+=(jwm) ;; + kde) dbus_args+=(startplasma-x11) ;; + lxde) dbus_args+=(startlxde) ;; + lxqt) dbus_args+=(lxqt-session) ;; + mate) dbus_args+=(mate-session) ;; + xfce) dbus_args+=(xfce4-session) ;; + openbox) dbus_args+=(openbox-session) ;; + *) dbus_args+=($DEFAULT_SESSION) ;; + esac + + # echo "${dbus_args[*]}" # if broken, try this + echo "dbus-launch ${dbus_args[*]}" +} + +# turn off annoying beep +xset b off + +exec $(get_session "$1")
A place-dotfiles-extra.sh

@@ -0,0 +1,70 @@

+#!/bin/sh + +# place-dotfiles-extra.sh: simple script to symlink many of my extra dotfiles +# TODO: currently doesn't work, needs updating +# by x1phosura + +dotfiles_root="$HOME"/73h4x/dotfiles/dotfiles-extra # where dotfiles live +#dotfiles_root="$PWD" # alternative (for testing) +dest="$HOME" # usually $HOME + +# TODO: detect if X11/Wayland from system +#display_server=x11 +display_server=wayland + + +die() { + echo "$@"; exit 1 +} + +[ ! -d "$dotfiles_root" ] && \ + die "ERROR: $dotfiles_root doesn't exist. Aborting..." + +# TODO: change '[[' to '[', test... +#[[ "$(realpath $dotfiles_root)" = "$(realpath $dest)" ]] && \ +# die " ERROR: dotfiles_root and dest are the same directory! Aborting..." + + +#dotfiles_extra_list=".config/nano \ +#.config/neofetch \ +#.config/radare2 \ +#.config/ranger \ +#.config/systemd" +dotfiles_extra_list=".config/nano \ +.config/radare2 \ +.config/ranger" + +dotfiles_wayland_list="" + +dotfiles_x_list="i3/.config/alacritty \ +i3/.config/compton \ +i3/.config/i3 \ +i3/.config/i3status \ +i3/.config/picom \ +i3/.config/polybar \ +i3/.config/redshift \ +i3/.config/rofi \ +i3/.xinitrc \ +i3/.Xresources \ +i3/.Xresources-manjaro" + +# Note: directly symlink items to .config instead of symlinking .config itself +# because I don't want to preserve everything that programs create there +mkdir -p "$dest"/.config + +for file in $dotfiles_extra_list; do + # TODO: only link after checking file's existence in config_dir_list + ln -svfn "$dotfiles_root/$file" "$dest"/"$file" +done + +# TODO: link X11 dotfiles +# TODO: link wayland dotfiles + +# link personal /bin directory (ex. contains scripts and such...) +ln -svfn "$dotfiles_root"/bin "$dest"/bin + +# link /etc dotfiles (some of these HAVE to be in /etc) +#sudo ln -svf "$dotfiles_root"/etc/default/tlp /etc/default/tlp # tlp dir +# TODO: /etc/pacman.conf +# TODO: backup old files, copy instead of linking +
A sway/.profile

@@ -0,0 +1,24 @@

+#!/bin/sh +# make default editor Neovim +export EDITOR=nvim + +# Most pure GTK3 apps use wayland by default, but some, +# like Firefox, need the backend to be explicitely selected. +export MOZ_ENABLE_WAYLAND=1 +export MOZ_DBUS_REMOTE=1 +export GTK_CSD=0 + +# qt wayland +export QT_QPA_PLATFORM="wayland" +export QT_QPA_PLATFORMTHEME=qt5ct +export QT_WAYLAND_DISABLE_WINDOWDECORATION="1" + +#Java XWayland blank screens fix +export _JAVA_AWT_WM_NONREPARENTING=1 + +# set default shell and terminal +export SHELL=/bin/bash +#export TERMINAL_COMMAND=/usr/share/sway/scripts/foot.sh + +# add default location for zeit.db +export ZEIT_DB=~/.config/zeit.db