Initial commit

This commit is contained in:
Alexander Gehrke 2019-09-30 14:49:14 +02:00
commit cefd40b6dc
31 changed files with 1028 additions and 0 deletions

6
README.md Normal file
View file

@ -0,0 +1,6 @@
# crater's script collection
Some scripts that I wrote over the years and wanted to store with versioning
somewhere. Maybe some of them are useful for others.
Documentation may or may not follow, some scripts include a `--help` output.

3
bin/alert Executable file
View file

@ -0,0 +1,3 @@
#!/bin/zsh
time=$1; shift
echo "DISPLAY=:0.0 sm \"$@\"" | at $time

14
bin/autoless Executable file
View file

@ -0,0 +1,14 @@
#!/bin/zsh
if [[ -n "$@" ]]; then
out=$(<"$@")
else
out=$(cat)
fi
((lim=$LINES-1))
numlines=$(echo $out | wc -l)
if (( $numlines > $lim ))
then
echo $out | less -R
else
echo $out
fi

17
bin/dbus-find Executable file
View file

@ -0,0 +1,17 @@
#!/bin/zsh
if [[ $1 == "-u" ]]; then
USER=$2
SUDO="sudo -u $USER"
shift 2
else
SUDO=
fi
export "$({for i in $(pgrep -u $USER dbus-daemon); grep -z DBUS_SESSION_BUS_ADDRESS /proc/$i/environ} | head -n 1)"
if [[ -z $DBUS_SESSION_BUS_ADDRESS ]]; then
echo "No DBUS found"
exit 1
else
exec $=SUDO "$@"
fi

66
bin/dmjavadoc Executable file
View file

@ -0,0 +1,66 @@
#!/usr/bin/env ruby
require 'dmenu'
JAVA_DOC_LOCATION = "/usr/share/doc/api"
JAVAFX_DOC_LOCATION = "/usr/share/doc/javafx-sdk-docs-*"
USER_DOC_LOCATION = (ENV['XDG_DATA_HOME'] || ENV['HOME'] + '/.local/share') + '/javadoc/*'
class DocIndex
attr_reader :items
def initialize(path)
@items = []
find_entries(path)
end
private
def gen_candidates(dir)
Dir.entries(dir).reject {|e| e == '.' ||
e == '..' ||
e == 'class-use' ||
e == 'src-html' ||
(e =~ /^[a-z].*\..*/ && e != 'package-summary.html')}
end
def find_entries(dir, path = [])
candidates = gen_candidates(dir)
candidates.each do |entry|
if entry == "package-summary.html"
@items << Dmenu::Item.new(path.join(?.), dir + ?/ + entry)
elsif entry.end_with? ".html"
@items << Dmenu::Item.new(
path.join(?.) + ?. + File.basename(entry, '.html'),
dir + ?/ + entry
)
elsif File.directory?(dir + ?/ + entry)
find_entries(dir + ?/ + entry, path + [entry])
end
end
end
end
user_libs = Dir.glob(USER_DOC_LOCATION)
java_folder = Dir.glob(JAVA_DOC_LOCATION).last
jfx_folder = Dir.glob(JAVAFX_DOC_LOCATION).last + "/html"
libmenu = Dmenu.new
libmenu.items = [
Dmenu::Item.new("Java Standard Library (std)", java_folder),
Dmenu::Item.new("javafx", jfx_folder)
] + user_libs.map{|f| Dmenu::Item.new(File.basename(f), f)}
libmenu.case_insensitive = true
libmenu.prompt = "Library:"
libmenu.lines = 20
menu = Dmenu.new
menu.items = DocIndex.new(libmenu.run.value).items
menu.case_insensitive = true
menu.prompt = "Javadoc:"
menu.lines = 20
system("xdg-open #{menu.run.value}")

91
bin/dmpc Executable file
View file

@ -0,0 +1,91 @@
#!/bin/zsh
dmenu_opts=("" "-i")
replace=("-r")
zparseopts -E -D -K -help=help \
a=artist -artist=artist \
b=album -album=album \
t=title -title=title \
j=jump -jump=jump \
r=replace -replace=replace R=replace -no-replace=replace \
o:=dmenu_opts -dmenu-opts:=dmenu_opts \
h:=host -host:=host \
p:=port -port:=port
if [ -n "$help" ]; then
<<-HELP
dmpc: manage mpd playlist with dmenu
Usage: dmpc {-a|-b|-t|-j} [OPTION]
Options:
-a, --artist search for artist
-b, --album search for album
-t, --title search for title
-j, --jump jump to song in current playlist (requires rofi)
(if given in addition to searches, jumps after changes)
-r, --replace replace current playlist
-R, --no-replace do not replace current playlist
-o, --dmenu-opts additional options for dmenu
-h, --host MPD host server
-p, --port server port
dmpc lets you select all tracks from an artist or album or a single track.
HELP
exit 0
fi
if [[ -z "$artist" && -z "$album" && -z "$title" ]]; then
<<-ERR
At least one of -a, -b, -t or -j must be given. See --help for more information.
ERR
exit 1
fi
typeset -a queries
mpc_() {
mpc $=host $=port "$@"
}
dmenu_search() {
local type=$1
mpc_ list $type "${queries[@]}" | dmenu ${=dmenu_opts[2]}
}
add_query() {
local type=$1
local query=$2
queries+=$type
queries+=$query
}
if [[ -n $artist ]]; then
add_query albumartist "$(dmenu_search artist)"
fi
if [[ -n $album ]]; then
add_query album "$(dmenu_search album)"
fi
if [[ -n $title ]]; then
add_query title "$(dmenu_search title)"
fi
if [[ ${replace[1]} == "-r" || "${replace[1]}" == "--replace" ]]; then
mpc_ clear
fi
if [[ ${#queries} -gt 0 ]]; then
mpc_ search "${queries[@]}" | mpc_ add
mpc_ play
fi
if [[ -n $jump ]]; then
mpc play "$(mpc playlist | rofi -dmenu -format d)"
fi

52
bin/dmscaladoc Executable file
View file

@ -0,0 +1,52 @@
#!/usr/bin/env ruby
require 'dmenu'
JAVA_DOC_LOCATION = "/home/crater2150/manuals/scala-*"
USER_DOC_LOCATION = (ENV['XDG_DATA_HOME'] || ENV['HOME'] + '/.local') + '/scaladoc/*'
class DocIndex
attr_reader :items
def initialize(path)
@items = []
find_entries(path)
end
private
def gen_candidates(dir)
Dir.entries(dir).reject {|e| e == '.' ||
e == '..' ||
e == 'class-use' ||
e == 'src-html' ||
(e =~ /^[a-z].*\..*/ && e != 'package-summary.html')}
end
def find_entries(dir, path = [])
candidates = gen_candidates(dir)
candidates.each do |entry|
if entry == "package-summary.html"
@items << Dmenu::Item.new(path.join(?.), dir + ?/ + entry)
elsif entry.end_with? ".html"
@items << Dmenu::Item.new(
path.join(?.) + ?. + File.basename(entry, '.html'),
dir + ?/ + entry
)
elsif File.directory?(dir + ?/ + entry)
find_entries(dir + ?/ + entry, path + [entry])
end
end
end
end
scala_folder = Dir.glob(JAVA_DOC_LOCATION).last + "/api/scala-library/"
menu = Dmenu.new
menu.items = DocIndex.new(scala_folder).items
menu.case_insensitive = true
menu.prompt = "Javadoc:"
menu.lines = 20
system("xdg-open #{menu.run.value}")

30
bin/dmscrot Executable file
View file

@ -0,0 +1,30 @@
#!/usr/bin/env ruby
require 'dmenu'
def run_menu(items, prompt)
menu = Dmenu.new
menu.case_insensitive = true
menu.lines = items.length
menu.items = items
menu.prompt = prompt
menu.run.value
end
modes = [
Dmenu::Item.new('multidisp', '-m'),
Dmenu::Item.new('select', '-s'),
Dmenu::Item.new('focused', '-u -d 1'),
Dmenu::Item.new('normal', '')
]
actions = [
Dmenu::Item.new('move to screenshots', 'mv $f ~/media/screenshots'),
Dmenu::Item.new('view image', 'xdg-open $f'),
Dmenu::Item.new('make draggable', 'dragon -x $f'),
Dmenu::Item.new('nothing', 'true')
]
mode = run_menu(modes, "Screenshot type")
action = run_menu(actions, "and then")
system('scrot', mode, '-e', action)

187
bin/dmsearch Executable file
View file

@ -0,0 +1,187 @@
#!/bin/zsh
emulate -L zsh
SYSTEM_CONFIG_PATH='/etc/dmsearch'
CONFIG_PATH="$HOME/.config/dmsearch"
CACHE_PATH="$HOME/.cache/dmsearch"
mkdir -p "${CACHE_PATH}"
# required software
depend() {
local script="$1"; shift;
local missing
local i
for i in "$@"; do
type "$i" &>/dev/null || {
echo >&2 "$i is required for ${script}. Please install it"
missing=1
}
done
[ -n "$missing" ] && exit 1
}
depend dmsearch \
rofi \
mv \
tail \
cut
################################################################################
# helpers
################################################################################
urlencode() {
setopt extendedglob
input=$(</dev/stdin)
# by jkramer, source: http://stackoverflow.com/a/187853/928769
echo "${${(j: :)input}//(#b)(?)/%$[[##16]##${match[1]}]}"
}
# define a module option
# Parameters:
# 1: module id
# 2: option name
# 3: default value
# 4: description
optdef() {
typeset -A -g opts_${1}
local optname="opt_${1}_${2}"
eval "if [ -z \"\$${optname}\" ]; then
${optname}=\"$3\";
fi"
eval "opts_${1}[$2]=\"${4:-"undocumented"}\""
}
# get history for a search
# parameters:
# 1: search, for which to get history
dmhist() {
local search=$1
local dmhistfile="$CACHE_PATH/history_$search"
if [[ -e "$dmhistfile" ]] then
<"$dmhistfile"
else
</dev/null
fi
}
# add history for a search.
#
# Older entries can be truncated by specifying the maximum history length.
#
# parameters:
# 1: search, for which to add history
# 2: the new entry for the history file
# 3: (optional) maximum number of history items to store
dmhistadd() {
local search=$1
local line=$2
[[ -z "$2" ]] && return
local truncate=${3:-"+0"}
local dmhistfile="$CACHE_PATH/history_$search"
echo "$line" >> "$dmhistfile"
mv "$dmhistfile" "${dmhistfile}.tmp"
tail -n ${truncate} "${dmhistfile}.tmp" > "${dmhistfile}"
rm "${dmhistfile}.tmp"
}
# freetext rofi with a default value.
#
# When called, opens a rofi with only one choice. Pressing enter without any
dmdefault() {
value=$(echo "$2" | rofi -dmenu -l 1 -p "$1" -sort-method fzf)
if [[ "$value" == "$2" ]]; then
$=3
else
echo "$value"
fi
}
################################################################################
# plugin loading
################################################################################
# system plugins are loaded first, so they can be overridden by user plugins
for i in "(${SYSTEM_CONFIG_PATH}/searchers/"*(N) \
"${CONFIG_PATH}/searchers/"*(N); do
. "$i"
done
################################################################################
# Configurable Options
################################################################################
# querystring
SERCHILO="https://www.findfind.it/u/crater2150?query="
# some default values. all of them can be overridden by rc.zsh
typeset -A searches
searches=( g Google w Wikipedia )
webbrowser_cmd="xdg-open"
[[ -e "${SYSTEM_CONFIG_PATH}/rc.zsh" ]] && . "${SYSTEM_CONFIG_PATH}/rc.zsh"
[[ -e "${CONFIG_PATH}/rc.zsh" ]] && . "${CONFIG_PATH}/rc.zsh"
################################################################################
# main script
################################################################################
zparseopts -D -E -help=help h=help
if [ -n "$help" ]; then
<<-HELP
dmsearch [-h]
Opens dmenu and lets you run web searches
configured searches:
HELP
for k in ${(k)searches}; do
echo " ${k}:\t${(Q)searches[$k]}";
done
<<-HELP
defined module options:
HELP
for k in ${(k)searches}; do
eval "if [ \"\${#opts_$k}\" -gt 0 ]; then
echo \" Module ${(Q)searches[$k]}:\";
for o in \${(k)opts_${k}}; do
echo \" opt_${k}_\${o}: \${opts_${k}[\$o]}\";
done
fi"
done
exit 0
fi
# start dmenu
coproc dmenu -i -l 20 -p 'serchilo widget:'
# generate menu elements
for i in ${(k)searches}; do print -p "${i} - ${searches[$i]}"; done
# close coproc stdin
exec 5>&p 6<&p; coproc exit; exec 5>&-
# get dmenu result
search=$(read -eu 6 | cut -d" " -f1)
[[ -z "$search" ]] && exit 1 #user aborted
if which "s_${search}" &>/dev/null; then
qs=$(s_${search})
else
qs="${SERCHILO}${search}"
result=$(dmhist "$search" | dmenu -i -l 20 -p "params to $search")
dmhistadd "$search" "$result"
qs+="+$(echo $result| urlencode)"
fi
echo ${webbrowser_cmd} $qs
${webbrowser_cmd} $qs

17
bin/dmtexdoc Executable file
View file

@ -0,0 +1,17 @@
#!/bin/zsh
zparseopts -D -E -help=help h=help -update=update u=update
CACHE_FILE="${XDG_CACHE_HOME:-$HOME/.cache}/dtexdoc.list"
SOURCES_FILE="${XDG_CONFIG_HOME:-$HOME/.config}/dmtexdoc/sources"
if [[ -n "$help" ]]; then
echo "Usage: $0 [-u|--update]"
exit 1
fi
if [[ -n "$update" || ! -e "$CACHE_FILE" ]]; then
find -L ${$(which texdoc):h:h:h}/texmf-dist/doc/ "${(@f)$(<$SOURCES_FILE)}" \
-iname '*.pdf' -printf "%f\n" \
| sed -e 's/\..*//' | sort | uniq > $CACHE_FILE
fi
texdoc $(dmenu < $CACHE_FILE)

5
bin/dmumount Executable file
View file

@ -0,0 +1,5 @@
#!/bin/zsh
device=$(udiskie-info -a -o '{mount_path}' | grep -ve '^$' | dmenu -l 20)
if [[ -n "$device" ]]; then
udiskie-umount $device
fi

39
bin/dmxrandr Executable file
View file

@ -0,0 +1,39 @@
#!/usr/bin/env ruby
require 'xrandr'
require 'dmenu'
menu = Dmenu.new
menu.case_insensitive = true
menu.lines = 20
outputs = Xrandr::Parser.new.parse[1].group_by(&:connected)
menu.items = (outputs[true] + outputs[false]).map{
|o| Dmenu::Item.new(o.name + (o.connected ? ' (connected)' : ''), o)
}
menu.prompt = "output:"
output = menu.run.value
menu.items = output.modes.map{
|mode|Dmenu::Item.new(mode.resolution, {mode: mode.resolution})
}
menu.items << Dmenu::Item.new("off", {off: true})
menu.prompt = "Current resolution: #{output.resolution}"
mode = menu.run.value
unless mode[:off]
menu.items = [:"left-of", :"right-of", :"above", :"below"].flat_map{|dir|
outputs[true].reject{|o| o == output}.map{|out| [dir,out]}
}.map{|setting|
Dmenu::Item.new(setting[0].to_s.gsub('-',' ') + " " + setting[1].name,
{setting[0] => setting[1].name})
}
menu.items << Dmenu::Item.new("don't change", {})
menu.prompt = "Select position:"
mode.merge! menu.run.value
end
control = Xrandr::Control.new
control.configure(output, mode)
control.apply!

5
bin/fixenc Executable file
View file

@ -0,0 +1,5 @@
#!/bin/zsh
for i in "$@"; do
dos2unix $i &>/dev/null
iconv -fLATIN1 -tUTF8 $i | sponge $i
done

6
bin/idea Executable file
View file

@ -0,0 +1,6 @@
#!/bin/zsh
unset JAVA_HOME
source /etc/profile.d/11_oracle-jdk.sh
export IBUS_ENABLE_SYNC_MODE=1
export XMODIFIERS=""
exec $(ls ${XDG_DATA_HOME:-~/.local/share}/idea-IU-*/bin/idea.sh | sort | tail -n 1)

20
bin/ipy Executable file
View file

@ -0,0 +1,20 @@
#!/bin/zsh
if [[ -n $VIRTUAL_ENV ]]; then
pip install ipython &>/dev/null
else
cd ~/toy-projects/playground_venv/
. bin/activate
fi
if [[ -e $VIRTUAL_ENV/ipython_profile ]]; then
ipy_profile="--profile=$(<$VIRTUAL_ENV/ipython_profile)"
fi
if [[ "$1" == "pip" ]]; then
exec "$@"
elif [[ $1 == "-s" ]]; then
exec $SHELL
else
exec ipython $ipy_profile "$@"
fi

11
bin/mdcat Executable file
View file

@ -0,0 +1,11 @@
#!/bin/zsh
MDCAT=/usr/bin/mdcat
encoding=$(file -i "$1" | sed "s/.*charset=\(.*\)$/\1/")
if ! iconv -f $encoding <<<"" &> /dev/null; then
cat "$1"
elif [[ $encoding != 'utf-8' ]]; then
iconv -f $encoding -t 'utf-8' < "$1" | $MDCAT /dev/stdin
else
$MDCAT $1
fi

13
bin/mkscript Executable file
View file

@ -0,0 +1,13 @@
#!/bin/zsh
BINDIR=$HOME/.local/bin
if [[ -e $BINDIR/$1 ]]; then
echo Script $1 exists, opening for edit
$EDITOR $BINDIR/$1
else
touch $BINDIR/$1
chmod a+x $BINDIR/$1
echo "#!$SHELL" >> $BINDIR/$1
$EDITOR $BINDIR/$1
exit 0
fi

75
bin/newmails Executable file
View file

@ -0,0 +1,75 @@
#!/bin/zsh
DEFAULT=raw
ICON=/usr/share/icons/Adwaita/48x48/actions/mail-message-new.png
opt() {
if [ -n "$1" ]; then
return 0
else
return 1
fi
}
contains() {
arr=$1
value=$2
[[ ${${(P)arr}[(ie)$value]} -lt ${#${(P)arr}} ]]
}
zparseopts -D -E h=help -help=help \
r=raw -raw=raw \
n=number -number=number \
p=pretty -pretty=pretty
if [ -n "$help" ]; then
cat <<HELP
Usage: newmails [OPTIONS] [MAILDIR]
Options:
-h --help Show this help
-r --raw Show full paths to new mail files (default)
-n --number Only show number of new mails
-p --pretty Show formatted output of new mails (TODO)
HELP
fi
local md=${MAILDIR:-${MAIL:-$HOME/Mail}}
local cache=${XDG_CACHE_HOME:-$HOME/.cache}/seen-mails
newmails=$(find $md/ -type f -a \
\( -regex ".*:2,[PRTDF]*" \) -exec realpath \{\} \;)
decode(){
perl -CS -MEncode -ne 'print decode("MIME-Header", $_)' | \
sed -e 's/&/\&amp;/' -e 's/</\&lt;/' -e 's/>/\&gt;/'
}
from() { formail -zcb -xFrom | tail -n 1 | decode }
subject() { formail -zcb -xSubject | decode }
if opt $number; then
echo -n $newmails | wc -l
exit 0
fi
if opt $pretty; then
touch $cache
seen=$(<$cache)
truncate --size 0 $cache
notify-send --icon=$ICON "$(
echo -n $newmails | while read mail; do
if ! contains seen $mail; then
echo -n "<b>$(from < $mail):</b> $(subject < $mail)<br>"
fi
echo $mail >> $cache
done
)"
exit 0
fi
#otherwise
echo -n $newmails

7
bin/pdftosvg Executable file
View file

@ -0,0 +1,7 @@
#!/bin/zsh
for i in "$@"; do
inkscape --without-gui --file=$i --export-plain-svg=/dev/stdout \
| tr -d '\n' \
| sed -e 's!</\?tspan[^>]*>!!g' \
| xmllint --compress /dev/stdin --output ${i:r}.svg
done

74
bin/pomdep-graph Executable file
View file

@ -0,0 +1,74 @@
#!/bin/zsh
zparseopts -D -K -E h=help -help=help -renderer:=renderer r:=renderer \
f:=filter -filter:=filter \
o:=output -output:=output \
l:=leaf_color -leaf-color:=leaf_color \
G=graph_only -graph-only=graph_only
renderer=${renderer[2]:-dot}
output=${output[2]:-deps.png}
leaf_color=${leaf_color[2]:-green}
if [[ $output == "-" ]]; then output=/dev/stdout; fi
if [[ -n $graph_only ]]; then
renderer=cat
output=/dev/stdout
fi
if [[ -z "$2" ]]; then
echo "Usage: $0 [options] POM_FILE..."
echo
echo "Options:"
echo " -f, --filter=TEXT only show dependencies with TEXT in their group id"
echo " -r, --renderer=PROGRAM use PROGRAM for rendering. May contain additional parameters"
echo " e.g. -r \"dot -Goverlap=false\""
echo " default: dot -Tpng"
echo " -o, --output=FILE output to FILE, defaults to deps.png"
echo " -l, --leaf-color=COLOR color of leaf nodes (packages without dependencies)"
echo " -G, --graph-only output unlayouted graph code, overrides -r and -o"
echo " equivalent to \"-r cat -o /dev/stdout\""
fi
if [[ -n $filter ]]; then
DEP_PATH="//dependencies//groupId[contains(text(),'${filter[2]}')]/following-sibling::artifactId/text()"
else
DEP_PATH="//dependencies//groupId/following-sibling::artifactId/text()"
fi
PKG_PATH="/project/artifactId/text()"
xpath() {
xmllint --shell <(sed -e "s/xmlns=/ignore=/" $2) <<<"cat $1" | grep -v '^\(/ >\| --\)'
}
remove-disconnected() {
gvpr -c "N[$.degree==0]{delete(NULL, $)}" "$@"
}
color-leaf-deps() {
gvpr -c "N[$.outdegree==0]{$.color ='$1'}"
}
graph-from-poms() {
echo 'digraph deps {'
for pom in "$@"; do
pkg=$(xpath $PKG_PATH $pom)
deps=($(xpath $DEP_PATH $pom | grep '^[a-zA-Z]'))
echo " \"$pkg\""
for i in $deps; do
echo " \"$pkg\" -> \"$i\""
done
done
echo '}'
}
render() {
$=renderer > $output
}
graph-from-poms "$@" | remove-disconnected | color-leaf-deps $leaf_color | render

2
bin/qrshow Executable file
View file

@ -0,0 +1,2 @@
#!/bin/zsh
qrencode -s 40 "$*" -o - | feh -ZF -

40
bin/re Executable file
View file

@ -0,0 +1,40 @@
#!/bin/zsh
SCRIPTDIR=$XDG_CONFIG_HOME/re/
zparseopts -D h=help -help=help d:=dir -dir:=dir n=dry_run -dry-run=dry_run e=edit -edit=edit
if [[ -z "$@" || -n $help ]]; then
<<-HELP
re - execute regular jobs without cluttering your path
Usage: re [opts] <scriptname> [scriptopts]
1. put script in $SCRIPTDIR
2. run "re <scriptname>"
3. ...
4. PROFIT!
Options:
-d, --dir=DIR change to given directory
-n, --dry-run just display the script, that would be executed
-e, --edit open the script in an editor
HELP
exit
fi
if [[ -n $dir ]]; then
cd $dir[2]
fi
if [[ -e $SCRIPTDIR/$1 ]]; then
if [[ -n $dry_run ]]; then
$PAGER -F $SCRIPTDIR/$1
elif [[ -n $edit ]]; then
$EDITOR $SCRIPTDIR/$1
else
script=$1
shift
. $SCRIPTDIR/$script "$@"
fi
else
echo "Script \"$1\" not found"
fi

5
bin/tmux-url-fuzz Executable file
View file

@ -0,0 +1,5 @@
#!/bin/zsh
target=$(tmux capture-pane -e -p -J -S -20 \
| grep -oP "(https?://|www\.)[^\"<>') \e]*" \
| ifne fzf-tmux --tac)
if [[ -n $target ]]; then xdg-open $target; fi

56
bin/unlock-parse Executable file
View file

@ -0,0 +1,56 @@
#!/usr/bin/env ruby
require 'time'
def valid_log(lines)
lines.reduce(["L",true]){|acc,line|
if acc[1] && line[0] != acc[0] then
[line[0], true]
else
[nil, false]
end
}[1]
end
if ARGV[0] == '-h' then
puts <<~HELP
Usage: unlock-parse [-s] DAY...
-s short output, total only
HELP
exit
end
if ARGV[0] == '-s' then
short=true
days=ARGV[1..-1]
else
short=false
days=ARGV
end
days.empty? && days = [Date.today.iso8601]
days.each do |logday|
path = if File.exists? logday then logday else ENV['XDG_DATA_HOME'] + '/log/locktime/' + logday end
log = File.readlines(path)
if ! valid_log(log) then puts "Invalid log file"; exit 1 end
if log.length % 2 != 0 then
log << "L " + Time.now.iso8601
end
times = log.each_slice(2).map{|e|
Time.parse(e[1][2..-1]) - Time.parse(e[0][2..-1])
}
if ! short then
times.map{|t| Time.at(t).utc.strftime("%H:%M:%S")}.each{|s|puts s}
puts "\nTotal:"
end
puts Time.at(times.sum).utc.strftime("%H:%M:%S")
end

22
bin/unlock-track Executable file
View file

@ -0,0 +1,22 @@
#!/bin/zsh
lockstate() { pidof slimlock &>/dev/null }
lockstate; was_locked=$?
LOGDIR=${XDG_DATA_HOME:-$HOME/.local/share}/log/locktime
mkdir -p $LOGDIR
logfile=$LOGDIR/$(date --iso-8601)
while true; do
if lockstate && [[ $was_locked -gt 0 ]]; then
echo "L $(date --iso-8601=minute)" >> $logfile
was_locked=0
elif ! lockstate && [[ $was_locked == 0 ]]; then
# change daily logfile on first unlock
logfile=$LOGDIR/$(date --iso-8601)
echo "U $(date --iso-8601=minute)" >> $logfile
was_locked=1
fi
sleep 60
done

13
bin/update-amm Executable file
View file

@ -0,0 +1,13 @@
#!/bin/zsh
versions=$(curl -L https://api.github.com/repos/lihaoyi/Ammonite/releases/latest)
download-version() {
(
echo "#/usr/bin/env python --version sh" && \
curl -L $( echo $versions \
| jq -r ".assets | map(select(.name | startswith(\"$1\")))[0].browser_download_url")
) > $2
chmod +x $2
}
download-version 2.13 $(which amm)
download-version 2.12 $(which amm)2.12

36
bin/venv Executable file
View file

@ -0,0 +1,36 @@
#!/bin/zsh
zparseopts -D -E c=cdhere -cdhere=cdhere h=help -help=help
if [[ -n $help ]]; then
<<-HELP
Usage: ${0:t} [-c] [DIR]
If DIR contains bin/activate, start a shell with that virtualenv.
Otherwise recursively look up virtualenvs in DIR (by looking for dirs ending
in "venv") and select one with fzf.
-c, --cdhere Change back to the current working directory instead of the
virtual env's base dir
HELP
exit
fi
ORIGDIR=$PWD
venvsh() {
cd $1
. bin/activate
if [[ -n $cdhere ]]; then
cd $ORIGDIR
fi
$SHELL
}
if [[ -n $1 && -e $1/bin/activate ]]; then
exec venvsh $1
fi
venv=$(fd -I -t d 'venv$' $1 | fzf)
if [[ -n $venv ]]; then
venvsh $venv
fi

20
bin/vf Executable file
View file

@ -0,0 +1,20 @@
#!/bin/zsh
zparseopts -D -E -ext:=ext e:=ext h=help -help=help
if [[ -n $help ]]; then
<<-HELP
Usage: ${0:t} [-e EXT | PATTERN] [DIR...]
Find files with fd, show them with fzf and open selected files via xdg-open.
Either -e with a file extension or a pattern can be given to narrow search.
Any further arguments are passed to fd as search path.
HELP
exit
fi
if [[ -n $ext ]]; then
fd -e ${ext[2]} . "$@"
else
fd "$@"
fi | fzf | xargs --null xdg-open

10
bin/webapp Executable file
View file

@ -0,0 +1,10 @@
#!/bin/zsh
profile="${0:t}"
need firefox
need firejail
mkdir -p $HOME/.jails/firefox-$profile
exec firejail --private=$HOME/.jails/firefox-$profile \
firefox --no-remote "$@"

3
bin/webapp-cp Executable file
View file

@ -0,0 +1,3 @@
#!/bin/zsh
profile="${${0:t}%%-cp}"
cp "$@" $HOME/.jails/firefox-$profile

83
bin/xc Executable file
View file

@ -0,0 +1,83 @@
#!/bin/zsh
# install this program with the name xc and symlink it as xs.
# xc will use the clipboard selection, while xs while use the primary selection
source $(which need)
need xclip
function get_primary() { xclip -o -selection primary }
function get_clipboard() { xclip -o -selection clipboard }
function set_primary() { xclip -i -selection primary }
function set_clipboard() { xclip -i -selection clipboard }
function show_both() {
printf "\e[1;94mPrimary\e[0m\n"
get_primary
echo
printf "\e[1;94mClipboard\e[0m\n"
get_clipboard
}
function read_both() {
need pee moreutils
pee "xclip -i -selection primary" "xclip -i -selection clipboard"
}
function common() {
cmd=$1
getc=$2
setc=$3
shift 3
case "$cmd" in
"read") $setc;;
"readboth") read_both ;;
"showboth") show_both ;;
"sed") $getc | sed -e "$@" | $setc; $getc;;
"pipe") $getc | "$@" | $setc; $getc;;
"edit") need vipe moreutils; $getc | vipe | $setc; $getc;;
"") $getc ;;
*) <<-HELP
Usage: xc [COMMAND]
xc fromxs|toxs
xs [COMMAND]
xs fromxc|toxc
The used X selection is determined by the name the program is called as:
xc: clipboard (Ctrl-C / Ctrl-V)
xs: primary selection (middle mouse button)
For showboth/readboth, the action is done for both selections.
Commands:
show/showboth: show contents of clipboard (default if no command given)
read/readboth: store input to clipboard
sed: modify contents using a sed expression
pipe: modify contents by piping through a command
edit: edit clipboard contents using \$EDITOR
fromxs/toxs: xc only: copy contents from or to primary selection
fromxc/toxc: xs only: copy contents from or to clipboard
HELP
;;
esac
}
cmd=$1
[[ -n $1 ]] && shift
case "${0:t}" in
xc)
case "$cmd" in
"fromxs"|"fromXS") get_primary | set_clipboard ;;
"toxs"|"toXS") get_clipboard | set_primary ;;
*) common "$cmd" get_clipboard set_clipboard "$@";;
esac
;;
xs)
case "$cmd" in
"fromxc"|"fromXC") get_clipboard | set_primary ;;
"toxc"|"toXC") get_primary | set_clipboard ;;
*) common "$cmd" get_primary set_primary "$@";;
esac
;;
esac