diff --git a/.bin/12color.sh b/.bin/OLD/12color.sh similarity index 100% rename from .bin/12color.sh rename to .bin/OLD/12color.sh diff --git a/.bin/16colors.sh b/.bin/OLD/16colors.sh similarity index 100% rename from .bin/16colors.sh rename to .bin/OLD/16colors.sh diff --git a/.bin/OLD/256color.sh b/.bin/OLD/256color.sh new file mode 100755 index 0000000..ae894fb --- /dev/null +++ b/.bin/OLD/256color.sh @@ -0,0 +1,10 @@ +#!/bin/sh +for fgbg in 38 48; do + while [ "${color:=0}" -le 255 ]; do + printf "\\e[${fgbg};5;%sm %3s \\e[0m" $color $color + [ $(((color + 1) % 6)) = 4 ] && printf '\n' + color=$((color+1)) + done + printf '\n' && unset color +done +exit 0 diff --git a/.bin/OLD/KAPUTT/backup_laptop.sh b/.bin/OLD/KAPUTT/backup_laptop.sh new file mode 100755 index 0000000..cf83aa6 --- /dev/null +++ b/.bin/OLD/KAPUTT/backup_laptop.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +# +DATE="$(date +%F_%H-%M-%S)" +SRC="/" +DST="sdk@192.168.1.20:/tank/BACKUP/" + +ROPTS="--archive --human-readable --progress --size-only" + +rsync --archive --human-readable --progress --size-only --link-dest $PWD/current source "$PWD/destination" diff --git a/.bin/OLD/KAPUTT/ccc-streams.sh b/.bin/OLD/KAPUTT/ccc-streams.sh new file mode 100755 index 0000000..2fc34c5 --- /dev/null +++ b/.bin/OLD/KAPUTT/ccc-streams.sh @@ -0,0 +1,76 @@ +#!/bin/sh + +sformat="webm" +squality="sd" +translated="native" +mediaplayer="mpv" + +usage() { + printf "Available rooms:\n" >&2 + printf " a|ada|1\n" >&2 + printf " b|borg|2\n" >&2 + printf " c|clarke|3\n" >&2 + printf " d|dijkstra|4\n" >&2 + printf " e|elize|5\n" >&2 + printf " chaoswest|150\n" >&2 + printf " openinfrastructure|oio\n" >&2 + printf " wiki|151\n\n" >&2 + exit 1 +} + +[ -z $1 ] && usage; + +hall="$1" + +case "$hall" in +1|2|3|4|5|150|151|oio) + ;; +a|ada) + hall="1" + ;; +b|borg) + hall="2" + ;; +c|clarke) + hall="3" + ;; +d|dijkstra) + hall="4" + ;; +e|eliza) + hall="5" + ;; +chaoswest) + hall="150" + ;; +open*) + hall="oio" + ;; +wiki*) + hall="151" + ;; +*) + usage; + ;; +esac + +webmbase="http://cdn.c3voc.de/s%s_%s_%s.webm" +hlsbase="http://cdn.c3voc.de/hls/s%s_%s_%s.m3u8" +audiobase="http://cdn.c3voc.de/s%s_%s.%s" + +slink="" +case "$sformat" in +webm) + slink="$(printf "$webmbase" "${hall}" "${translated}" "${squality}")" + ;; +m3u8|hls) + slink="$(printf "$hlsbase" "${hall}" "${translated}" "${squality}")" + ;; +*) + printf "Only the stream formats »webm« and »hls« are available.\n" >&2 + exit 1 + ;; +esac + +$mediaplayer "$slink" + diff --git a/.bin/OLD/KAPUTT/chrome b/.bin/OLD/KAPUTT/chrome new file mode 100755 index 0000000..00bb5bf --- /dev/null +++ b/.bin/OLD/KAPUTT/chrome @@ -0,0 +1,2 @@ +#!/bin/sh +/usr/local/bin/chrome --enable-unveil --enable-features=WebUIDarkMode --force-dark-mode $@ diff --git a/.bin/OLD/KAPUTT/openbsd_post_install_pkg.sh b/.bin/OLD/KAPUTT/openbsd_post_install_pkg.sh new file mode 100755 index 0000000..21a6527 --- /dev/null +++ b/.bin/OLD/KAPUTT/openbsd_post_install_pkg.sh @@ -0,0 +1,35 @@ +#!/bin/sh + +# essential +pkg_add rsync wget curl lftp mc ranger vim speedtest-cli autocutsel git ectags + +# dwm +pkg_add dmenu jq scrot slop + +# pass +pkg_add password-store gnupg pinentry +doas ln -s /usr/local/bin/pinentry /usr/bin/pinentry + +# mutt +pkg_add mutt w3m urlview msmtp offlineimap mu par + +# irssi +pkg_add irssi + +# luakit +pkg_add luafs luajit gmake webkitgtk4 + +# multimedia +pkg_add ffmpeg ffmpegthumbnailer youtube-dl ImageMagick + +# tor +pkg_add tor torsocks + +# X11 +pkg_add mupdf zathura zathura-pdf-mupdf sxiv seafile-client pidgin telegram-purple + +# other +pkg_add nload htop nmap ncdu tig xosd sshfs-fuse + +# BIG ones +pkg_add firefox libreoffice gimp smtube fnaify vimb diff --git a/.bin/OLD/KAPUTT/openup b/.bin/OLD/KAPUTT/openup new file mode 100755 index 0000000..d163fad --- /dev/null +++ b/.bin/OLD/KAPUTT/openup @@ -0,0 +1,383 @@ +#!/bin/sh +# +# Copyright (c) 2013 - 2017 M:tier Ltd. +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +# +# Author: Antoine Jacoutot +# Maintainer: M:Tier Ltd. + +# ChangeLog +# https://gitlab.com/mtier/openup/commits/master + +######################################################################## +### DO NOT EDIT THIS FILE!!! ### +### User defined variables: overrides are read from /etc/openup.conf ### +######################################################################## + +# URL to the latest openup version +OPENUP_URL="https://stable.mtier.org/openup" + +# signify(1) public key +PKG_PUBKEY_URL="https://stable.mtier.org/mtier-$(uname -r | tr -d '.')-pkg.pub" + +# PKG_PATH for currently running OpenBSD release +PKG_PATH_MAIN="https://ftp.fr.openbsd.org/pub/OpenBSD/$(uname -r)/packages/$(arch -s)" + +# ERRATA_PATH +ERRATA_PATH="https://ftp.fr.openbsd.org/pub/OpenBSD/patches/$(uname -r)/common" + +# PKG_PATH for the corresponding release stable service +PKG_PATH_UPDATE="https://stable.mtier.org/updates/$(uname -r)/$(arch -s)" + +# PKG_PATH addition for the corresponding LTS release stable service +#PKG_PATH_UPDATE_LTS="https://user%domain.tld:password@stable.mtier.org/updates-lts/$(uname -r)/$(arch -s)" + +# URL to the latest vuxml (vulnerabilities database) +VUXML_URL="https://stable.mtier.org/vuxml/$(uname -r | tr -d '.').xml" + +# fetch command (must behave like "ftp -o"); e.g. "wget -qO" +FETCH="ftp -MVo" + +# exclusion list: pkg names without version/flavor, separated by space +EXCLUDE_PKG="" + +######################################################################## +### End of user defined variables ### +######################################################################## + +usage() { + echo + echo "Usage: ${0##*/} [-K][-Se|c]" >&2 + echo + echo "Options:" + echo " -K do not check for kernel binpatches (when running non GENERIC)" + echo " -N do not check for syspatches" + echo " -S ignore binpatch/package signatures" + echo " -c check/cron mode, report only (cannot be used with -S)" + echo " -e echo the PKG_PATH that ${0##*/} would use" + echo + exit 1 +} + +pr_err() { + echo "!!! ${@}" +} + +bye_bye() { + rm -rf ${_TMPDIR} ${_PID} + exit 1 +} + +pr() { + if [ -z "${checkrun}" ]; then + echo "===> ${@}" + fi +} + +get_key() { + [ -r /etc/signify/mtier-${_REL_INT}-pkg.pub ] && return + + pr "Downloading and installing public key" + ${FETCH} ${_TMPKEY} ${PKG_PUBKEY_URL} || bye_bye + install -m0644 ${_TMPKEY} /etc/signify/mtier-${_REL_INT}-pkg.pub || bye_bye +} + +show_env() { + echo PKG_PATH=${PKG_PATH_UPDATE_LTS}:${PKG_PATH_UPDATE}:${PKG_PATH_MAIN} + exit 0 +} + +check_openupd() { + local _U + + pr "Checking for openup update" + _U="${FETCH} - ${OPENUP_URL} | awk -F '=' '/^_OPENUP_VERSION/ { print \$2 }'" + _U=$(eval $_U) + if [ -z "${_U}" ]; then + pr_err "Cannot retrieve ${OPENUP_URL}" + pr_err "Please verify your Internet connection, proxy settings and firewall." + bye_bye + fi + + if [ "${_OPENUP_VERSION}" -lt "${_U}" ]; then + pr_err "New openup release (version ${_U}) available; please update with:" + pr_err "${FETCH} $(readlink -f $0) ${OPENUP_URL}" + bye_bye + fi +} + +# check that we have no installed binpatches from a previous release and +# if so remove the entries manually (we don't want pkg_delete to +# modify nor error out on installed files from newer release/binpatch) +rm_old_bp() { + local _bp + local _BPDB=$(ls -d /var/db/binpatch/{binpatch-,}[0-9]* 2>/dev/null |grep -v ${_REL}) + local _BPPKG=$(ls -d /var/db/pkg/binpatch* 2>/dev/null |grep -v binpatch${_REL_INT}) + if [ -n "${_BPPKG}" -o -n "${_BPDB}" ]; then + pr "Removing old release binpatch entries" + fi + for _bp in ${_BPPKG} ${_BPDB}; do + rm -rf ${_bp} + done +} + +update_syspatches() { + pr "Installing/updating syspatches" + syspatch + if [ $? -gt 0 ]; then + pr_err "syspatch failed; please run syspatch manually" + bye_bye + fi +} + +update_binpatches() { + local _BP _b _e + + # binpatches can only be found in PKG_PATH_UPDATE{,_LTS) and we + # want to make sure we search in all paths and don't stop at the + # first match we find + for i in ${PKG_PATH_UPDATE_LTS} ${PKG_PATH_UPDATE}; do + _BP="$(pkg_info -Q binpatch${_REL_INT}-${_ARCH} | sed 's/.[^-]*$//' | sort -u)${_BP:+ ${_BP}}" + done + + if [ -n "${_BP}" ]; then + for _e in ${EXCLUDE_PKG}; do + set -A _BP -- ${_BP} + _BP="$(for _b in ${_BP[@]}; do echo ${_b} | grep -v "^${_e}$"; done)" + done + _BP=$(echo "${_BP}" | tr '\n' ' ') + + pr "Installing/updating binpatch(es)" + pkg_add ${pkgopt} ${_BP} || bye_bye + fi +} + +update_pkg() { + local _PKG _e _p + + _PKG=$(pkg_info -q | grep -v binpatch${_REL_INT}-${_ARCH}) + + if [ -n "${_PKG}" ]; then + for _e in ${EXCLUDE_PKG}; do + set -A _PKG -- ${_PKG} + _PKG="$(for _p in ${_PKG[@]}; do echo ${_p} | grep -v "^${_e}-.*"; done)" + done + _PKG=$(echo "${_PKG}" | tr '\n' ' ') + + pr "Updating package(s)" + pkg_add -quz ${pkgopt} ${_PKG} || bye_bye + fi +} + +# this only outputs the missing syspatches on the system +check_syspatches() { + _SYSPATCHES=$(syspatch -c) + for _p in ${_SYSPATCHES}; do + ${FETCH} ${_TMPERRATA} ${ERRATA_PATH}/${_p}.patch.sig + [ -e ${_TMPERRATA} ] || continue + echo "--- ${_p} ---" + echo -n "Available errata: " + awk '/OpenBSD/{f=1;next} /Apply/{f=0;next} f' ${_TMPERRATA} | grep -ve '^$' + done +} + +# this only outputs the most recent vulnerability for each matching pkg +check_vuxml() { + local _BP_MATCH _OUTDATED _PKG_MATCH _b _e _p + + ${FETCH} ${_TMPVUXML} ${VUXML_URL} || bye_bye + perl -pi -e 's,\$ARCH,'"${_ARCH}"',g' ${_TMPVUXML} + + if [ "${_REL_INT}" -lt 61 ]; then + _BP_MATCH="$(grep binpatch ${_TMPVUXML} | sed -e 's,,,g;s,,,g;s,\$ARCH,'"${_ARCH}"',g' | sort -u)" + for _e in ${EXCLUDE_PKG}; do + set -A _BP_MATCH -- ${_BP_MATCH} + _BP_MATCH="$(for _b in ${_BP_MATCH[@]}; do echo ${_b} | grep -v "^${_e}$"; done)" + done + fi + + _PKG_MATCH=$(pkg_info -q | grep -v binpatch${_REL_INT}-${_ARCH}) + + for _e in ${EXCLUDE_PKG}; do + set -A _PKG_MATCH -- ${_PKG_MATCH} + _PKG_MATCH="$(for _p in ${_PKG_MATCH[@]}; do echo ${_p} | grep -v "^${_e}-.*"; done)" + done + + if [ "${_REL_INT}" -lt 61 ]; then + # set to "quirks" if empty to prevent running pkg_add against an empty pkg list + _OUTDATED=$((pkg_add -Iqn -Dnosig -Dunsigned ${_BP_MATCH:=quirks}; pkg_add -Iqnuz -Dnosig -Dunsigned ${_PKG_MATCH:=quirks}) 2>&1 | \ + grep '^NOT CHECKING DIGITAL SIGNATURE FOR ' | \ + sed -e 's,^NOT CHECKING DIGITAL SIGNATURE FOR ,,g' | \ + grep -v '^quirks-' | \ + perl -ne '/^(.*)-(\d[^-]*)[-]?(\w*)(.*)$/ && print "$1\n"' | \ + sort -u) + else + # set to "quirks" if empty to prevent running pkg_add against an empty pkg list + _OUTDATED=$((pkg_add -Inuvz -Dnosig -Dunsigned ${_PKG_MATCH:=quirks}) 2>&1 | \ + grep '^Adding.*(pretending)' | sort -u | sed -e 's,Adding ,,;s,(pretending),,;s,->.*,,' | \ + grep -v '^quirks-' | \ + perl -ne '/^(.*)-(\d[^-]*)[-]?(\w*)(.*)$/ && print "$1\n"' | \ + sort -u) + fi + + for p in ${_OUTDATED} + do + echo "--- ${p} ---\n" + echo "Available update(s): " + # XXX how do we print only the 1st matching range in awk? + awk "/${p}<\/name>/,/<\/vuln>/" ${_TMPVUXML} | \ + sed '/<\/vuln>/,$d' | \ + sed -n -e 's/.*\(.*\)<\/lt><\/range>.*/\1/p' \ + -e 's/.*

\(.*\)<\/p>.*/\1/p' | uniq | \ + while read l; do echo -n "${l} "; done + echo "\n" + done | fmt | sed '/^$/d' +} + +do_i_need_to_reboot() { + # XXX hardcoded PKG_DBDIR + local osversion=$(sysctl -n kern.osversion) + local kern_version=$(sysctl -n kern.version | head -1) + local booted_version=$(what -s /bsd | tail -1 | tr -d '\t') + local booted_time=$(sysctl -n kern.boottime) + local kern_time=$(stat -qf "%Um" /bsd) + local warn=0 + + # Check /bsd.booted first if available due to kernel relinking + if [ -e /bsd.booted ]; then + [ X"${kern_version}" != X"${booted_version}" ] && warn=1 + else + [ "${booted_time}" -lt "${kern_time}" ] && warn=1 + fi + + if [ ${warn} -gt 0 ]; then + pr_err + pr_err "System must be rebooted after the last kernel update" + pr_err + fi +} + +patch_syspatch() { + pr_err + pr_err "Patching syspatch(8) to use syspatches signed by MTier." + pr_err + cp /usr/sbin/syspatch /usr/sbin/syspatch.pre-mtier + sed -i \ + "s,openbsd-\${_OSrev}-syspatch.pub,mtier-\${_OSrev}-pkg.pub,g; \ + s,/etc/installurl,/etc/installurl-mtier,g" \ + /usr/sbin/syspatch + [ -e /etc/installurl-mtier ] || echo https://stable.mtier.org > /etc/installurl-mtier +} + +trap "bye_bye" 1 2 3 13 15 + +if [ -f /etc/openup.conf ]; then + if [ $(stat -f "%SMp%SLp" /etc/openup.conf) != "------" ]; then + pr_err "Unsecure permissions on /etc/openup.conf; please run:" + pr_err "chmod 0600 /etc/openup.conf" + exit 1 + fi + . /etc/openup.conf +fi + +# regex taken from fw_update(1) +set -A _REL -- $(sysctl -n kern.version | sed 's/^OpenBSD \([0-9]\.[0-9]\)\([^ ]*\).*/\1 \2/;q') +_REL_INT="$(echo ${_REL[0]} | tr -d '.')" +_OPENUP_MINREL=60 +_OPENUP_VERSION=33 +if [ -n "${_REL[1]}" -a "${_REL[1]}" != "-stable" ]; then _badrel=1; fi +if [ "${_REL_INT}" -lt "${_OPENUP_MINREL}" ]; then _badrel=1; fi +if [ -n "${_badrel}" ]; then + pr_err "${_REL[0]}${_REL[1]} is not a supported release" + exit 1 +fi + +while getopts 'KNSce' arg; do + case ${arg} in + K) if [ "${_REL_INT}" -lt 61 ]; then nokrn=1; fi ;; + N) nosyspatch=1 ;; + S) nosig=1; pkgopt="${pkgopt} -Dnosig -Dunsigned" ;; + c) checkrun=1 ;; + e) showenv=1 ;; + *) usage ;; + esac +done +[ $# = $(($OPTIND-1)) ] || usage + +[ -n "${showenv}" ] && show_env + +if [ "$(id -u)" -ne 0 ]; then + pr_err "Need root privileges to run this script" + usage +fi + +[ -n "${checkrun}" -a -n "${nosig}" -a -n "${showenv}" ] && usage + +_ARCH=$(arch -s) +_PID="/var/run/${0##*/}.pid" +_TMP="${TMPDIR:=/tmp}" +_TMPDIR=$(mktemp -dp ${_TMP} .openup-XXXXXXXXXX) || exit 1 +_TMPKEY="${_TMPDIR}/key" +_TMPVUXML="${_TMPDIR}/vuxml" +_TMPERRATA="${_TMPDIR}/errata" + +export PKG_PATH=${PKG_PATH_UPDATE_LTS}:${PKG_PATH_UPDATE}:${PKG_PATH_MAIN} + +if [ -f ${_PID} ]; then + pr_err "openup is already running ($(cat ${_PID})):" + pr_err "${_PID}" + exit 1 +fi +echo $$ >${_PID} + +if [ -n "${nokrn}" ]; then + EXCLUDE_PKG="binpatch${_REL_INT}-${_ARCH}-kernel ${EXCLUDE_PKG}" +fi +if [ -n "${EXCLUDE_PKG}" ]; then + pr "Excluded package(s)/binpatch(es): ${EXCLUDE_PKG}" +fi + +check_openupd + +if [ -z "${nosyspatch}" -a -e /usr/sbin/syspatch ]; then + _sum=$(sha256 -q /usr/sbin/syspatch) + case "${_sum}" + in + # 6.1 syspatch + b8b9c4bec128884498b5c3e77a350f42079f7987ef862a1ec452f489403dfbe6) + patch_syspatch + ;; + esac +fi + +if [ "${checkrun}" ]; then + if [ "${_REL_INT}" -ge 61 -a -z "${nosyspatch}" ]; then + check_syspatches + fi + check_vuxml +else + [ -z "${nosig}" ] && get_key + rm_old_bp + if [ "${_REL_INT}" -lt 61 -a -z "${nosyspatch}" ]; then + update_binpatches + else + [ -z "${nosyspatch}" ] && update_syspatches + fi + update_pkg +fi + +do_i_need_to_reboot + +rm -rf ${_TMPDIR} +rm ${_PID} diff --git a/.bin/OLD/KAPUTT/osd_pipe.sh b/.bin/OLD/KAPUTT/osd_pipe.sh new file mode 100755 index 0000000..49de881 --- /dev/null +++ b/.bin/OLD/KAPUTT/osd_pipe.sh @@ -0,0 +1,2 @@ +#!/bin/sh +osd_cat -l1 -p top -o 1 -A right -O 1 -s 1 -o 40 -w -d4 -i 20 -c "#eeeeee" -f "-xos4-terminus-medium-r-normal--16-160-72-72-c-80-iso8859-15" - diff --git a/.bin/OLD/KAPUTT/rec_encode b/.bin/OLD/KAPUTT/rec_encode new file mode 100755 index 0000000..60581d7 --- /dev/null +++ b/.bin/OLD/KAPUTT/rec_encode @@ -0,0 +1,15 @@ +#!/bin/sh + +_vidfile="/home/sdk/work/rec-screen.mkv" +_micfile="/home/sdk/work/rec-mic-clean.wav" +_outfile="${_vidfile%%.*}-$(date "+%Y%m%d_%H%M%S").mp4" + +ffmpeg -y -i $_vidfile \ + -i $_micfile \ + -c:v libx265 \ + -c:a aac -shortest \ + -crf 21 -s 1920x1080 \ + -preset medium -movflags faststart \ + -threads $(sysctl -n hw.ncpuonline) \ + $_outfile \ + && echo "Done encoding $(readlink -f $_outfile)" diff --git a/.bin/OLD/KAPUTT/rec_encode_noaudio b/.bin/OLD/KAPUTT/rec_encode_noaudio new file mode 100755 index 0000000..99e0f41 --- /dev/null +++ b/.bin/OLD/KAPUTT/rec_encode_noaudio @@ -0,0 +1,13 @@ +#!/bin/sh + +_vidfile="/home/sdk/work/rec-screen.mkv" +_outfile="${_vidfile%%.*}-$(date "+%Y%m%d_%H%M%S").mp4" + +ffmpeg -y -i $_vidfile \ + -c:v libx265 \ + -c:a aac -shortest \ + -crf 21 -s 1920x1080 \ + -preset medium -movflags faststart \ + -threads $(sysctl -n hw.ncpuonline) \ + $_outfile \ + && echo "Done encoding $(readlink -f $_outfile)" diff --git a/.bin/OLD/KAPUTT/rec_scr b/.bin/OLD/KAPUTT/rec_scr new file mode 100755 index 0000000..2e9d69d --- /dev/null +++ b/.bin/OLD/KAPUTT/rec_scr @@ -0,0 +1,79 @@ +#!/bin/sh + +screen=0 +microphone=0 +system_audio=0 + +select _sel in \ + "Record screen" \ + "Record microphone" \ + "Record system audio" \ + "Start recording" \ + "Quit" +do + case "$_sel" in + "Record screen") screen=1; ;; + "Record microphone") microphone=1; ;; + "Record system audio") system_audio=1; ;; + "Start recording") break; ;; + "Quit") exit 0; ;; + esac + +[ screen -eq 1 ] && echo "Screen recording: enabled" \ + || echo "Screen recodding: disabled" +[ microphone -eq 1 ] && echo "Microphone recording: enabled" \ + || echo "Microphone recodding: disabled" + +done + +clear + +set -x + +AUDIOMONDEVICE=snd/0.mon +AUDIOPLAYDEVICE=snd/0.default +AUDIORECDEVICE=snd/0.rec + +AUDIOMONPID=X +AUDIORECPID=X + +trap rec_stop 0 1 2 3 6 +rec_stop() { + kill $AUDIORECPID $AUDIOMONPID +} + +rec_mon() { + aucat -f $AUDIOMONDEVICE -o $HOME/work/rec-mon.wav & + AUDIOMONPID=$! +} + +rec_mic() { + aucat -o $HOME/work/rec-mic.wav & + AUDIORECPID=$! +} + +rec_screen() { + echo 'Press q to stop.' + ffmpeg -y -loglevel warning -hide_banner \ + -fflags genpts \ + -flags low_delay \ + -thread_queue_size 256 \ + -framerate 30 \ + -f x11grab \ + -probesize 16M \ + -i :0.0 \ + -c:v libx264rgb \ + -crf 0 \ + -qp 0 -framerate 30 \ + -sws_flags neighbor \ + -preset ultrafast \ + -tune zerolatency \ + $HOME/work/rec-screen.mkv +} + +rec_mon +rec_mic +rec_screen +rec_stop + +shotcut --noupgrade --fullscreen --clear-recent $HOME/work/rec-screen.mkv $HOME/work/rec-*.wav diff --git a/.bin/OLD/KAPUTT/rec_screen b/.bin/OLD/KAPUTT/rec_screen new file mode 100755 index 0000000..b747750 --- /dev/null +++ b/.bin/OLD/KAPUTT/rec_screen @@ -0,0 +1,83 @@ +#!/bin/sh + + +audio() { + # set mixer controls + print configuring microphone + mixerctl -q record.adc-0:1_source=mic2 + mixerctl -q record.adc-2:3_source=mic2 + mixerctl -q inputs.mix_source=mic2 +} + + +webcam() { + printf 'start webcam\n' + doas mpv --quiet \ + --panscan=1 \ + --framedrop=vo \ + --ontop av://v4l2:/dev/video0 \ + --profile=low-latency \ + --untimed \ + --vf=hflip \ + --geometry=220x180 2>&1 > /dev/null & + print move the picture to the right place and press any key + read +} + + +capture() { + printf 'starting recording... press q to stop\n' + RES=$(xwininfo -root | grep 'geometry' | awk '{print $2;}' |cut -d"+" -f1) + ffmpeg -y -loglevel warning \ + -thread_queue_size 256 \ + -probesize 10000000 \ + -hide_banner \ + -f sndio \ + -i default \ + -c:a flac \ + -f x11grab \ + -s $RES \ + -i :0.0 \ + -r 25 \ + -c:v libx265 \ + -crf 0 \ + -qp 0 \ + -preset ultrafast \ + -g 50 \ + -keyint_min 25 \ + $HOME/work/rec_screen.mkv +} + +encode() { + printf 'encoding video\n' + ffmpeg -y \ + -i $HOME/work/rec_screen.mkv \ + -c:v libx265 \ + -crf 21 \ + -s 1920x1080 \ + -preset medium \ + $HOME/work/rec_screen.mp4 +} + +printf ' +(1) desktop only (works on linux) +(2) desktop + audio +(3) desktop + webcam + audio +' +printf ": " +read sel + +case $sel in + 1) capture; + encode; + ;; + 2) audio; + capture; + encode; + ;; + 3) audio; + webcam; + capture; + encode; + ;; +esac diff --git a/.bin/OLD/KAPUTT/recscr b/.bin/OLD/KAPUTT/recscr new file mode 100755 index 0000000..eff4d90 --- /dev/null +++ b/.bin/OLD/KAPUTT/recscr @@ -0,0 +1,71 @@ +#!/bin/sh -xe + +clear + +AUDIOPLAYDEVICE=snd/0.default +AUDIORECDEVICE=snd/0.rec +AUDIOMONDEVICE=snd/0.mon + +AUDIOMONPID=X +AUDIORECPID=X + +trap rec_stop 1 2 3 6 +rec_stop() { + kill $AUDIORECPID $AUDIOMONPID +} + +rec_mon() { + aucat -f $AUDIOMONDEVICE -o $HOME/work/rec-mon.wav & + AUDIOMONPID=$! +} + +rec_mic() { + aucat -j on -c 0:0 -o $HOME/work/rec-mic.wav & + AUDIORECPID=$! +} + +rec_screen() { + echo 'Press q to stop.' + #ffmpeg -y \ + # -loglevel warning \ + # -hide_banner \ + # -fflags genpts \ + # -flags low_delay \ + # -thread_queue_size 256 \ + # -framerate 30 \ + # -f x11grab \ + # -probesize 16M \ + # -i :0.0 \ + # -c:v libx264rgb \ + # -crf 0 \ + # -qp 0 -framerate 30 \ + # -sws_flags neighbor \ + # -preset ultrafast \ + # -tune zerolatency \ + # $HOME/work/rec-screen.mkv + ffmpeg -y -loglevel warning -hide_banner \ + -f x11grab -i :0.0 -c:v libx264rgb -crf 0 -qp 0 -framerate 30 -sws_flags neighbor -preset ultrafast -tune zerolatency $HOME/work/rec-screen.mkv \ + -f sndio -i $AUDIORECDEVICE -c:a copy $HOME/work/rec-mic.wav \ + -f sndio -i $AUDIOMONDEVICE -c:a copy $HOME/work/rec-mon.wav +} + +#rec_mon +#rec_mic +rec_screen +#rec_stop + +sleep 0.5 + + sox $HOME/work/rec-mic.wav -n trim 0 5 noiseprof \ + | sox $HOME/work/rec-mic.wav $HOME/work/rec-mic-clean.wav \ + noisered - 0.2 bass 5 contrast +#sox $HOME/work/rec-mic.wav $HOME/work/rec-mic-clean.wav bass 5 contrast + +printf "[A]utoencode or [S]hotcut: " +read S + +case $S in + [aA]) rec_encode; ;; + [sS]) shotcut --noupgrade --fullscreen --clear-recent $HOME/work/rec-screen.mkv $HOME/work/rec-*.wav; ;; + *) ;; +esac diff --git a/.bin/OLD/KAPUTT/screen-make b/.bin/OLD/KAPUTT/screen-make new file mode 100755 index 0000000..31735aa --- /dev/null +++ b/.bin/OLD/KAPUTT/screen-make @@ -0,0 +1,2 @@ +#!/bin/sh +ssh ld7078 "screen -S make -p 0 -X stuff \"./mymake.sh -p krn/ms prg;`echo '\015'`\"" diff --git a/.bin/OLD/KAPUTT/sdedit b/.bin/OLD/KAPUTT/sdedit new file mode 100755 index 0000000..8aeca75 --- /dev/null +++ b/.bin/OLD/KAPUTT/sdedit @@ -0,0 +1,4 @@ +#!/bin/sh +export _JAVA_OPTIONS='-Dawt.useSystemAAFontSettings=gasp -Dswing.defaultlaf=com.sun.java.swing.plaf.gtk.GTKLookAndFeel -Dawt.useSystemAAFontSettings=on' +export _JAVA_AWT_WM_NONREPARENTING=1 +java -jar $HOME/.bin/sdedit-*.jar diff --git a/.bin/OLD/KAPUTT/sdedit-4.2.1.jar b/.bin/OLD/KAPUTT/sdedit-4.2.1.jar new file mode 100755 index 0000000..b4edf14 Binary files /dev/null and b/.bin/OLD/KAPUTT/sdedit-4.2.1.jar differ diff --git a/.bin/OLD/KAPUTT/select_audio b/.bin/OLD/KAPUTT/select_audio new file mode 100755 index 0000000..13f4793 --- /dev/null +++ b/.bin/OLD/KAPUTT/select_audio @@ -0,0 +1,2 @@ +#!/bin/sh + diff --git a/.bin/OLD/KAPUTT/shotwell_notify.sh b/.bin/OLD/KAPUTT/shotwell_notify.sh new file mode 100755 index 0000000..4c884b9 --- /dev/null +++ b/.bin/OLD/KAPUTT/shotwell_notify.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +while true; +do + FILES=$(ls -1 | grep -v shotwell | grep -vi xmp | grep -vi jpg | wc -l | awk '{ print $1 }') + THUMBS=$(ls -1 | grep shotwell | grep -vi "xmp\|jpg\|jpeg" | wc -l | awk '{ print $1 }') + OUT="T: $THUMBS | F: $FILES" + printf "$OUT\n" + if [ "$FILES" == "$THUMBS" ]; + then notify-send "Shotwell Import Finished: ${PWD##*/} $OUT" + printf "${PWD##*/}" | xclip -r + exit 0 + fi + sleep 5 +done diff --git a/.bin/OLD/KAPUTT/subfzf b/.bin/OLD/KAPUTT/subfzf new file mode 100755 index 0000000..8151fd8 --- /dev/null +++ b/.bin/OLD/KAPUTT/subfzf @@ -0,0 +1,28 @@ +#!/bin/sh + +subsonic() { + subsonic-cli -c /home/sdk/.subsonic-cli.conf $@ +} + +next=1 +offset=0 +until [ $next -eq 0 ] +do +_someAlbums=$(subsonic \ + -p type alphabeticalByArtist \ + -p size 500 -p offset $offset getAlbumList2 \ + | jq .albumList2.album[]) +offset=$(( offset + 500 )) +_fullAlbums="\ +$_fullAlbums +$_someAlbums +" +if [ -z "$_someAlbums" ] +then + next=0 +fi +done + + + +echo $_fullAlbums | jq diff --git a/.bin/OLD/KAPUTT/update_hosts.sh b/.bin/OLD/KAPUTT/update_hosts.sh new file mode 100755 index 0000000..2595da6 --- /dev/null +++ b/.bin/OLD/KAPUTT/update_hosts.sh @@ -0,0 +1,3 @@ +#!/bin/sh +doas curl "https://raw.githubusercontent.com/StevenBlack/hosts/master/alternates/fakenews-gambling/hosts" -o /etc/hosts +#doas curl "https://raw.githubusercontent.com/StevenBlack/hosts/master/alternates/fakenews-gambling-social/hosts" -o /etc/hosts diff --git a/.bin/OLD/KAPUTT/vidoas b/.bin/OLD/KAPUTT/vidoas new file mode 100755 index 0000000..1298d0a --- /dev/null +++ b/.bin/OLD/KAPUTT/vidoas @@ -0,0 +1,6 @@ +#!/bin/ksh +TMP=$(mktemp) +cp /etc/doas.conf $TMP +$EDITOR $TMP +doas -C $TMP && mv $TMP /etc/doas.conf; +rm -f $TMP diff --git a/.bin/OLD/UUGRN-Termine.txt b/.bin/OLD/UUGRN-Termine.txt new file mode 100644 index 0000000..d5c60eb --- /dev/null +++ b/.bin/OLD/UUGRN-Termine.txt @@ -0,0 +1,28 @@ +LOCATION FIXME: Dezernat 16, Heidelberg +LOCATION STAMMTISCH: Metropolis, Walldorf + +FIXME 07.10.2022 19:00 +FIXME 11.11.2022 19:00 statt 04.11, Grund: Raumsituation +FIXME 02.12.2022 19:00 + +FIXME 13.01.2023 19:00 statt 06.01.2023, Grund: Raumsituation +FIXME 03.02.2023 19:00 +FIXME 03.03.2023 19:00 +FIXME 14.04.2023 19:00 statt 07.04.2023, Grund: Raumsituation +FIXME 05.05.2023 19:00 +FIXME 02.06.2023 19:00 +FIXME 07.07.2023 19:00 +FIXME 04.08.2023 19:00 +FIXME 01.09.2023 19:00 +FIXME 06.10.2023 19:00 +FIXME 03.11.2023 19:00 +FIXME 01.12.2023 19:00 + +STAMMTISCH 19.12.2022 18:00 +STAMMTISCH 17.01.2023 18:00 +STAMMTISCH 20.02.2023 18:00 +STAMMTISCH 20.03.2023 18:00 +STAMMTISCH 17.04.2023 18:00 +STAMMTISCH 15.05.2023 18:00 +STAMMTISCH 19.06.2023 18:00 + diff --git a/.bin/OLD/_config b/.bin/OLD/_config new file mode 100644 index 0000000..ac3a993 --- /dev/null +++ b/.bin/OLD/_config @@ -0,0 +1,70 @@ +#!/bin/sh + +# +# PIM / DOCUMENT DIRECTORY +# + +PIMDIR="${HOME}/Documents" + +# +# COLORS +# + +BACKGROUND="#002020" + +COLOR_NB="#002020" +COLOR_NF="#008080" +COLOR_SB="#004040" +COLOR_SF="#EEEEEE" + +# +# TERMINALS +# + +STERM="st -f Terminus:pixelsize=18" +BTERM="st -f Terminus:pixelsize=26" +HTERM="st -f spleen:pixelsize=32" + +# +# DMENU +# + +DMENUOPTS="-fn Terminus:pixelsize=20 \ + -nb $COLOR_NB \ + -nf $COLOR_NF \ + -sf $COLOR_SF \ + -sb $COLOR_SB \ + -i \ + -f" + +DMENU_CMD="dmenu $DMENUOPTS" +#DMENU_CMD="rofi -dmenu" +DMENURUN_CMD="dmenu_run $DMENUOPTS" +#DMENURUN_CMD="rofi -show run" + +# +# NOTIFY +# + +NOTIFY_CMD() { + twmnc -i "${VAR##*/}" \ + -d 5000 \ + -t "$(date +%H:%M)" \ + -c "$@" +} + +# +# FUNCTIONS +# + +needs() { + pkg_info -az | grep -q ^$1$ \ + || doas pkg_add $1 +} + +# +# CONNECT TO GPG-AGENT +# + +[ -f ~/.ksh/gnupg.ksh ] \ + && . ~/.ksh/gnupg.ksh diff --git a/.bin/OLD/a.out b/.bin/OLD/a.out new file mode 100755 index 0000000..ca0263c Binary files /dev/null and b/.bin/OLD/a.out differ diff --git a/.bin/OLD/amused-monitor b/.bin/OLD/amused-monitor new file mode 100755 index 0000000..3e33648 --- /dev/null +++ b/.bin/OLD/amused-monitor @@ -0,0 +1,440 @@ +#!/usr/bin/env perl +# +# Copyright (c) 2022 Omar Polo +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +use strict; +use warnings; +use v5.12; + +use open ":std", ":encoding(UTF-8)"; +use utf8; + +use Curses; +use POSIX qw(:sys_wait_h setlocale LC_ALL); +use Text::CharWidth qw(mbswidth); +use IO::Poll qw(POLLIN); +use Time::HiRes qw(clock_gettime CLOCK_MONOTONIC); +use Getopt::Long qw(:config bundling); +use Pod::Usage; + +my $run = 1; + +my $pfile; +my $trim = ""; + +my $pair_n = 1; + +my @songs; +my $current_song; +my $playlist_cur; +my $playlist_max; +my $time_cur; +my $time_dur; +my $status; +my $mode; + +my $last_lines; + +sub round { + return int(0.5 + shift); +} + +sub max { + my ($a, $b) = @_; + return $a > $b ? $a : $b; +} + +sub excerpt { + my $lines = shift; + my @tmp; + my ($n, $idx, $cur) = (0, 0, -1); + + open (my $fh, "-|", "amused", "show", "-p"); + while (<$fh>) { + chomp; + s,$trim,,; + $tmp[$idx] = $_; + + if (m/^>/) { + $cur = $n; + $current_song = s/^> //r; + } + + $n++; + $idx = ++$idx % $lines; + + last if $cur != -1 && $n - $cur > int($lines/2) && + $#tmp == $lines-1; + } + close($fh); + + return ("Empty playlist.") unless @tmp; + + # reorder the entries + my @r; + my $len = $#tmp + 1; + $idx = $idx % $len; + for (1..$len) { + push @r, $tmp[$idx]; + $idx = ++$idx % $len; + } + return @r; +} + +sub playlist_numbers { + my ($cur, $tot, $found) = (0, 0, 0); + open (my $fh, "-|", "amused", "show", "-p"); + while (<$fh>) { + $tot++; + $cur++ unless $found; + $found = 1 if m/^>/; + } + close($fh); + return ($cur, $tot); +} + +sub status { + my ($pos, $dur, $mode); + + open (my $fh, "-|", "amused", "status", "-f", + "status,time:raw,mode:oneline"); + + <$fh> =~ m/([a-z]+) (.*)/; + my ($status, $current_song) = ($1, $2); + + while (<$fh>) { + chomp; + $pos = s/position //r if m/^position /; + $dur = s/duration //r if m/^duration /; + $mode = $_ if m/^repeat/; + } + close($fh); + return ($status, $current_song, $pos, $dur, $mode); +} + +sub showtime { + my $seconds = shift; + my $str = ""; + + if ($seconds > 3600) { + my $hours = int($seconds / 3600); + $seconds -= $hours * 3600; + $str = sprintf("%02d:", $hours); + } + + my $minutes = int($seconds / 60); + $seconds -= $minutes * 60; + $str .= sprintf "%02d:%02d", $minutes, $seconds; + return $str; +} + +sub center { + my ($str, $pstr) = @_; + my $width = mbswidth($str); + return $str if $width > $COLS; + my $pre = round(($COLS - $width) / 2); + my $lpad = $pstr x $pre; + my $rpad = $pstr x ($COLS - $width - $pre); + return ($lpad, $str, $rpad); +} + +sub offsets { + my ($y, $x, $cur, $max) = @_; + my ($pre, $c, $post) = center(" $cur / $max ", '-'); + addstring $y, $x, ""; + + my $p = COLOR_PAIR($pair_n); + + attron $p; + addstring $pre; + attroff $p; + + addstring $c; + + attron $p; + addstring $post; + attroff $p; +} + +sub progress { + my ($y, $x, $pos, $dur) = @_; + + my $pstr = showtime $pos; + my $dstr = showtime $dur; + + my $len = $COLS - length($pstr) - length($dstr) - 4; + return if $len <= 0 or $dur <= 0; + my $filled = round($pos * $len / $dur); + + addstring $y, $x, "$pstr ["; + addstring "#" x $filled; + addstring " " x max($len - $filled, 0); + addstring "] $dstr"; +} + +sub show_status { + my ($y, $x, $status) = @_; + my ($pre, $c, $post) = center($status, ' '); + addstring $y, $x, $pre; + addstring $c; + addstring $post; +} + +sub show_mode { + my ($y, $x, $mode) = @_; + my ($pre, $c, $post) = center($mode, ' '); + addstring $y, $x, $pre; + addstring $c; + addstring $post; +} + +sub render { + erase; + if ($LINES < 4 || $COLS < 20) { + addstring "window too small"; + refresh; + return; + } + + my $song_pad = ""; + my $longest = 0; + $longest = max $longest, length($_) foreach @songs; + if ($longest < $COLS) { + $song_pad = " " x (($COLS - $longest)/2); + } + + my $line = 0; + map { + attron(A_BOLD) if m/^>/; + addstring $line++, 0, $song_pad . $_; + standend; + } @songs; + + offsets $LINES - 4, 0, $playlist_cur, $playlist_max; + progress $LINES - 3, 0, $time_cur, $time_dur; + show_status $LINES - 2, 0, "$status $current_song"; + show_mode $LINES - 1, 0, $mode; + + refresh; +} + +sub getsongs { + $last_lines = $LINES; + @songs = excerpt $LINES - 4; +} + +sub getnums { + ($playlist_cur, $playlist_max) = playlist_numbers; +} + +sub save { + return unless defined $pfile; + + open(my $fh, ">", $pfile); + open(my $ph, "-|", "amused", "show", "-p"); + + print $fh $_ while (<$ph>); +} + +sub hevent { + my $fh = shift; + my $l = <$fh>; + die "monitor quit" unless defined($l); + + $status = "playing" if $l =~ m/^play/; + $status = "paused" if $l =~ m/^pause/; + $status = "stopped" if $l =~ m/^stop/; + + ($time_cur, $time_dur) = ($1, $2) if $l =~ m/^seek (\d+) (\d+)/; + + $mode = $1 if $l =~ m/^mode (.*)/; + + getnums if $l =~ m/load|jump|next|prev/; + getsongs if $l =~ m/load|jump|next|prev/; +} + +sub hinput { + my ($ch, $key) = getchar; + if (defined $key) { + if ($key == KEY_BACKSPACE) { + system "amused", "seek", "0"; + } + } elsif (defined $ch) { + if ($ch eq " ") { + system "amused", "toggle"; + } elsif ($ch eq "<" or $ch eq "p") { + system "amused", "prev"; + } elsif ($ch eq ">" or $ch eq "n") { + system "amused", "next"; + } elsif ($ch eq ",") { + system "amused", "seek", "-5"; + } elsif ($ch eq ".") { + system "amused", "seek", "+5"; + } elsif ($ch eq "S") { + system "amused show | sort -u | amused load"; + } elsif ($ch eq "R") { + system "amused show | sort -R | amused load"; + } elsif ($ch eq "s") { + save; + } elsif ($ch eq "q") { + $run = 0; + } elsif ($ch eq "\cH") { + system "amused", "seek", "0" + } + } +} + +GetOptions( + "p:s" => \$pfile, + "t:s" => \$trim, + ) or pod2usage(1); + +my $mpid = open(my $monitor, "-|", "amused", "monitor") + or die "can't spawn amused monitor"; + +setlocale(LC_ALL, ""); +initscr; +start_color; +use_default_colors; +init_pair $pair_n, 250, -1; + +timeout 1000; +scrollok 0; +curs_set 0; +keypad 1; + +my $poll = IO::Poll->new(); +$poll->mask(\*STDIN => POLLIN); +$poll->mask($monitor => POLLIN); + +if (`uname` =~ "OpenBSD") { + use OpenBSD::Pledge; + use OpenBSD::Unveil; + + my $prog = `which amused`; + chomp $prog; + + unveil($prog, 'rx') or die "unveil $prog: $!"; + if (defined($pfile)) { + unveil($pfile, 'wc') or die "unveil $pfile: $!"; + pledge qw(stdio wpath cpath tty proc exec) or die "pledge: $!"; + } else { + pledge qw(stdio tty proc exec) or die "pledge: $!"; + } +} + +getsongs; +getnums; +($status, $current_song, $time_cur, $time_dur, $mode) = status; +render; + +while ($run) { + $poll->poll(); + hinput if $poll->events(\*STDIN) & POLLIN; + hevent $monitor if $poll->events($monitor) & POLLIN; + + getsongs if $LINES != $last_lines; + + render; +} + +endwin; +save; + +kill 'INT', $mpid; +wait; + +__END__ + +=pod + +=head1 NAME + +amused-monitor - curses interface for amused(1) + +=head1 SYNOPSIS + +B [B<-p> I] [B<-t> I] + +=head1 DESCRIPTION + +amused-monitor is a simple curses interface for amused(1). + +The following options are available: + +=over 12 + +=item B<-p> I + +Save the current playling queue to the file I upon exit or +I key. + +=item B<-t> I + +Trim out the given I from every song in the playlist view. + +=back + +The following key-bindings are available: + +=over 8 + +=item backspace or C-h + +Seek back to the beginning of the track. + +=item space + +Toggle play/pause. + +=item < or p + +Play previous song. + +=item > or n + +Play next song. + +=item , + +Seek backward by five seconds. + +=item . + +Seek forward by five seconds. + +=item R + +Randomize the playlist. + +=item S + +Sort the playlist. + +=item s + +Save the status to the file given with the B<-p> flag. + +=item q + +Quit. + +=back + +=head1 SEE ALSO + +amused(1) + +=cut diff --git a/.bin/OLD/aplay b/.bin/OLD/aplay new file mode 100755 index 0000000..851655d --- /dev/null +++ b/.bin/OLD/aplay @@ -0,0 +1,27 @@ +#!/bin/sh +. ~/.bin/_config +needs amused-- + + +if [ -z "$1" ] +then + DIR="$PWD" + echo "No parameter supplied, scraping current dir: $PWD" +else + DIR="$1" +fi + +amused stop + +find "$DIR" -type f -iname "*.flac" \ + -o -iname "*.mp3" \ + -o -iname "*.ogg" \ + -o -iname "*.m4a" \ + -o -iname "*.aac" \ + -o -iname "*.wav" \ + -o -iname "*.aiff" \ + | amused load + +amused play + + diff --git a/.bin/ascii b/.bin/OLD/ascii similarity index 100% rename from .bin/ascii rename to .bin/OLD/ascii diff --git a/.bin/OLD/audiotest b/.bin/OLD/audiotest new file mode 100755 index 0000000..22ad429 --- /dev/null +++ b/.bin/OLD/audiotest @@ -0,0 +1,17 @@ +#!/bin/sh -x + +_dir="$PWD/audiotest" +mkdir "$_dir" + +for i in *.flac; +do + _tmp="$_dir/${i%%.flac}" + # create reference wav + flac -df "$i" -o "${_tmp}.wav" + # encode to 128kbit mp3 + lame --cbr -b 128 "${_tmp}.wav" "${_tmp}-128.mp3" + # encode to 320kbit mp3 + lame --cbr -b 320 "${_tmp}.wav" "${_tmp}-320.mp3" + # encode to VBR(new) Quaity 5 mp3 + lame --vbr-new -b 96 -B 320 "${_tmp}.wav" "${_tmp}-VBR96.mp3" +done diff --git a/.bin/OLD/autoencode.sh b/.bin/OLD/autoencode.sh new file mode 100755 index 0000000..f413c69 --- /dev/null +++ b/.bin/OLD/autoencode.sh @@ -0,0 +1,45 @@ +#!/bin/sh + +# This script takes not arguments + +### CONF ### + +INDIR="/encode/IN" +OUTDIR="/encode/OUT" +LOG="/encode/autoencode.log" + +# FileNameConvention: +# [

$_file

" + echo "Back to Index

" + echo "
" + echo "" + ) > .thm/$_file.html + echo "" + done + echo "" +) > index.html diff --git a/.bin/OLD/fuzz b/.bin/OLD/fuzz new file mode 100755 index 0000000..d34d751 --- /dev/null +++ b/.bin/OLD/fuzz @@ -0,0 +1,2 @@ +#!/bin/sh +find $PWD -type f -iname "*$@*" diff --git a/.bin/OLD/gdb b/.bin/OLD/gdb new file mode 120000 index 0000000..dea5d2b --- /dev/null +++ b/.bin/OLD/gdb @@ -0,0 +1 @@ +/usr/local/bin/egdb \ No newline at end of file diff --git a/.bin/gdb-get-backtrace b/.bin/OLD/gdb-get-backtrace similarity index 100% rename from .bin/gdb-get-backtrace rename to .bin/OLD/gdb-get-backtrace diff --git a/.bin/OLD/getcal.sh b/.bin/OLD/getcal.sh new file mode 100755 index 0000000..a5b9388 --- /dev/null +++ b/.bin/OLD/getcal.sh @@ -0,0 +1,7 @@ +#!/bin/sh -x +URI="https://p101-caldav.icloud.com/1365501036/calendars/B9567D7C-2A67-442A-9439-2CA147934397/" +USER="silencex@me.com" +PASS="duob-lrgt-fsns-hnmo" +BASE="$(echo -n "$USER:$PASS" | base64)" + +curl -H "Authorization: Basic $BASE" "$URI" diff --git a/.bin/OLD/goport b/.bin/OLD/goport new file mode 100755 index 0000000..0c7b93a --- /dev/null +++ b/.bin/OLD/goport @@ -0,0 +1,58 @@ +#!/bin/sh + +cd /usr/ports + +# CHECK COMMAND LINE ARGUMENT +if [ ! -z "$1" ]; then + INPUT="$1" + if [ -f "/usr/ports/$INPUT/pkg/DESCR" ]; then + DIR="$INPUT" + fi +fi + +# CHECK CLIPBOARD +if [ -z "$1" ]; then + INPUT="$(xclip -o|head -1|col -b)" + if [ -f "/usr/ports/$INPUT/pkg/DESCR" ]; then + DIR="$INPUT" + fi +fi + +# ASK USER +if [ -z "$DIR" ]; then + DIR=$(ls -1d */* mystuff/*/* \ + | egrep -v '^pobj|^distfiles|^log|^plist|^packages|CVS|Makefile|\.tgz$' \ + | fzf -e); +fi + +# Nothing selected. +[ -z "$DIR" ] && exit 0 + +# Move to chosen dir +cd "/usr/ports/$DIR" + +# Gather port details and show them +DETAILS=$(printf "%s\n\n%s\n%s\n%s\n\nCVS %s\n" \ + "/usr/ports/$DIR" \ + "Package: $(make show=FULLPKGNAME)" \ + "Maintainer: $(make show=MAINTAINER)" \ + "Homepage: $(make show=HOMEPAGE)" \ + "$(cvs log -Nl -rHEAD 2>&1 \ + | awk '{ + if ($0 ~ /^===/) p++; + if (p == 1) print $0; + if ($0 ~ /^---/) p++; + }' \ + )" \ + | fzf -e) + +# Nothing selected. +[ -z "$DETAILS" ] && exit 0 + +# Do whatever. +case "$DETAILS" in + Package*) make show=FULLPKGNAME | xclip -r; ;; + Maintainer*) make show=MAINTAINER | xclip -r; ;; + Homepage*) firefox "$(make show=HOMEPAGE)" & ;; + *) cd "$DETAILS"; port mark; ksh; ;; +esac diff --git a/.bin/OLD/gopro b/.bin/OLD/gopro new file mode 100755 index 0000000..0dbeccd --- /dev/null +++ b/.bin/OLD/gopro @@ -0,0 +1,396 @@ +#!/usr/bin/env bash + +function get-output-filename { + # takes fileinput, returns fileoutput name; takes optional $2 argument to tack onto end of name + name="$(cut -d'.' -f1 <<<"$1")" + ext="$(cut -d'.' -f2 <<<"$1")" + echo "${name}_${2}.${ext}" +} + +function timelapse() { + framerate="$1" + filename="$2" + resolution_width="$3" + resolution_height="$4" + $(type -P ls) -1tr ./*.JPG >gopro_timelapse_list.txt + mencoder -nosound -ovc x264 \ + -vf scale="$resolution_width":"$resolution_height" -mf type=jpeg:fps="$framerate" \ + mf://@gopro_timelapse_list.txt -o "$filename" + rm gopro_timelapse_list.txt +} + +function superview() { + for i in *.MP4; do + name=$(echo "$i" | cut -d'.' -f1)+S + echo "$name" + ffmpeg -i "$i" -q:a 1 -q:v 1 0 -vcodec mpeg4 -acodec ac3 -aspect 16:9 -strict experimental "$name".MP4 + done +} + +function fisheye() { + #echo "https://gopro.com/help/articles/Question_Answer/HERO4-Field-of-View-FOV-Information" + echo -ne "Resolution:\n-[0] 4:3 Wide FOV\n-[1] 4:3 Medium FOV\n-[2] 4:3 Narrow FOV\nPhoto resolution: " + read -r res + distortion_args="" + case $res in + 0*) + distortion_args="0 0 -0.3" + ;; + 1*) + distortion_args="0 0 -0.2" + ;; + 2*) + distortion_args="0 0 -0.1" + ;; + esac + if [[ $1 == "" ]]; then + for photo in *.JPG; do + timestamp=$(stat -c %y "$photo") + mogrify -distort barrel "$distortion_args" "$photo" + touch -d "$timestamp" "$photo" + done + else + timestamp=$(stat -c %y "$1") + mogrify -distort barrel "$distortion_args" "$1" + touch -d "$timestamp" "$1" + fi +} + +function fisheye_video() { + #echo "https://gopro.com/help/articles/Question_Answer/HERO4-Field-of-View-FOV-Information" + #https://gopro.com/help/articles/question_answer/HERO3-Black-Edition-Field-of-View-FOV-Information + #https://gopro.com/help/articles/Question_Answer/HERO4-Field-of-View-FOV-Information + #https://gopro.com/help/articles/Question_Answer/HERO5-Black-Field-of-View-FOV-Information + #http://www.kolor.com/wiki-en/action/view/Autopano_Video_-_Focal_length_and_field_of_view + #https://gopro.com/help/articles/question_answer/hero6-black-field-of-view-fov-information + + vfov=0 + hfov=0 + diag=0 + + echo -ne "Camera: + -[0] HERO3 + -[1] HERO4/5 + -[2] HERO6 + >> Camera: " + read -r cam + case $cam in + 0*) + echo ">> HERO3" + echo -ne "Resolution: + -[0] 4:3 Wide FOV + -[1] 4:3 Medium FOV + -[2] 4:3 Narrow FOV + -[3] 16:9 Wide FOV + -[4] 16:9 Medium FOV + -[5] 16:9 Narrow FOV + >> Video resolution: " + read -r res + case $res in + 0*) + hfov=94.4 + vfov=122.6 + diag=149.2 + ;; + 1*) + hfov=72.2 + vfov=94.4 + diag=115.7 + ;; + 2*) + hfov=49.1 + vfov=64.6 + diag=79.7 + ;; + 3*) + hfov=69.5 + vfov=118.2 + diag=133.6 + ;; + 4*) + hfov=55 + vfov=94.4 + diag=107.1 + ;; + 5*) + hfov=37.2 + vfov=64.4 + diag=73.6 + ;; + esac + ;; + 1*) + echo ">> HERO4" + echo -ne "Resolution: + -[0] 4:3 Wide FOV + -[1] 4:3 Medium FOV + -[2] 4:3 Narrow FOV + -[3] 16:9 Wide FOV + -[4] 16:9 Medium FOV + -[5] 16:9 Narrow FOV + >> Video resolution: " + read -r res + case $res in + 0*) + hfov=94.4 + vfov=122.6 + diag=149.2 + ;; + 1*) + hfov=72.2 + vfov=94.4 + diag=115.7 + ;; + 2*) + hfov=49.1 + vfov=64.6 + diag=79.7 + ;; + 3*) + hfov=69.5 + vfov=118.2 + diag=133.6 + ;; + 4*) + hfov=55 + vfov=94.4 + diag=107.1 + ;; + 5*) + hfov=37.2 + vfov=64.4 + diag=73.6 + ;; + esac + ;; + 2*) + echo ">> HERO6" + echo -ne "Resolution: + -[0] 4:3 Wide FOV ZOOM 0 + -[1] 4:3 Wide FOV ZOOM 100 + -[2] 16:9 Wide FOV ZOOM 0 + -[3] 16:9 Wide FOV ZOOM 100 + >> Video resolution: " + read -r res + case $res in + 0*) + hfov=94.4 + vfov=122.6 + diag=149.2 + ;; + 1*) + hfov=49.1 + vfov=64.6 + diag=79.7 + ;; + 2*) + hfov=69.5 + vfov=118.2 + diag=133.6 + ;; + 3*) + hfov=35.7 + vfov=62.2 + diag=70.8 + ;; + esac + ;; + esac + + flength=$(echo "$vfov/$hfov*$diag" | bc -l | head -n1 | cut -d "." -f1) + if [[ $1 == "" ]]; then + for video in *.MP4; do + name=$(echo "$video" | cut -d'.' -f1)_corrected + ffmpeg -i "$video" -vf "lenscorrection=cx=0.5:cy=0.5:k1=-0.$flength:k2=-0.022" -q:a 1 -q:v 1 -vcodec libx264 "$name".mp4 + done + else + name=$(echo "$1" | cut -d'.' -f1)_corrected + ffmpeg -i "$1" -vf "lenscorrection=cx=0.5:cy=0.5:k1=-0.$flength:k2=-0.022" -q:a 1 -q:v 1 -vcodec libx264 "$name".mp4 + fi +} + +function convert() { + if [[ $1 == "" ]]; then + for i in *.MP4; do + name=$(echo "$i" | cut -d'.' -f1) + echo "$name" + ffmpeg -i "$i" -q:a 1 -q:v 1 -vcodec mpeg4 "$name".mov + done + else + name=$(echo "$1" | cut -d'.' -f1) + echo "$name" + ffmpeg -i "$1" -q:a 1 -q:v 1 -vcodec mpeg4 "$name".mov + fi +} + +function convert-h265-to-h264 { + fileout="$(get-output-filename ${1} h264)" + ffmpeg -i "$1" -bsf:v h264_mp4toannexb -vcodec libx264 -c:a copy "$fileout" +} + +function slowmo() { + ffmpeg -i "$1" -r 25 -vf "setpts=($3/1)*PTS" -q:a 1 -q:v 1 -vcodec libx264 "$2" + echo "Video slowed down, use trim to trim the video" +} + +function speed() { + ffmpeg -i "$1" -r "$4" -vf "setpts=($3/1)*PTS" -q:a 1 -q:v 1 -vcodec libx264 "$2" + echo "finished $1" +} + +function trim() { + ffmpeg -i "$1" -ss "$3" -t "$4" -q:a 1 -q:v 1 -vcodec libx264 "$2" +} + +function merge() { + LIST_FILE="$(mktemp)" + printf "file '$PWD/%s'\n" *.MP4 > $LIST_FILE + ffmpeg -f concat -safe 0 -i $LIST_FILE -c copy "$1" + rm $LIST_FILE +} + +function rotate90deg { + fileout="$(get-output-filename ${1} rotated)" + # use 'transpose=2' for counter-clockwise + ffmpeg -i "$1" -filter:v transpose=1 -metadata:s:v rotate="" "$fileout" +} + +function stabilize() { + ffmpeg -i "$1" -vf deshake "$2" +} + +function sort() { + mkdir -p videos/{single,chaptered,thumbnails,lowresvideos} + mkdir -p photos/{single,timelapse-burst-continuous} + if [[ $1 == "move" ]]; then + mv GOPR*.MP4 videos/single + mv GP*.MP4 videos/chaptered + mv GOPR*.JPG photos/single + mv G*.JPG photos/timelapse-burst-continuous + mv ./*.LRV videos/lowresvideos + mv ./*.THM videos/thumbnails + else + cp -p GOPR*.MP4 videos/single + cp -p GP*.MP4 videos/chaptered + cp -p GOPR*.JPG photos/single + cp -p G*.JPG photos/timelapse-burst-continuous + cp -p ./*.LRV videos/lowresvideos + cp -p ./*.THM videos/thumbnails + fi + echo "Finished!" +} + +function wifiinfo() { + echo "is $(pwd) the root of your SD card?" + read -r + echo -ne "Enter current (default) wifi password: " + read -r defssid + echo -ne "Enter Wifi SSID: " + read -r wifissid + echo -ne "Enter password: " + read -r wifipassword + { + echo "$defssid" + echo "EVssidprimary,$wifissid" + echo "EVpassphrase,$wifipassword" + } >>gpauto + echo "Done. Insert SD card into the camera, remove battery, insert battery and power on twice." +} + +function update() { + curl https://raw.githubusercontent.com/KonradIT/gopro-linux/master/version + curl https://raw.githubusercontent.com/KonradIT/gopro-linux/master/gopro >/usr/bin/gopro +} + +function gif() { + convert -size "$1" ./*.JPG -delay 5 -resize "$1" "$2" +} +function proxy() { + if [[ $1 == "rename" ]]; then + mkdir lowres highres + mv ./*.MP4 highres/ + mv ./*.LRV lowres/ + for i in lowres/*.LRV; do + name=$(echo "$i" | cut -d'.' -f1) + mv "$i" "$name".MP4 + done + fi + if [[ $1 == "move" ]]; then + mv highres/*.MP4 lowres/ + fi +} + +function help() { + echo 'GoPro Tool for Linux OS +Available commands: +- gopro + >>Check for missing dependencies, e.g. ffmpeg, imagemagick and mencoder + +- gopro timelapse [fps] [outfilename] [res width] [res height] + >>Makes a timelapse with pictures in the current folder, make sure to cd to a DCIM/XXXGOPRO folder! + >>Example: gopro timelapse 30 goproTL.mp4 1920 1080 + +- gopro superview + >>Applies SuperView to all GoPro videos in the current dir + +- gopro fisheye + >>Fixes barrel distorsion to all GoPro pictures in the current folder + +- gopro fisheye_video [video] + >>Fixes barrel distorsion on GoPro videos, [video] is optional, remove to apply to all mp4 videos in current dir + >>Also needs camera name input + +- gopro convert + >>Converts all GoPro MP4 videos to MPEG4 MOV videos for easy editing + +- gopro convert-h265-to-h264 [input_video] + >>Converts videos with h.265 codecs to h.264 + >>This is useful for backwards compatibility. Some videos recorded on HERO Black 7 devices cannot be played on older hardware until codecs are converted. + +- gopro slowmo [video] + >>Reduces the speed in a High FPS GoPro Video + >>Example: gopro slowmo GOPRO0553.MP4 + +- gopro trim [input video] [output video] [HH:MM:SS start] [HH:MM:SS end] + >>Trims a video to start and end times + >>Example: gopro trim GOPR0553.MP4 Trimmed.mp4 00:05:04 00:07:43 + +- gopro merge [output_video] + >>Merges all videos present in the current folder to [output_video] + +- gopro rotate90deg [input_video] + >>Rotates video 90 degrees clockwise (edit "translate=2" argument for counter-clockwise) + +- gopro stabilize + >>Stabilizes video + >>Example: gopro GOPRO0005.MP4 Stabilized.MP4 + +- gopro sort + >>Sorts media, please execute in DCIM/XXXGOPRO + +- gopro wifiinfo + >>Sets Wifi SSID and Password for HERO5, 6, 7 cameras + +- gopro gif + >>Makes gif from images in current dir + >>Example: gopro gif 800x600 animation.gif + +- gopro proxy [option] + >>[rename] = renames .LRV to lowres/*.MP4 + >>[move] = when finish editing, moves highres/*.MP4 to lowres/ + +- gopro update + >>Updates this script + +- gopro help + >>show this usage message' +} + +echo "GoPro Tool for Linux" +echo "To see a list of commands and syntax available run: gopro help" +echo "Checking dependencies..." +hash ffmpeg 2>/dev/null || { echo >&2 "ffmpeg ..... Not installed!"; } +hash mogrify 2>/dev/null || { echo >&2 "mogrify ..... Not installed!"; } +hash mencoder 2>/dev/null || { echo >&2 "mencoder ..... Not installed!"; } +hash bc 2>/dev/null || { echo >&2 "bc ..... Not installed!"; } +"$@" diff --git a/.bin/OLD/gopro-connect-wifi b/.bin/OLD/gopro-connect-wifi new file mode 100755 index 0000000..ef3367e --- /dev/null +++ b/.bin/OLD/gopro-connect-wifi @@ -0,0 +1,2 @@ +#!/bin/ksh +doas ifconfig iwx0 nwid "GP29056772" wpakey "2>q-FGf-6sQ" diff --git a/.bin/OLD/gopro-download b/.bin/OLD/gopro-download new file mode 100755 index 0000000..0f944e0 --- /dev/null +++ b/.bin/OLD/gopro-download @@ -0,0 +1,5 @@ +#!/bin/ksh +set -xe +mkdir -p /home/sdk/gopro +cd /home/sdk/gopro +wget -c -A MP4 -r -l 1 -nd http://10.5.5.9:8080/videos/DCIM/100GOPRO diff --git a/.bin/OLD/gpg-edit b/.bin/OLD/gpg-edit new file mode 100755 index 0000000..99c6f04 --- /dev/null +++ b/.bin/OLD/gpg-edit @@ -0,0 +1,4 @@ +#!/bin/sh +set -xe +f="$(readlink -f "$1")" +vim "$f.gpg" && gpg -qd "$f.gpg" > "$f" diff --git a/.bin/OLD/hetzner-cli b/.bin/OLD/hetzner-cli new file mode 100755 index 0000000..fef648f --- /dev/null +++ b/.bin/OLD/hetzner-cli @@ -0,0 +1,158 @@ +#!/bin/sh -e + +SERVER= # set by set_server() +SERVER_NAME= # set by set_server() +ACTION= # set by set_action() +SNAPSHOT= # set by set_snapshot() +IMAGE= # set by set_image() + +show_state() { + printf "SERVER: %s\n" "$SERVER" + printf "SERVER_NAME: %s\n" "$SERVER_NAME" + printf "ACTION: %s\n" "$ACTION" + printf "SNAPSHOT: %s\n" "$SNAPSHOT" + printf "IMAGE: %s\n" "$IMAGE" + printf "\nContinue? " + read -r _c + case $_c in + [Yy]) return; ;; + *) exit 2; ;; + esac +} + +######################## +### SERVER SELECTION ### +######################## + +set_server() { + SERVER_LIST="$(hcloud server list \ + -o noheader \ + -o columns=id,name,status,ipv4,ipv6)" + SERVER="$(printf '%s\n%s' \ + "$SERVER_LIST" \ + "0 create new server" \ + | fzf --tac --exact --with-nth=2.. \ + | cut -d" " -f1 \ + )" +} + +######################## +### ACTION SELECTION ### +######################## + +# Format: key Description... +ACTION_LIST="\ +create_snap Create snapshot +delete_snap Delete snapshot +restore_snap Restore snapshot +on Turn on +off Turn off +delete_server Delete VM(!!!!) +" + +set_action() { + ACTION="$(printf '%s\n' "$ACTION_LIST" \ + | fzf --tac --exact --with-nth=2.. \ + --header="Action for Server ID ${SERVER}" \ + | cut -d" " -f1 \ + )" +} + +########################## +### SNAPSHOT SELECTION ### +########################## +# needs: SERVER + +set_snap() { + SNAPSHOT="$(hcloud image list \ + -o columns=id,description \ + -o noheader \ + -t snapshot \ + | fzf --tac --exact --with-nth=2.. \ + | cut -d" " -f1 \ + )" +} + +####################### +### IMAGE SELECTION ### +####################### + +set_image() { + IMAGE="$(hcloud image list \ + -o columns=id,description \ + -o noheader \ + -t system \ + | fzf --tac --exact --with-nth=2.. \ + | cut -d" " -f1 \ + )" +} + +######################### +### CREATE NEW SERVER ### +######################### +# needs: SERVER=0, IMAGE +create_server() { + echo NOT IMPLEMENTED +} + +##################### +### DELETE SERVER ### +##################### +# needs: SERVER=0 +delete_server() { + echo NOT IMPLEMENTED +} + +######################### +### RESTORE FROM SNAP ### +######################### +# needs: SERVER, SNAPSHOT +restore_snap() { + echo NOT IMPLEMENTED +} + +####################### +### CREATE SNAPSHOT ### +####################### +# needs: SERVER +create_snap() { + echo NOT IMPLEMENTED +} + +####################### +### DELETE SNAPSHOT ### +####################### +# needs: SERVER, SNAPSHOT + +delete_snap() { + echo NOT IMPLEMENTED +} + + + +################################ +### MAIN PROGRAM STARTS HERE ### +################################ + +# We need a server +set_server + +# In case we want a new server, the action is implicit. For all other +# cases, we ask for user input. +if [ $SERVER -eq 0 ]; then + ACTION=create_server +else + set_action +fi + +# Now we evaluate the action and execute the next steps +case $ACTION in + delete_snap) set_snap; delete_snap; ;; + restore_snap) set_snap; restore_snap; ;; + create_snap) create_snap; ;; + create_server) create_server; ;; + delete_server) delete_server; ;; + console) hcloud server request-console ${SERVER}; ;; + turn*on) hcloud server poweron ${SERVER}; exit 0; ;; + turn*off) hcloud server poweroff ${SERVER}; exit 0; ;; +esac diff --git a/.bin/hlsvideo.sh b/.bin/OLD/hlsvideo.sh similarity index 100% rename from .bin/hlsvideo.sh rename to .bin/OLD/hlsvideo.sh diff --git a/.bin/hostwatch b/.bin/OLD/hostwatch similarity index 100% rename from .bin/hostwatch rename to .bin/OLD/hostwatch diff --git a/.bin/hpaste b/.bin/OLD/hpaste similarity index 100% rename from .bin/hpaste rename to .bin/OLD/hpaste diff --git a/.bin/OLD/ifonly b/.bin/OLD/ifonly new file mode 100755 index 0000000..f40af2e --- /dev/null +++ b/.bin/OLD/ifonly @@ -0,0 +1,11 @@ +#!/bin/sh + +only=$1 + +for if in $(ifconfig | grep "^[a-z]" | cut -d":" -f1 | grep -Ev "lo0|enc0|pflog0") +do + doas ifconfig $if down + doas ifconfig $if -inet + doas ifconfig $if -inet6 +done +doas ifconfig $only inet autoconf up diff --git a/.bin/OLD/image-handler b/.bin/OLD/image-handler new file mode 100755 index 0000000..01ec948 --- /dev/null +++ b/.bin/OLD/image-handler @@ -0,0 +1,92 @@ +#!/bin/sh +# C-x + ?-? + +set -x + +copy_to_clipboard() { + printf '%s\n' "Clipping $1" + printf '%s' "$(readlink -f "$1")" \ + | xclip -selection clipboard +} + +upload_to_paste() { + printf '%s\n' "Pasting $1" + scp "$1" sdk@codevoid.de:/home/www/htdocs/gopher/p/ + printf '%s' "https://codevoid.de/I/p/${1##*/}" \ + | xclip -selection clipboard +} + +save_image() { + if [ -z "$SXIVDIR" ] + then + . $HOME/.bin/_config + SXIVDIR="$(find . -type d -maxdepth 1 | dmenu -p "Save" $DMENUOPTS)" + export SXIVDIR; + fi + printf '%s\n' "Saving $1 to $SXIVDIR/" + mkdir -p "$SXIVDIR" + mv "$1" "$SXIVDIR/" + + base="${1%.*}" + for type in cr2 CR2 orf ORF dng DNG tif TIF xmp XMP + do + test -f "${base}.${type}" && mv "${base}.${type}" "$SXIVDIR/" + done +} + +edit_image() { + base=${1%.*} + for type in cr2 CR2 orf ORF dng DNG + do + printf "Trying %s.%s\n" "${base}" "${type}" + if [ -f "${base}.${type}" ] + then + rawtherapee "${base}.${type}" + break + fi + done + for type in tif TIF + do + printf "Trying %s.%s\n" "${base}" "${type}" + if [ -f "${base}.${type}" ] + then + gimp "${base}.${type}" + break + fi + done +} + +rotate_cw() { + printf '%s\n' "Rotating CW" + convert -rotate 90 "$1" "$1" +} + +rotate_ccw() { + printf '%s\n' "Rotating CCW" + convert -rotate 270 "$1" "$1" +} + +show_details() { + echo "$1" + exiftool "$1" | grep Date | tr ':' '-' + read +} + +_options="Exit +Edit Image +Copy Image Path +Rotate CW +Rotate CCW +Upload to Website +Show Dates" + +_sel=$(echo "$_options" | fzf -e) + +case "$_sel" in + Edit*) edit_image "$1" ;; + Copy*) copy_to_clipboard "$1" ;; + Show*) show_details "$1" ;; + Upload*) website-add-image-to-gallery "$1" ;; + "Rotate CW") rotate_cw "$1" ;; + "Rotate CCW") rotate_ccw "$1" ;; +esac diff --git a/.bin/OLD/image_daterename.sh b/.bin/OLD/image_daterename.sh new file mode 100755 index 0000000..11b80aa --- /dev/null +++ b/.bin/OLD/image_daterename.sh @@ -0,0 +1,49 @@ +#!/bin/sh + +NAME="$(basename "$1")" +EXT="$(echo ${NAME##*.} | tr '[:upper:]' '[:lower:]')" +DIR="$(dirname "$1")" + +# san +SED0="$(echo "$NAME" | sed -n "/^20[0-9]\{2\}-[0-9]\{2\}-[0-9]\{2\}_[0-9]\{2\}-[0-9]\{2\}-[0-9]\{2\}-[a-z]\{3\}\.$EXT/p")" +if [ ! -z "$SED0" ] +then + echo "Skipping - matches name pattern already ($NAME)" + exit 0 +fi + +EXIFDATES="$(exiftool -q -q \ + -p '$modifyDate' \ + -p '$createDate' \ + -p '$dateTimeOriginal' \ + -p '$FileModifyDate' \ + "$1" \ + | grep "^20" \ + | cut -b 1-19 \ + | tr ':' '-' \ + | tr ' ' '_' \ + )" + +SED1="$(echo "$NAME" | sed -n 's/.*\(20[0-9]\{2\}\)-\([0-9]\{2\}\)-\([0-9]\{2\}\)_\([0-9]\{2\}\)-\([0-9]\{2\}\)-\([0-9]\{2\}\).*/\1-\2-\3_\4-\5-\6/p')" +SED2="$(echo "$NAME" | sed -n 's/.*\(20[0-9]\{2\}\)\([0-9]\{2\}\)\([0-9]\{2\}\)_\([0-9]\{2\}\)\([0-9]\{2\}\)\([0-9]\{2\}\).*/\1-\2-\3_\4-\5-\6/p')" +SED3="$(echo "$NAME" | sed -n 's/.*\(20[0-9]\{2\}\)\([0-9]\{2\}\)\([0-9]\{2\}\)\([0-9]\{2\}\)\([0-9]\{2\}\)\([0-9]\{2\}\).*/\1-\2-\3_\4-\5-\6/p')" + +PICK="$(for d in $EXIFDATES $SED1 $SED2 $SED3; do echo $d; done | sort -u | head -1)" + +echo "Dates for: $1" + +for e in $EXIFDATES +do echo "From EXIF: " $e; done + +for f in $SED1 $SED2 $SED3 +do echo "From Filename: " $f; done + +if [ -z "$PICK" ] +then + echo "Skipping - no dates found" +else + NEWNAME="$DIR/$PICK-$(pwgen -A -0 -1 3).$EXT" + echo mv "$1" "$NEWNAME" + mv "$1" "$NEWNAME" +fi +echo diff --git a/.bin/OLD/imagecompare b/.bin/OLD/imagecompare new file mode 100755 index 0000000..a9e2403 --- /dev/null +++ b/.bin/OLD/imagecompare @@ -0,0 +1,31 @@ +#!/bin/sh +set -e +c=0 +find . -mindepth 1 -maxdepth 1 -type f \ + | grep '....-..-.._' \ + | cut -b 1-19 \ + | sort -u \ + | while read line +do + things="$(findimagedupes -t 95% -- $line*)" + [ -z "$things" ] && continue + c=$(( c + 1 )) + ls -1l $things \ + | awk '{ print $5" "$9 }' \ + | sort -nr \ + | cut -d" " -f2- \ + | while read thing + do + mkdir -p set-$c + if [ -z "$PICK" ] + then + PICK=$thing + echo pick set-$c/1-$(basename $PICK) + mv $PICK set-$c/1-$(basename $PICK) + else + echo discard set-$c/2-$(basename $thing) + mv $thing set-$c/2-$(basename $thing) + fi + done + PICK= +done diff --git a/.bin/OLD/imagedate2filename.sh b/.bin/OLD/imagedate2filename.sh new file mode 100755 index 0000000..e5d5c43 --- /dev/null +++ b/.bin/OLD/imagedate2filename.sh @@ -0,0 +1,71 @@ +#!/bin/sh +# +# usage: +# find $somedir -type f -exec imagedate2filename.sh {} \; + +NAME="$(basename "$1")" +EXT="$(echo ${NAME##*.} | tr '[:upper:]' '[:lower:]')" +DIR="$(dirname "$1")" + +[ "$EXT" == "jpeg" ] && EXT=jpg + +# don't fiddle with file names that look right already +SED0="$(echo "$NAME" | sed -n "/^[12][09][90-4][0-9]-[0-1][0-9]-[0-3][0-9]_[0-5][0-9]-[0-5][0-9]-[0-5][0-9]-[a-z]\{3\}\.$EXT/p")" +if [ ! -z "$SED0" ] +then + echo "Skipping - matches name pattern already ($NAME)" + exit 0 +fi + +# find dates in exif data +EXIFDATES="$(exiftool -q -q \ + -p '$modifyDate' \ + -p '$createDate' \ + -p '$dateTimeOriginal' \ + -p '$FileModifyDate' \ + "$1" \ + | cut -b 1-19 \ + | grep "^20" \ + | tr '_' '0' \ + | tr ':' '-' \ + | tr ' ' '_' \ + )" + +# find dates in the filename +# yyyy-mm-dd_hh-mm-ss +SED1="$(echo "$NAME" | sed -n 's/.*\([12][09][90-4][0-9]\)-\([0-1][0-9]\)-\([0-3][0-9]\)_\([0-5][0-9]\)-\([0-5][0-9]\)-\([0-5][0-9]\).*/\1-\2-\3_\4-\5-\6/p')" +# yyyymmdd_hhmmss +SED2="$(echo "$NAME" | sed -n 's/.*\([12][09][90-4][0-9]\)\([0-1][0-9]\)\([0-3][0-9]\)_\([0-5][0-9]\)\([0-5][0-9]\)\([0-5][0-9]\).*/\1-\2-\3_\4-\5-\6/p')" +# yyyymmddhhmmss +SED3="$(echo "$NAME" | sed -n 's/.*\([12][09][90-4][0-9]\)\([0-1][0-9]\)\([0-3][0-9]\)\([0-5][0-9]\)\([0-5][0-9]\)\([0-5][0-9]\).*/\1-\2-\3_\4-\5-\6/p')" + +# yyyy-mm-dd_hh.mm.ss +SED4="$(echo "$NAME" | sed -n 's/.*\([12][09][90-4][0-9]\)-\([0-1][0-9]\)-\([0-3][0-9]\)_\([0-5][0-9]\)\.\([0-5][0-9]\)\.\([0-5][0-9]\).*/\1-\2-\3_\4-\5-\6/p')" + +# yyyy-mm-dd hh.mm.ss +SED5="$(echo "$NAME" | sed -n 's/.*\([12][09][90-4][0-9]\)-\([0-1][0-9]\)-\([0-3][0-9]\) \([0-5][0-9]\)\.\([0-5][0-9]\)\.\([0-5][0-9]\).*/\1-\2-\3_\4-\5-\6/p')" + +# yyyy-mm dd_hh-mm-ss +SED6="$(echo "$NAME" | sed -n 's/.*\([12][09][90-4][0-9]\)-\([0-1][0-9]\)-\([0-3][0-9]\) \([0-5][0-9]\)-\([0-5][0-9]\)-\([0-5][0-9]\).*/\1-\2-\3_\4-\5-\6/p')" + +# pick the oldest one +PICK="$(for d in $EXIFDATES $SED1 $SED2 $SED3 $SED4 $SED5 $SED6; do echo $d; done | sort -u | head -1)" + +# put info on screen and rename +echo "Dates for: $1" + +for e in $EXIFDATES +do echo "From EXIF: " $e; done + +for f in $SED1 $SED2 $SED3 $SED4 $SED5 $SED6 +do echo "From Filename: " $f; done + +if [ -z "$PICK" ] +then + echo "Skipping - no dates found" +else + NEWNAME="$DIR/$PICK-$(pwgen -A -0 -1 3).$EXT" + echo mv "$1" "$NEWNAME" + mv "$1" "$NEWNAME" +fi +echo diff --git a/.bin/OLD/imagesort b/.bin/OLD/imagesort new file mode 100755 index 0000000..b4ddfcd --- /dev/null +++ b/.bin/OLD/imagesort @@ -0,0 +1,12 @@ +#!/bin/sh + +find ${@:-.} -mindepth 1 \ + -maxdepth 1 \ + -type f \( -iname "*.jpg" \ + -o -iname "*.jpeg" \ + -o -iname "*.png" \ + -o -iname "*.tif" \ + -o -iname "*.gif" \ + -o -iname "*.heic" \ + -o -iname "*.dng" \ + \) | sort | nsxiv -ati diff --git a/.bin/OLD/imagesort_bg b/.bin/OLD/imagesort_bg new file mode 100755 index 0000000..501f57e --- /dev/null +++ b/.bin/OLD/imagesort_bg @@ -0,0 +1,21 @@ +#!/bin/sh + +ncpu=$(sysctl -n hw.ncpuonline) +temp=$(mktemp -d) + +find ${@:-.} -maxdepth 1 -type f \( -iname "*.jpg" \ + -o -iname "*.jpeg" \ + -o -iname "*.png" \ + -o -iname "*.gif" \ + -o -iname "*.heic" \ + -o -iname "*.tif" \ + \) | sort -R > $temp/filelist.txt + +count=$(( $(wc -l < $temp/filelist.txt) / ncpu )) + +( cd $temp && split -l $count $temp/filelist.txt ) + +for f in $temp/x* +do + nsxiv -ati < $f & +done diff --git a/.bin/OLD/imageview b/.bin/OLD/imageview new file mode 100755 index 0000000..93f5591 --- /dev/null +++ b/.bin/OLD/imageview @@ -0,0 +1,2 @@ +#!/bin/sh +nsxiv -at $@ diff --git a/.bin/OLD/imap-listmailboxes b/.bin/OLD/imap-listmailboxes new file mode 100755 index 0000000..e64bf12 --- /dev/null +++ b/.bin/OLD/imap-listmailboxes @@ -0,0 +1,6 @@ +#!/bin/sh + +print "t1 login sdk $(pass Internet/mail.codevoid.de | head -1)\nt1 list \"\" \"*\"\nt1 logout" \ + | openssl s_client -quiet -connect mail.codevoid.de:993 -crlf - 2>/dev/null \ + | grep "^\* LIST" | awk '{ print $NF }' | sort + diff --git a/.bin/OLD/imgview b/.bin/OLD/imgview new file mode 100755 index 0000000..e8a1b76 --- /dev/null +++ b/.bin/OLD/imgview @@ -0,0 +1,112 @@ +#!/bin/sh + +# Description: Open hovered or current directory in image viewer. +# Generates media thumbnails with optional dependencies. +# +# Dependencies: +# - imv (https://github.com/eXeC64/imv) or, +# - sxiv (https://github.com/muennich/sxiv) or, +# - ucollage (https://github.com/ckardaris/ucollage) or, +# - lsix (https://github.com/hackerb9/lsix), or +# - viu (https://github.com/atanunq/viu), or +# - catimg (https://github.com/posva/catimg), or +# - optional: ffmpeg for audio thumbnails (album art) +# - optional: ffmpegthumbnailer for video thumbnails +# +# Shell: POSIX compliant +# Author: Arun Prakash Jana, Luuk van Baal +# +# Consider setting NNN_PREVIEWDIR to $XDG_CACHE_HOME/nnn/previews +# if you want to keep media thumbnails on disk between reboots. +set -x + +NNN_PREVIEWDIR="${NNN_PREVIEWDIR:-${TMPDIR:-/tmp}/nnn/previews}" + +exit_prompt() { + set -x + [ -n "$1" ] && printf "%s\n" "$1" + printf "%s" "Press any key to exit..." + cfg=$(stty -g); stty raw -echo; head -c 1; stty "$cfg" + clear + exit +} + +make_thumbs() { + set -x + mkdir -p "$NNN_PREVIEWDIR$dir" || return + if [ "$1" -eq 3 ]; then + [ -d "$target" ] && exit_prompt "$2 can only display a single image" + mime="$(file -bL --mime-type -- "$target")" + case "$mime" in + audio/*) ffmpeg -i "$target" "$NNN_PREVIEWDIR$target.jpg" -y >/dev/null 2>&1 + ret="$NNN_PREVIEWDIR/$target.jpg" ;; + video/*) ffmpegthumbnailer -i "$target" -o "$NNN_PREVIEWDIR$target.jpg" 2> /dev/null + ret="$NNN_PREVIEWDIR/$target.jpg" ;; + *) ret="$target" ;; + esac + fi + for file in "$dir"/*; do + if [ ! -f "$NNN_PREVIEWDIR$file.jpg" ]; then + case "$(file -bL --mime-type -- "$file")" in + audio/*) [ "$1" -ne 0 ] && ffmpeg -i "$file" "$NNN_PREVIEWDIR$file.jpg" -y >/dev/null 2>&1 ;; + video/*) [ "$1" -ne 1 ] && ffmpegthumbnailer -i "$file" -o "$NNN_PREVIEWDIR$file.jpg" 2> /dev/null ;; + esac + fi + done + for file in "$NNN_PREVIEWDIR$dir"/*; do + filename="$(basename "$file" .jpg)" + [ ! -e "$dir/$filename" ] && rm "$file" 2>/dev/null + done +} + +listimages() { + set -x + find -L "$dir" "$NNN_PREVIEWDIR$dir" -maxdepth 1 -type f -print0 2>/dev/null +} + +view_files() { + set -x + [ -f "$target" ] && count="-n $(listimages | grep -a -m 1 -ZznF "$target" | cut -d: -f1)" + case "$1" in + sxiv) listimages | xargs -0 sxiv -a "${count:--t}" -- ;; + imv*) listimages | xargs -0 "$1" "${count:-}" -- ;; + esac +} + +target="$(readlink -f "$1")" +[ -d "$target" ] && dir="$target" || dir="${target%/*}" +if uname | grep -q "Darwin"; then + [ -f "$1" ] && open "$1" >/dev/null 2>&1 & +elif type lsix >/dev/null 2>&1; then + if [ -d "$target" ]; then + cd "$target" || exit_prompt + fi + make_thumbs "" + clear + lsix + cd "$NNN_PREVIEWDIR$dir" && lsix + exit_prompt +elif type ucollage >/dev/null 2>&1; then + type ffmpeg >/dev/null 2>&1 && make_thumbs 1 + UCOLLAGE_EXPAND_DIRS=1 ucollage "$dir" "$NNN_PREVIEWDIR$dir" || exit_prompt +elif type sxiv >/dev/null 2>&1; then + type ffmpegthumbnailer >/dev/null 2>&1 && make_thumbs 0 + view_files sxiv +elif type imv >/dev/null 2>&1; then + make_thumbs "" + view_files imv >/dev/null 2>&1 & +elif type imvr >/dev/null 2>&1; then + make_thumbs "" + view_files imvr >/dev/null 2>&1 & +elif type viu >/dev/null 2>&1; then + clear + make_thumbs 3 viu + viu -n "$ret" + exit_prompt +elif type catimg >/dev/null 2>&1; then + make_thumbs 3 catimg + catimg "$ret" + exit_prompt +else + exit_prompt "Please install sxiv/imv/viu/catimg/lsix." +fi diff --git a/.bin/OLD/ksh-update-completions b/.bin/OLD/ksh-update-completions new file mode 100755 index 0000000..33a9207 --- /dev/null +++ b/.bin/OLD/ksh-update-completions @@ -0,0 +1,33 @@ +#!/bin/ksh + +rm -f "${HOME}/.ksh/complete.ksh" + +add() { ( printf '%s %s' "$1" "$2" | tr '\n' ' '; printf '\n') >> "${HOME}/.ksh/complete.ksh"; } + +if [ -d ~/.password-store ]; then + ARGS="$(cd ~/.password-store && ls -1d */* | sed 's/\.gpg$//g;s/ /\\ /g')" + add "set -A complete_pass -- change edit insert show rm cp mv search find " "$ARGS" +fi + +if [ -f ${HOME}/.ssh/config ]; then + add "set -A complete_ssh -- " "$(awk '/^Host .*/ { print $2 }' ${HOME}/.ssh/config)" +fi + +add "set -A complete_kill_1 -- " "-9 -HUP -INFO -KILL -TERM" +add "set -A complete_ifconfig_1 -- " "$(ifconfig | grep ^[a-z] | cut -d: -f1)" +add "set -A complete_amused_1 -- " "add flush jump load monitor next pause play prev repeat restart show status stop toggle" +add "set -A complete_got_1 -- " "$(got -h 2>&1 | sed -n s/commands://p)" + +add "set -A complete_make_1 -- " "$(sh ~/.ksh/complete.portvars)" + +ARGS="reload restart stop start disable enable ls" +add "set -A complete_rcctl_1 -- " "$ARGS" +add "set -A complete_rcctl_2 -- " "$(rcctl ls all)" +add "set -A complete_got_1 -- " "$(got -h 2>&1 | sed -n s/commands://p)" +add "set -A complete_xdl_1 -- " "$(cd ~/x && ls -d *)" +add "set -A complete_ytdl_1 -- " "$(cd ~/Videos/YouTube && ls -d *)" + + +add "set -A complete_catgirl -- " "$(cd ~/.config/catgirl && ls *)" + +add "set -A complete_man -- " "port-modules bsd.port.mk ports packages dpb make ffmpeg-complete mpv cabal-module cargo-module go-module gnome-module python-module qmake-module ruby-module cargo" diff --git a/.bin/list-myfiles b/.bin/OLD/list-myfiles similarity index 100% rename from .bin/list-myfiles rename to .bin/OLD/list-myfiles diff --git a/.bin/listincludes.pl b/.bin/OLD/listincludes.pl similarity index 100% rename from .bin/listincludes.pl rename to .bin/OLD/listincludes.pl diff --git a/.bin/OLD/lmms b/.bin/OLD/lmms new file mode 100755 index 0000000..767ad61 --- /dev/null +++ b/.bin/OLD/lmms @@ -0,0 +1,3 @@ +#!/bin/sh +export QT_AUTO_SCREEN_SCALE_FACTOR=1 +/usr/local/bin/lmms diff --git a/.bin/OLD/lsblog b/.bin/OLD/lsblog new file mode 100755 index 0000000..53be218 --- /dev/null +++ b/.bin/OLD/lsblog @@ -0,0 +1,8 @@ +#!/bin/sh +. $HOME/.bin/_config + +printf "Blog Index:\n" +ssh $USER@$DOMAIN "find $LOCAL_PATH/posts -type f -maxdepth 1 \ + -exec printf '{}|' \; -exec head -1 '{}' \; \ + | sed 's,.*/,,'| sort | column -s'|' -t " + diff --git a/.bin/lspaste b/.bin/OLD/lspaste similarity index 100% rename from .bin/lspaste rename to .bin/OLD/lspaste diff --git a/.bin/OLD/luajit b/.bin/OLD/luajit new file mode 120000 index 0000000..832df8a --- /dev/null +++ b/.bin/OLD/luajit @@ -0,0 +1 @@ +/usr/local/bin/luajit51 \ No newline at end of file diff --git a/.bin/OLD/mail-offline-update b/.bin/OLD/mail-offline-update new file mode 100755 index 0000000..f8a484b --- /dev/null +++ b/.bin/OLD/mail-offline-update @@ -0,0 +1,3 @@ +#!/bin/sh +mbsync -a +mu index diff --git a/.bin/OLD/make1 b/.bin/OLD/make1 new file mode 100755 index 0000000..1e1854d --- /dev/null +++ b/.bin/OLD/make1 @@ -0,0 +1,2 @@ +#!/bin/sh +MAKE_JOBS=1 make $@ diff --git a/.bin/OLD/mcat b/.bin/OLD/mcat new file mode 100755 index 0000000..0312562 --- /dev/null +++ b/.bin/OLD/mcat @@ -0,0 +1,12 @@ +#!/bin/sh + +for foo in in $@ +do + case $foo in + *.gz) zcat $foo; ;; + *.tgz) zcat $foo; ;; + *.bz2) bzcat $foo; ;; + *.tbz2) bzcat $foo; ;; + *) cat $foo; ;; + esac +done diff --git a/.bin/OLD/media-ccc-list-update.1 b/.bin/OLD/media-ccc-list-update.1 new file mode 100755 index 0000000..234b2fd --- /dev/null +++ b/.bin/OLD/media-ccc-list-update.1 @@ -0,0 +1,27 @@ +#!/bin/sh + +rm -f ~/.cache/media.ccc.list + +curl -s \ + -H "CONTENT-TYPE: application/json" \ + https://media.ccc.de/public/conferences \ + | jq -rc '.[][].url' \ + | while read conference +do + echo "+ Scraping ${conference##*/}" + curl -s \ + -H "CONTENT-TYPE: application/json" \ + "$conference" \ + | jq -rc '.events[].url' \ + | while read event + do + echo "| Event: ${event##*/}" + curl -s \ + -H "CONTENT-TYPE: application/json" \ + "$event" \ + | jq -rc '.recordings[].recording_url' \ + | fgrep '/webm-hd/' \ + >> ~/.cache/media.ccc.list + + done +done diff --git a/.bin/OLD/metamixer b/.bin/OLD/metamixer new file mode 100755 index 0000000..adc9baf --- /dev/null +++ b/.bin/OLD/metamixer @@ -0,0 +1,54 @@ +#!/bin/sh + +# add your volume and mute attributes here (mixerctl -af /dev/mixer?) +_volumelist="outputs.master outputs.play" +_mutelist="outputs.master.mute outputs.play_mute" + +[ -z $1 ] && print "$0 [volume]" && exit 2 + +_mute() { + # $1 = device + # $2 = on/off + for _entry in $_mutelist; + do + if mixerctl -f $1 2>&1 | cut -d"=" -f1 | grep -q $_entry; + then + print "$1: $_entry => $2" + mixerctl -qf $1 $_entry=$2 + fi + done +} + +_vol() { + # $1 = device + # $2 = volume + for _entry in $_volumelist; + do + if mixerctl -f $1 2>&1 | cut -d"=" -f1 | grep -q $_entry; + then + print "$1: $_entry => $2" + mixerctl -qf $1 $_entry=$2 + fi + done +} + +for _mixdev in /dev/mixer*; +do + # do not follow symlinks (eg. /dev/mixer) + [ -h $_mixdev ] && continue + + # if volume is 0 set volume and mute + # if volume is >0 set volume and unmute + if [ "$1" == "0" ]; then + _mute $_mixdev on + _vol $_mixdev 0 + elif [ "$1" -gt "0" ] && [ "$1" -lt "1001" ]; then + _mute $_mixdev off + _vol $_mixdev $1 + else + print "Use number between 0 and 1000" + exit 1 + fi +done + +printf "VOL\n" >> /tmp/lemonbar.fifo diff --git a/.bin/OLD/mictest b/.bin/OLD/mictest new file mode 100755 index 0000000..cf84142 --- /dev/null +++ b/.bin/OLD/mictest @@ -0,0 +1,10 @@ +#!/bin/sh +echo recording +aucat -o /tmp/test.wav & +PID=$! +sleep 3 +kill $PID +sleep 0.2 +echo playing +aucat -i /tmp/test.wav +echo done diff --git a/.bin/OLD/migrate-varbase.sh b/.bin/OLD/migrate-varbase.sh new file mode 100755 index 0000000..7f5ec9b --- /dev/null +++ b/.bin/OLD/migrate-varbase.sh @@ -0,0 +1,35 @@ +#!/bin/sh +echo "Changing all VARBASE to LOCALSTATEDIR" +find . ! -path "*/CVS/*" -type f ! -name "*.orig" -exec sed -i "s/VARBASE/LOCALSTATEDIR/g" "{}" \; + +echo "List LOCALSTATEDIR lines:" +fgrep -r LOCALSTATEDIR . + +echo "Show CVS diff" +cvs diff . + +make show=MAINTAINER + +echo -n "Bump? " +read +case $REPLY in + [yY]) portbump; ;; +esac + +echo -n "Testbuild? " +read +case $REPLY in + [yY]) make clean=all; make -j 12 fetch; make package; portcheck; ;; +esac + +echo -n "Portcheck? " +read +case $REPLY in + [yY]) portcheck; ;; +esac + +echo -n "make port-lib-depends-check? " +read +case $REPLY in + [yY]) make port-lib-depends-check; ;; +esac diff --git a/.bin/OLD/mkHLS.sh b/.bin/OLD/mkHLS.sh new file mode 100755 index 0000000..bf09276 --- /dev/null +++ b/.bin/OLD/mkHLS.sh @@ -0,0 +1,40 @@ +#!/bin/sh + +FILE="$1" +NAME="${1%%.*}" +EXT="${1##*.}" + +ffmpeg -i "$FILE" \ + -map 0:v:0 -map 0:a:0 \ + -map 0:v:0 -map 0:a:0 \ + -map 0:v:0 -map 0:a:0 \ + -map 0:v:0 -map 0:a:0 \ + -c:v libx264 -crf 22 -c:a aac -ar 44100 \ + -filter:v:0 scale=w=480:h=360 -maxrate:v:0 600k -b:a:0 500k \ + -filter:v:1 scale=w=640:h=480 -maxrate:v:1 1500k -b:a:1 1000k \ + -filter:v:2 scale=w=1280:h=720 -maxrate:v:2 3000k -b:a:2 2000k \ + -filter:v:2 scale=w=1920:h=1080 -maxrate:v:3 6000k -b:a:3 4000k \ + -var_stream_map \ + "v:0,a:0,name:360p v:1,a:1,name:480p v:2,a:2,name:720p v:3,a:3,name:1080p" \ + -preset veryfast \ + -hls_list_size 10 \ + -threads 0 \ + -f hls \ + -hls_time 3 \ + -hls_flags independent_segments \ + -master_pl_name "$NAME.m3u8" \ + -y "$NAME-%v.m3u8" + +ffmpegthumbnailer -i "${NAME}.mp4" -s 720 -o "${NAME}.jpg" + +cat < test.html + + + +EOF diff --git a/.bin/OLD/mkTerminCalendar.sh b/.bin/OLD/mkTerminCalendar.sh new file mode 100644 index 0000000..6092cbf --- /dev/null +++ b/.bin/OLD/mkTerminCalendar.sh @@ -0,0 +1,27 @@ +#!/bin/sh + +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//ZContent.net//Zap Calendar 1.0//EN +CALSCALE:GREGORIAN +METHOD:PUBLISH +BEGIN:VEVENT +SUMMARY:Abraham Lincoln +UID:c7614cff-3549-4a00-9152-d25cc1fe077d +SEQUENCE:0 +STATUS:CONFIRMED +TRANSP:TRANSPARENT +RRULE:FREQ=YEARLY;INTERVAL=1;BYMONTH=2;BYMONTHDAY=12 +DTSTART:20080212 +DTEND:20080213 +DTSTAMP:20150421T141403 +CATEGORIES:U.S. Presidents,Civil War People +LOCATION:Hodgenville\, Kentucky +GEO:37.5739497;-85.7399606 +DESCRIPTION:Born February 12\, 1809\nSixteenth President (1861-1865)\n\n\n + \nhttp://AmericanHistoryCalendar.com +URL:http://americanhistorycalendar.com/peoplecalendar/1,328-abraham-lincol + n +END:VEVENT +END:VCALENDAR + diff --git a/.bin/OLD/mkpatch b/.bin/OLD/mkpatch new file mode 100755 index 0000000..052fcb2 --- /dev/null +++ b/.bin/OLD/mkpatch @@ -0,0 +1,20 @@ +#!/bin/sh + +if [ -f Makefile ] +then + _name="$(make show=PKGNAME)" + _epoch="$(make show=EPOCH)" + _rev="$(make show=REVISION)" + _patchname="${_name}${_epoch:+v$_epoch}${_rev:+p$_rev}" +else + _patchname="unnamed_diff_$(date +%Y%m%d_%H%M%S)" +fi +set -x +if [ -d CVS ] +then + doas cvs -d sdk@cvs.openbsd.org:/cvs diff -uNp . > /home/sdk/diffs/${_patchname}.diff +else + doas git diff -U --no-prefix --cached . > /home/sdk/diffs/${_patchname}.diff +fi +set +x +doas chmod 666 /home/sdk/diffs/${_patchname}.diff diff --git a/.bin/OLD/mkpicindex-static.sh b/.bin/OLD/mkpicindex-static.sh new file mode 100755 index 0000000..f1bc8c5 --- /dev/null +++ b/.bin/OLD/mkpicindex-static.sh @@ -0,0 +1,249 @@ +#!/bin/sh + +printf '%s' \ +'/*! + * mkpicindex.sh - v0.1 + * https://codevoid.de + * Copyright (c) 2019 Stefan Hagen + * Licensed under the ISC license. + */ +' > LICENSE + +# DEPENDENCIES +# - ImageMagic (identify, convert) +# - raw only: jhead +# - raw only: dcraw + +# LIMITATIONS +# - leftover images on the last row won't be added +# - the thumbnail cache is not cleaned automaticall + + +# CONFIGURE +TITLE="My Gallery" # browser title +WIDTH=1000 # how wide will the gallery be +ROW_HEIGHT=180 # how high will the justified rows be? +THUMB_QUALITY=83 # quality for thumbnails +THUMB_PATH="thm" # relative path to thumbnail folder +THUMB_PADDING="6" # image padding + +# TECHNICAL STUFF +DEBUG=0 # debug output +PROCS=8 + +# PRINT HELP / USAGE TEXT +usage() { + printf '%s\n' \ +'mkpicindex - Version: $Id$ + +Usage: mkpicindex [arguments] > file.html + +Arguments: + -t "My Gallery" Gallery title + -w 850 Gallery main area width + -h 180 Row height (thumbnail size) + -q 83 Thumbnail quality + -b 6 Thumbnail border (padding) + -p 8 Max. parallel conversion processes + -d Enable debug mode (verbose output) + -h Usage (this text) +' + exit 2 +} + +# OVERIDE DEFAULTS +while getopts 't:w:h:b:q:p:d' c +do + case $c in + t) TITLE="$OPTARG" ;; + w) WIDTH="$OPTARG" ;; + h) ROW_HEIGHT="$OPTARG" ;; + q) QUALITY="$OPTARG" ;; + b) THUMB_PADDING="$OPTARG" ;; + p) PROCS="$OPTARG" ;; + d) DEBUG=1 ;; + ?|*) usage; ;; + esac +done + +# PRINT USAGE IF OUTPUT IS NOT REDIRECTED +[ "$DEBUG" != 1 ] && test -t 1 && usage; + +# GLOBAL TMP VARIABLES +G_ROW_WIDTH=0 # combined pic width < WIDTH @ ROW_HEIGHT +G_ROW_FILES="" # pipe separated files < WIDTH +MORE=1 # trigger next loop + +# CREATE THUMBNAIL DIRECTORY +mkdir -p "$THUMB_PATH" + +# OUTPUT HELPER +debug() { [ "$DEBUG" == "1" ] && printf '%s\n' "Debug: $1" >&2; } +console() { printf '%s\n' "$1" >&2; } + +# CALCULATE BY ASPECT RATIO +get_width_by_height() { + # returns aspect ratio calculated width + local F="$1" # image file + local TH="$2" # target height + local R="$(identify -format ' %w %h ' "$1" | awk -vTH=$TH \ + '{ printf("%.0f", TH*($1/$2)) }')" + printf '%.0f' "$R" + debug "get_width_by_height: FILE=$F TARGET_HEIGHT=$TH RET_WIDTH=$R" +} + +# TOO MANY CONVERT PROCSSES => WAIT +thread_check() { + while [ $(pgrep convert | wc -l | awk '{ print $1 }') -gt $(($PROCS-1)) ]; + do debug "Process Limit ($PROCS) reached. Waiting..."; sleep 2; done +} + +# EXTACT CAMERA IMAGE FROM RAW +convert_raw() { + # XXX dcraw may export a PPM file. + F="$1" # raw image + if ! [ -f "${F%%.*}_preview.jpg" ]; then + dcraw -e -c "$F" > "${F%%.*}_preview.jpg" + jhead -q -autorot "${F%%.*}_preview.jpg" + console "Raw Conversion: ${F%%.*}_preview.jpg" + fi +} + +# CREATE THUMBNAIL +create_thumb() { + local F="$1" # original + local W="$2" # width + local H="$3" # height + local T="${F%%.*}-$H" + if [ -f "$THUMB_PATH/$T.gif" ]; + then printf '%s' "$THUMB_PATH/$T.gif" + elif [ -f "$THUMB_PATH/$T.jpeg" ]; + then printf '%s' "$THUMB_PATH/$T.jpeg" + else + thread_check + case $(printf '%s' "${F##*.}" | tr '[:upper:]' '[:lower:]') in + gif) console "Creating Thumbnail: $THUMB_PATH/$T.gif" + nohup convert -quality $THUMB_QUALITY -sharpen 2x2 \ + -coalesce -resize 6000x$H\> \ + -deconstruct "$F" \ + "$THUMB_PATH/$T.gif" >/dev/null 2>&1 & + printf '%s' "$THUMB_PATH/$T.gif" ;; + *) console "Creating Thumbnail: $THUMB_PATH/$T.jpeg" + nohup convert -quality $THUMB_QUALITY -sharpen 2x2 \ + -auto-orient -resize 6000x$H\> "$F" \ + "$THUMB_PATH/$T.jpeg" >/dev/null 2>&1 & + printf '%s' "$THUMB_PATH/$T.jpeg" ;; + esac + fi +} + +# ADD IMAGE LOOP +add_image() { + local F="$1" # image file + # How wide would the image be when we rescale it to $ROW_HEIGHT? + local NW=$(get_width_by_height "$F" "$ROW_HEIGHT") + debug "add_image: FILE=$F NW=${NW}x$ROW_HEIGHT" + + # We add images and their width to $G_ROW_WIDTH until $WIDTH will + # be exceeded. + if [ "$(( $G_ROW_WIDTH + $NW ))" -gt "$WIDTH" ]; then + + debug "add_image: max width reached with F=$F @ $G_ROW_WIDTH" + + # we're building a row now + printf "
\n"; + + # calculate how much we need to stretch images to fill the + # whole row. + local RFH=$(printf "$G_ROW_WIDTH $WIDTH $ROW_HEIGHT" \ + | awk '{ printf("%.0f",$3*($2/$1)) }') + debug "RFH=$RFH" + + # loop through the images in this row and recalculate + # them with their new, real height. + local IFS='|'; for RF in $G_ROW_FILES; + do + local RFW=$(($(get_width_by_height "$RF" "$RFH") - 2*$THUMB_PADDING)) + debug "add_image: adding file: F=$RF with W=$RFW H=$RFH" + + local T=$(create_thumb "$RF" "$RFW" "$RFH") + debug "add_image: created thumbnail $T" + + # output HTML for image + console "Adding Image: $RF" + printf '
\n' + printf ' \n' + printf ' \n' + printf ' \n' + printf '
\n' + done + + # we're done with this row now. + printf "
\n"; + + # set leftover file as for next iteration + G_ROW_WIDTH="$NW" + G_ROW_FILES="$F|" + else + # add more items... + debug "add_image: width has not been reached, continue loop." + G_ROW_WIDTH="$(( $G_ROW_WIDTH + $NW ))" + G_ROW_FILES="$F|$G_ROW_FILES" + fi +} + +# HEADER +printf '%s\n' \ +' + + + '"$TITLE"' + + + +
+' +### MAIN LOOP ########################################################## +for F in *.*; +do + if [ -f "$F" ]; + then + case "$(printf '%s' ${F##*.} | tr '[:upper:]' '[:lower:]')" in + jpg|jpeg|png|gif|svg) add_image "$F" ;; + cr2|dng|nef|CR2) convert_raw "$F" && \ + add_image "${F%%.*}_preview.jpg" ;; + *) console "Ignoring: $F" ;; + esac + fi +done +### MAIN LOOP END ###################################################### + +# FOOTER +printf '%s\n' \ +'
+ +' diff --git a/.bin/OLD/mkpicindex.sh b/.bin/OLD/mkpicindex.sh new file mode 100755 index 0000000..2db61d4 --- /dev/null +++ b/.bin/OLD/mkpicindex.sh @@ -0,0 +1,793 @@ +#!/bin/sh + +printf '%s' \ +'/*! + * mkpicindex.sh - v0.1 + * https://codevoid.de + * Copyright (c) 2019 Stefan Hagen + * Licensed under the ISC license. + * + * style.css, justify.js: + * justifiedGallery - v4.0.0-alpha + * http://miromannino.github.io/Justified-Gallery/ + * Copyright (c) 2019 Miro Mannino + * Licensed under the MIT license. + */ +' > LICENSE + +# CONFIGURE +GALLERY_TITLE="My Gallery" # browser title +GALLERY_ROW_HEIGHT=150 # how high will the justified rows be? +GALLERY_RANDOMIZE=false # enable random sorting (true,false) +BODY_STYLE="color:orange; background:black;" # +THUMBNAIL_QUALITY=83 # quality for thumbnails +THUMBNAIL_PATH="thm" # relative path to thumbnail folder +INCLUDE_HEADER="HEADER" # file with html to include before gallery +INCLUDE_FOOTER="FOOTER" # file with html to include after gallery + +### ZE PROGAM STARTZ HERE ############################################## +cleanup() { + # DELETE BROKEN IMAGES + printf '%s\n' "Removing incomplete thumbnails." >&2 + find $THUMBNAIL_PATH -name "*_tmp.*" -exec rm -v "{}" \; + exit 1 +} +trap cleanup 1 2 3 6 + +# CREATE THUMBNAIL DIRECTORY +mkdir -p $THUMBNAIL_PATH + +# INCLUDE CUSTOM HEADER & FOOTER +FOOTER=$([ -f $INCLUDE_FOOTER ] && cat $INCLUDE_FOOTER | sed 's/^/ /g') +HEADER=$([ -f $INCLUDE_HEADER ] && cat $INCLUDE_HEADER | sed 's/^/ /g') + +# PRINT HEADER +printf '%s%s%s%s%s\n' \ +' + + '"$GALLERY_TITLE"' + + + + + +' "$HEADER"' +
' + + +# RESCALE AND ADD IMAGE +# PARAM 1: original +# 2: thumbnail_basename +# 3: thumbnail_format (extension) +add_image() { + local FILE="$1" + local THUMB="$THUMBNAIL_PATH/$2-$GALLERY_ROW_HEIGHT" + local EXT="$3" + printf '%s\n' "Adding image: $FILE" >&2 + if ! [ -f "$THUMB.$EXT" ] && [ "$FILE" != "$THUMB.$EXT" ]; + then convert -quality $THUMBNAIL_QUALITY -sharpen 2x2 \ + -coalesce -resize 6000x$GALLERY_ROW_HEIGHT\> \ + -deconstruct "$FILE" "${THUMB}_tmp.$EXT" && \ + mv "${THUMB}_tmp.$EXT" "$THUMB.$EXT" + fi + local WH="$(identify -format ' %w %h ' "$THUMB.$EXT" \ + | awk '{ print "width="$1" height="$2 }')" + printf ' %s\n' "" + printf ' %s\n' "" + printf ' %s\n' '' +} + +### MAIN LOOP ########################################################## + +for file in *.*; +do + if [ -f "$file" ]; + then + case $(printf '%s' ${file##*.} | tr '[:upper:]' '[:lower:]') in + jpg|jpeg|png) + add_image "$file" "${file%%.*}" "jpeg" ;; + gif) + add_image "$file" "${file%%.*}" "gif" ;; + *) printf '%s\n' "Ignoring: $file" >&2 ;; + esac + fi +done + +### MAIN LOOP END ###################################################### + +# PRINT FOOTER +printf '%s%s\n' \ +"
+ +" "$FOOTER + +" + +### ASSETS (style.css, justify.js) ##################################### +printf '%s' ' +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 +' | base64 -d | gunzip > justify.js + + +printf '%s' ' +H4sICOujrl0AA3N0eWxlLmNzcwDVVk1vnDAQve+vmCaqlEQ1y6abJiVKLz1UrZJb/oABA5MY +G9lmN5sq/73GfKzYBUKORVotY7/xzDyPH15efFrABTyV2mCCLP5FOWdqBwQ2a8/3fEJ5kdEK +khlTBMtljkrmVAgU0kvRZGXooVz+af1Js8Cycvkpi53CNDNwFp3Dpb/6Dg/WHR5q/wpyjxET +msVQipgpMBmDh9+PwOthz0KWC6/LjqRNen8XAFuMTRbAyvc/31qzkBoNShGAYpwa3LBqVG6Y +SrjcBpBhHDNxu3gbWu8H0C/D4zFuRmYSTEvFXCr72DTUkpfGxY5RF5zuAkDBUTASchk9DycF +sLyAkEbPqZKWiQBOb9xzC48SMrphkCq6A7tcxDLJLVUathly5hhrc0INXNIYRWrJMRlsKZrH +rMxDQZHrezsFd5BQrllFK9gKuGEqgBO3yWeyoBGa3d3KPz9xadZ2AL63quycqhRtjb6jm8ZV +IGeNUWp/mKfjxE7ON/ROQejMINOYLtA0rJrVm+lA4/NdkHEInRlkGtOrxsIm+tPIIoCr+vRw +lpjOGN1ogFCquGoZIYVbY6SFjjposkm8iBZVepNlvwPq6m5xrvDuCLb5DjMRSmNkfljwVfHi +JrtjSSLJpS321HfPnjf36pSuee8x2HjZ81pHS6QwROMrs+J1WcdwQ1tWr/C1XtqNJTRHbvPX +VGiimcJkFpPtP9mgxpCzWczOdDpi+tCvzzwKSzjlE81yfaw315VtCQmf0RCjbPHNrjUY26l+ +roFRzQg6/SS5fJ2JlPNwM0AjO+E9pYQJo3Y9RkbV9rD8Vb/r2uadHWxKxYbQ07o35DEuP2Pr +t0r0MRL+6w6oS7VXmwEhGnPTBQph70Hjot2TqlpmSC1C5HJdi0knYCu/eAG/+TtS+Y9txf7O +0h3o94qwu15QcagG/avQ/O9Hd+G7qavMGrVszE5xYe2KXk+J9/5LRpS9L5U6gG8V/m3xD0Dc +I3kQCwAA +' | base64 -d | gunzip > style.css diff --git a/.bin/OLD/mkport b/.bin/OLD/mkport new file mode 100755 index 0000000..2c5843a --- /dev/null +++ b/.bin/OLD/mkport @@ -0,0 +1,254 @@ +#!/usr/bin/env perl + +# ISC LICENSE +# Copyright Stefan Hagen + +# usage: ./mkport thing thing thing > Makefile +# ./mkport -h +# +# "thing" is something you want in the port. It can be a module, distfile +# provider or build tool. +# +# The script is far from complete. I'm just adding constraints and +# support for key words along the way. +# +# The script runs top down and builds up constraints (for example no +# MASTER_SITES when GH_* is present. And prefills WANTLIB and *_DEPENDS +# based on modules it knows. +# +# The idea is to create a sensible default Makefile to start with. +# That means I won't add all variables for a given module. Just the ones +# that are most likely needed. +# +# DONE +# lua cmake qmake cpan qt5 qt6 python +# +# TODO +# erlang gnome gnu gnustep intltool java +# +# SKIPPED (rare use) +# apache-module asterisk-sounds fortran gcc4 clang heimdal imake qt4 +# +# UNSURE (or unknown) +# dconf font gconf2 +# +# USE PORTGEN +# go ruby perl +# +# MAYBE PORTGEN IN FUTURE? +# cabal cargo +# +# DIDN'T LOOK AT THOSE YET +# kde-applications kf5 mariadb meson mono mozilla ocaml pear pecl php +# postgresql scons tcl tk xfce4 + +use strict; +use warnings; +use File::Basename; + +my %arg = map {$_ => 1} @ARGV; + +# USAGE +if(exists $arg{"-h"}) { + print "Usage: ".basename($0)." thing thing thing > Makefile\n"; + print "Things: "; + open(my $f, '<', "$0") or die $!; + my @lines = sort grep s/^exists \$arg\{"([^_]\w+)"\}.*/$1/g, <$f>; + @lines = do { my %s; grep { !$s{$_}++ } @lines }; + while(my $l=shift(@lines)) { chomp($l); print "$l "; } + print "\n"; + exit(0); +} + +# DEFAULTS +$arg{"_distname"} = "\${V}"; +$arg{"_maintainer"} = 'Stefan Hagen '; +$arg{"_license"} = "LICENSE"; +$arg{"_mastersites"} = ""; +$arg{"_makeflags"} = ""; +$arg{"_testflags"} = ""; +$arg{"_wantlib"} = []; +$arg{"_libdepends"} = []; +$arg{"_rundepends"} = []; +$arg{"_builddepends"} = []; +$arg{"_testdepends"} = []; +$arg{"_configstyle"} = ""; + +sub addlist { + push(@{$arg{$_[0]}}, ( $_[1] )); +} + +sub printlist { + print "$_[0]".join(' ', sort @{$arg{$_[1]}})."\n\n" +} + +# CONSTRAINTS +if(exists $arg{"github"}) { + delete $arg{"_distname"}; + delete $arg{"_mastersites"}; +} +if(exists $arg{"cpan"}) { + delete $arg{"_mastersites"}; + delete $arg{"_makeflags"}; + delete $arg{"_testflags"}; + delete $arg{"_wantlib"}; + delete $arg{"_libdepends"}; + $arg{"_license"} = "Perl"; + $arg{"_configstyle"} = "modinst"; +} +if(exists $arg{"autoconf"}) { + $arg{"_configstyle"} = "autoconf"; +} +if(exists $arg{"nobuild"}) { + delete $arg{"_wantlib"}; + delete $arg{"_builddepends"}; + delete $arg{"_configstyle"}; + delete $arg{"_makeflags"}; +} + +# COMMENT +print "COMMENT =\t\n\n"; + +# PORT INFO +print "V =\t\t\n"; +exists $arg{"github"} + and print "GH_ACCOUNT =\t\n" + and print "GH_PROJECT =\t\n" + and print "GH_TAGNAME =\t\${V}\t\n" + and print "\#GH_COMMIT =\t\n"; +exists $arg{"cpan"} + and print "PKG_ARCH =\t*\n"; +exists $arg{"_distname"} + and print "DISTNAME =\t\${V}\n" + and print "\#PKGNAME =\t\${DISTNAME}-\${V}\n"; +exists $arg{"github"} + and print "\#PKGNAME =\t\${GH_PROJECT}-\${V}\n"; + +print "\nCATEGORIES =\t\n\n"; + +# HOMEPAGE +print "HOMEPAGE =\t\n\n"; + +# MAINTAINER +exists $arg{"_maintainer"} + and print "MAINTAINER =\t", $arg{'_maintainer'}, "\n\n"; +exists $arg{"cpan"} + and print "CPAN_AUTHOR =\t\n\n"; + +# LICENSE +exists $arg{"_license"} + and print "\# $arg{'_license'}\n"; +print "PERMIT_PACKAGE =\tYes\n\n"; + +# MASTER_SITES +exists $arg{"_mastersites"} + and print "MASTER_SITES =\t\n" + and print "\#EXTRACT_SUFX =\t\n\n"; + +# MODULES +exists $arg{"cmake"} and $arg{"_modules"} .= "devel/cmake "; +exists $arg{"lua"} and $arg{"_modules"} .= "devel/lua "; +exists $arg{"qmake"} and $arg{"_modules"} .= "devel/qmake "; +exists $arg{"qt5"} and $arg{"_modules"} .= "x11/qt5 "; +exists $arg{"qt6"} and $arg{"_modules"} .= "x11/qt6 "; +exists $arg{"python"} and $arg{"_modules"} .= "lang/python "; +exists $arg{"ruby"} and $arg{"_modules"} .= "lang/ruby "; +exists $arg{"tk"} and $arg{"_modules"} .= "x11/tk "; +exists $arg{"gnome"} and $arg{"_modules"} .= "gnome "; +exists $arg{"perl"} and $arg{"_modules"} .= "perl "; +exists $arg{"cpan"} and $arg{"_modules"} .= "cpan "; +exists $arg{"php"} and $arg{"_modules"} .= "php "; +exists $arg{"fortran"} and $arg{"_modules"} .= "fortran "; +exists $arg{"cabal"} and $arg{"_modules"} .= "devel/cabal "; +exists $arg{"cargo"} and $arg{"_modules"} .= "devel/cargo "; +exists $arg{"java"} and $arg{"_modules"} .= "java "; +exists $arg{"_modules"} + and print "MODULES =\t$arg{'_modules'}\n"; + +# MOD* +exists $arg{"qt5"} + and print "\#MODQT5_DEPS =\t\n" + and print "\#MODQT5USE_CXX11 = No\t\n"; +exists $arg{"qt6"} + and print "\#MODQT6_DEPS =\t\n" + and print "\#MODQT6USE_CXX11 = No\t\n"; +exists $arg{"lua"} + and print "MODLUA_VERSION =\t\${MODLUA_DEFAULT_VERSION}\n"; +exists $arg{"python"} + and print "MODPI_VERSION =\t\${MODPY_DEFAULT_VERSION}\n"; +exists $arg{"qmake"} + and print "\#MODQMAKEPROJECTS =\t\n"; +exists $arg{"qmake"} + and print "\#MODQMAKEARGS =\t\n"; +exists $arg{"_modules"} + and print "\n"; + +# WANTLIB +exists $arg{"lua"} + and addlist("_wantlib","\${MODLUA_WANTLIB}"); +exists $arg{"python"} + and addlist("_wantlib","\${MODPY_WANTLIB}"); +exists $arg{"cmake"} + and addlist("_wantlib","\${COMPILER_LIBCXX}"); + +exists $arg{"_wantlib"} + and print "\# ?uses pledge()?\n" + and printlist("WANTLIB =\t","_wantlib"); + +# LIB_DEPENDS +exists $arg{"lua"} + and addlist("_libdepends", "\${MODLUA_LIB_DEPENDS}"); +exists $arg{"python"} + and addlist("_libdepends", "\${MODPY_LIB_DEPENDS}"); + +exists $arg{"_libdepends"} + and printlist("LIB_DEPENDS =\t", "_libdepends"); + +# RUN_DEPENDS +exists $arg{"_rundepends"} + and printlist("RUN_DEPENDS =\t", "_rundepends"); + +# BUILD_DEPENDS +exists $arg{"cpan"} + and addlist("_builddepends", "\${RUN_DEPENDS}"); +exists $arg{"autoconf"} + and addlist("_builddepends", "\${MODGNU_AUTOCONF_DEPENDS}") + and addlist("_builddepends", "\${MODGNU_AUTOMAKE_DEPENDS}") + and addlist("_builddepends", "devel/libtool"); +exists $arg{"_builddepends"} + and printlist("BUILD_DEPENDS =\t", "_builddepends"); + +# TEST_DEPENDS +exists $arg{"_testflags"} + and printlist("\#TEST_DEPENDS =\t", "_testdepends"); + +# COMPILER +exists $arg{"gcc"} + and print "COMPILER=\tbase-clang ports-gcc\n\n"; + +# CONFIGURE +exists $arg{"autoconf"} + and print "\#AUTOCONF_VERSION =\t?.??\n" + and print "\#AUTOMAKE_VERSION =\t?.??\n\n"; +exists $arg{"_configstyle"} + and print "\#CONFIGURE_STYLE =\t", $arg{'_configstyle'}, "\n\n"; + +# FLAGS +exists $arg{"_makeflags"} + and print "\#MAKE_FLAGS =\t\n\n"; + +exists $arg{"nobuild"} + and print "NO_BUILD =\tYes\n\n"; + +# USE FLAGS +exists $arg{"gmake"} + and print "USE_GMAKE =\tYes\n\n"; + +# TESTS +exists $arg{"_testflags"} + and print "\#NO_TEST =\tYes\n" + and print "\#TEST_TARGET =\t\n\n"; +exists $arg{"cpan"} + and print "\#MODCPAN_EXAMPLES =\tYes\n\n"; + +print ".include \n"; diff --git a/.bin/OLD/mkvm b/.bin/OLD/mkvm new file mode 100755 index 0000000..37f2cd2 --- /dev/null +++ b/.bin/OLD/mkvm @@ -0,0 +1,15 @@ +#!/bin/sh -xe + +_dir="$HOME/qemu" +_disk="obsd69.qcow2" +_media="install69.iso" +_size="20G" +_arch="x86_64" + +mkdir -p "$_dir" +rm -f bsd.rd +wget -c "http://192.168.1.20/pub/OpenBSD/snapshots/amd64/bsd.rd" \ + || echo "Install Media not found online" +qemu-img create -f qcow2 ${_dir}/${_disk} ${_size} +qemu-system-${_arch} -m 512M -boot order=nc -device e1000 -net nic -net user,tftp=${_dir},tftp-server-name=192.168.1.20,bootfile=pxeboot -hda ${_dir}/${_disk} + diff --git a/.bin/motd.sh b/.bin/OLD/motd.sh similarity index 100% rename from .bin/motd.sh rename to .bin/OLD/motd.sh diff --git a/.bin/OLD/mount_iso b/.bin/OLD/mount_iso new file mode 100755 index 0000000..61553ff --- /dev/null +++ b/.bin/OLD/mount_iso @@ -0,0 +1,3 @@ +#!/bin/sh +doas vnconfig -v vnd0 $1 +doas mount -v -t cd9660 /dev/vnd0c /mnt diff --git a/.bin/OLD/move-to-corner b/.bin/OLD/move-to-corner new file mode 100755 index 0000000..f1ebf84 --- /dev/null +++ b/.bin/OLD/move-to-corner @@ -0,0 +1,2 @@ +#!/bin/sh +wmctrl -r :ACTIVE: -e 0,1150,70,720,400 diff --git a/.bin/OLD/mplay b/.bin/OLD/mplay new file mode 100755 index 0000000..adc3479 --- /dev/null +++ b/.bin/OLD/mplay @@ -0,0 +1,4 @@ +#!/bin/sh +THING="$(xclip -o)" +echo "$THING" >> /tmp/thing.txt +mpv "$THING" diff --git a/.bin/OLD/mpva b/.bin/OLD/mpva new file mode 100755 index 0000000..d7c355b --- /dev/null +++ b/.bin/OLD/mpva @@ -0,0 +1,4 @@ +#!/bin/sh +/usr/local/bin/mpv --no-video --force-window=no "$@" + + diff --git a/.bin/OLD/multissh.sh b/.bin/OLD/multissh.sh new file mode 100755 index 0000000..2b259a5 --- /dev/null +++ b/.bin/OLD/multissh.sh @@ -0,0 +1,7 @@ +#!/bin/sh -x + +S="git.codevoid.de dns.codevoid.de honk.codevoid.de jabber.codevoid.de shell.codevoid.de gopher.codevoid.de mail.codevoid.de irc.uugrn.org fossil.codevoid.de" + +for srv in $S; do + ssh -tt $srv "$@"; +done diff --git a/.bin/mutt-find b/.bin/OLD/mutt-find similarity index 100% rename from .bin/mutt-find rename to .bin/OLD/mutt-find diff --git a/.bin/OLD/mycatgirl b/.bin/OLD/mycatgirl new file mode 100755 index 0000000..74a2e97 --- /dev/null +++ b/.bin/OLD/mycatgirl @@ -0,0 +1,17 @@ +#!/bin/sh + +[ -z "$1" ] \ + && return 2 + +/usr/local/bin/catgirl \ + -N notify-send \ + -O nnn.sh \ + -C xcopy \ + -i "* [JPQ][OAU][IR][NT]" \ + -l \ + -h shell.codevoid.de \ + -p 40004 \ + -r x \ + -u sdk \ + -n sdk \ + -w "sdk@$(hostname -s)/${1}:$(pass Internet/znc)" diff --git a/.bin/OLD/mysuspend b/.bin/OLD/mysuspend new file mode 100755 index 0000000..c17e3db --- /dev/null +++ b/.bin/OLD/mysuspend @@ -0,0 +1,4 @@ +#!/bin/sh +echo "Attempt to suspend at $(/bin/date)" >> /tmp/suspend +/usr/sbin/zzz +echo "Resuming from suspend at $(/bin/date)" >> /tmp/suspend diff --git a/.bin/netrestart b/.bin/OLD/netrestart similarity index 100% rename from .bin/netrestart rename to .bin/OLD/netrestart diff --git a/.bin/OLD/network b/.bin/OLD/network new file mode 100755 index 0000000..e9299bf --- /dev/null +++ b/.bin/OLD/network @@ -0,0 +1,47 @@ +#!/bin/sh + +if_cmd() { + doas ifconfig $@ +} + +destroy_interface() { + if_cmd $1 > /dev/null 2>&1 + [ $? -eq 0 ] && ( doas ifconfig $1 down \ + && doas ifconfig $1 destroy ) +} + +destroy_all() { + destroy_interface iwx0 + destroy_interface re0 + destroy_interface ure0 +} + +setup_wifi() { + destroy_interface re0 + destroy_interface ure0 + destroy_interface iwx0 + doas route -n flush + if_cmd iwx0 -joinlist + if_cmd iwx0 join DiscMate wpakey GeekConnection23 + if_cmd iwx0 inet autoconf + if_cmd iwx0 inet6 autoconf + if_cmd iwx0 up +} + +setup_eth() { + destroy_interface re0 + destroy_interface ure0 + destroy_interface iwx0 + doas route -n flush + if_cmd $1 inet autoconf + if_cmd $1 inet6 autoconf + if_cmd $1 up +} + +case $1 in + wifi) setup_wifi; ;; + re) setup_eth re0; ;; + ure) setup_eth ure0; ;; +esac + + diff --git a/.bin/OLD/next.sh b/.bin/OLD/next.sh new file mode 100755 index 0000000..5324c7e --- /dev/null +++ b/.bin/OLD/next.sh @@ -0,0 +1,25 @@ +#!/bin/sh + +# $1 = 2013-11-08 + +date_in=2013-11-08 +len=28 + +len_s=$(( 28 * 24 * 60 * 60 )) + +# convert to ts +date_s_in=$(date -jf %Y-%m-%d +%s $date_in) + +# add len +date_s_out1=$(( date_s_in + len_s )) +date_s_out2=$(( date_s_out1 + len_s )) +date_s_out3=$(( date_s_out2 + len_s )) + +date_out1=$(date -jf %s +%Y-%m-%d $date_s_out1) +date_out2=$(date -jf %s +%Y-%m-%d $date_s_out2) +date_out3=$(date -jf %s +%Y-%m-%d $date_s_out3) + +echo "$date_in + $len days = $date_out1" +echo "$date_out1 + $len days = $date_out2" +echo "$date_out2 + $len days = $date_out3" + diff --git a/.bin/OLD/nget b/.bin/OLD/nget new file mode 100755 index 0000000..a77c508 --- /dev/null +++ b/.bin/OLD/nget @@ -0,0 +1,14 @@ +#!/bin/sh + +param="$@" + +if [ -z "$param" ]; +then + echo "nget " + exit 2 +fi + +# web resource +# dl youtube with yt-dlp +# dl image with ftp +# dl diff --git a/.bin/OLD/nnn-preview b/.bin/OLD/nnn-preview new file mode 100755 index 0000000..06285a2 --- /dev/null +++ b/.bin/OLD/nnn-preview @@ -0,0 +1,17 @@ +#!/bin/sh + +trap cleanup 1 2 3 6 9 11 +cleanup() { + kill $PID 2>/dev/null + exit +} + +test -p "${NNN_FIFO}" || exit 1 + +while read line + kill $PID 2> /dev/null + wait + nsxiv -N tabbed $line & + PID=$! +do +done < "${NNN_FIFO}" diff --git a/.bin/OLD/nrg2iso b/.bin/OLD/nrg2iso new file mode 100755 index 0000000..da753a9 Binary files /dev/null and b/.bin/OLD/nrg2iso differ diff --git a/.bin/OLD/nterm b/.bin/OLD/nterm new file mode 100755 index 0000000..752ea7e --- /dev/null +++ b/.bin/OLD/nterm @@ -0,0 +1,12 @@ +#!/bin/sh +. $HOME/.bin/_config + +RES=$(xrandr | grep "*+" | awk '{print $1}') +RESH=${RES%x*} +RESV=${RES#*x} + +GAP=$(( RESH / 12 )) +H=$(( RESH - 2 * GAP )) +V=$(( RESV - 2 * GAP )) + +$NTERM -c nterm $@ diff --git a/.bin/obsd-route b/.bin/OLD/obsd-route similarity index 100% rename from .bin/obsd-route rename to .bin/OLD/obsd-route diff --git a/.bin/obsd-vm b/.bin/OLD/obsd-vm similarity index 100% rename from .bin/obsd-vm rename to .bin/OLD/obsd-vm diff --git a/.bin/OLD/od b/.bin/OLD/od new file mode 100755 index 0000000..b7f01fc --- /dev/null +++ b/.bin/OLD/od @@ -0,0 +1,3 @@ +#!/bin/sh +set -x +objdump -p $(which $1) diff --git a/.bin/OLD/oi.sh b/.bin/OLD/oi.sh new file mode 100644 index 0000000..69450d0 --- /dev/null +++ b/.bin/OLD/oi.sh @@ -0,0 +1,17 @@ +#!/bin/sh +doas pkill dhclient +print connecting wifi +doas ifconfig iwm0 nwid "E-M5MKIII-P-BJ9A11068" wpakey 18927072 +print press key when wifi is connected +read +doas ifconfig iwm0 inet 192.168.0.9 +sleep 1 + +mkdir $HOME/Olympus +cd $HOME/Olympus +for file in $(curl http://192.168.0.10/get_imglist.cgi?DIR=%2FDCIM%2F100OLYMP | cut -d"," -f1,2 | sed 's/,/\//g'); +do + wget -nc http://192.168.0.10$file +done + + diff --git a/.bin/OLD/open.sh b/.bin/OLD/open.sh new file mode 100755 index 0000000..64cd2a3 --- /dev/null +++ b/.bin/OLD/open.sh @@ -0,0 +1,74 @@ +#!/bin/ksh + +if [ -z "$1" ]; +then + print "Parameter missing." + exit 2 +fi + +################################################### +# URLS +################################################### + +if print "$1" | egrep -qi '^http[s]{0,1}://'; +then + case "$1" in + *.mkv) mpv "$1"; ;; + *.mp4) mpv "$1"; ;; + *.webm) mpv "$1"; ;; + *) sacc "$1"; ;; + esac + ${BROWSER:=firefox} "$1" + exit 0 +fi + +################################################### +# REAL FILES +################################################### + +if [ ! -f "$1" ]; +then + print "Parameter is not a file." + exit 1 +fi + +################################################### +# BY EXTENSION +################################################### + +EXT="$(print "${1##*.}" | tr '[:upper:]' '[:lower:]')" + +case "$EXT" in + docx) libreoffice "$1"; ;; + xlsx) libreoffice "$1"; ;; + txt) vim "$1"; ;; + out) kdump -RTf "$1" | less; ;; + *) unset EXT; ;; +esac + +if [ ! -z "$EXT" ]; +then + exit 0; +fi + +################################################### +# BY MIME TYPE +################################################### + +case "$(file -ib "$1")" in + # full qualified + application/ogg) ogg123 "$1"; ;; + application/pdf) zathura "$1"; ;; + application/postscript) zathura "$1"; ;; + application/vnd.oasis.opendocument.*) libreoffice "$1"; ;; + audio/mpeg) mpg123 "$1"; ;; + audio/midi) timidity "$1"; ;; + # wildcards + audio/*) mpv "$1"; ;; + video/*) mpv "$1"; ;; + image/*) sxiv "$1"; ;; + # can't handle + application/octet-stream) print "Sorry, can't handle: $1"; ;; + # vim can handle a lot! + *) vim "$1"; ;; +esac diff --git a/.bin/OLD/openbsd_benchmark.sh b/.bin/OLD/openbsd_benchmark.sh new file mode 100755 index 0000000..4915da6 --- /dev/null +++ b/.bin/OLD/openbsd_benchmark.sh @@ -0,0 +1,6 @@ +#!/bin/sh + +GLXINFO="$(glxinfo)" + +# xenotic +XENOTIC_FPS=$(xonotic-sdl -benchmark demos/the-big-keybench 2>&1 | grep "one-second fps" | awk '{ printf("%.0f\n",$5) }' ) diff --git a/.bin/OLD/openbsd_kernel.sh b/.bin/OLD/openbsd_kernel.sh new file mode 100755 index 0000000..ccddcf6 --- /dev/null +++ b/.bin/OLD/openbsd_kernel.sh @@ -0,0 +1,24 @@ +#!/bin/sh + +export DEBUG=-g +export DEBUG_FLAGS=-g + +if [ $1 = "compile" ]; then + cd /usr/src/sys/arch/amd64/conf + if [ ! -f MYKERNEL ]; then + cp GENERIC.MP MYKERNEL + fi + \config MYKERNEL + cd /sys/arch/amd64/compile/MYKERNEL + make +fi + +if [ $1 = "install" ]; then + cd /sys/arch/amd64/compile/MYKERNEL + make install +fi + +if [ $1 = "clean" ]; then + cd /sys/arch/amd64/compile/MYKERNEL + make clean +fi diff --git a/.bin/OLD/osdbar b/.bin/OLD/osdbar new file mode 100755 index 0000000..a232347 --- /dev/null +++ b/.bin/OLD/osdbar @@ -0,0 +1,13 @@ +#!/bin/sh + +osd_cat --pos=bottom \ + --offset=220 \ + --align=center \ + --indent=0 \ + --font="-*-terminus-bold-r-normal-*-38-*-*-*-*-*-*-*" \ + --colour="#FF6A00" \ + --barmode=percentage \ + --outline=2 \ + --age=0 \ + --percentage=$1 \ + --text="$2" & diff --git a/.bin/OLD/osdcat b/.bin/OLD/osdcat new file mode 100755 index 0000000..8f61831 --- /dev/null +++ b/.bin/OLD/osdcat @@ -0,0 +1,10 @@ +#!/bin/sh +osd_cat --pos=bottom \ + --offset=220 \ + --align=right \ + --indent=0 \ + --font="-*-terminus-bold-r-normal-*-38-*-*-*-*-*-*-*" \ + --colour="#FF6A00" \ + --age=0 \ + --outline=2 \ + --text="$1" diff --git a/.bin/pass-add b/.bin/OLD/pass-add similarity index 100% rename from .bin/pass-add rename to .bin/OLD/pass-add diff --git a/.bin/OLD/pass-change b/.bin/OLD/pass-change new file mode 100755 index 0000000..ddac709 --- /dev/null +++ b/.bin/OLD/pass-change @@ -0,0 +1,25 @@ +#/bin/sh + +echo -n "Internet/...: " +read +_file="Internet/$REPLY" + +echo -n "Username: " +read +_login="$REPLY" + +echo -n "Password (empty to generate): " +read + +[ -z "$REPLY" ] \ + && _password="$(pwgen -syn -r "{}'\\§()°\`|[]\";" 16 1)" \ + || _password="$REPLY" + +{ + echo "$_password"; + echo "Username: $_login"; +} | pass insert -m "${_file}" + +echo "=======" + +pass "${_file}" diff --git a/.bin/passmenu b/.bin/OLD/passmenu similarity index 100% rename from .bin/passmenu rename to .bin/OLD/passmenu diff --git a/.bin/passmenu-edit b/.bin/OLD/passmenu-edit similarity index 100% rename from .bin/passmenu-edit rename to .bin/OLD/passmenu-edit diff --git a/.bin/pastebitch b/.bin/OLD/pastebitch similarity index 100% rename from .bin/pastebitch rename to .bin/OLD/pastebitch diff --git a/.bin/OLD/pdf b/.bin/OLD/pdf new file mode 100755 index 0000000..c4b847d --- /dev/null +++ b/.bin/OLD/pdf @@ -0,0 +1,7 @@ +#!/bin/sh -e + +tmp=$(mktemp -d) +cd $tmp +wget "$1" +mupdf-gl * +rm -rf $tmp diff --git a/.bin/OLD/pfullcheck b/.bin/OLD/pfullcheck new file mode 100755 index 0000000..b95d42e --- /dev/null +++ b/.bin/OLD/pfullcheck @@ -0,0 +1,9 @@ +#!/bin/sh +make clean=all +make clean=dist +make -j 12 fetch +make package +portcheck +make port-lib-depends-check +make show=MAINTAINER + diff --git a/.bin/OLD/play_remote b/.bin/OLD/play_remote new file mode 100755 index 0000000..f3b1c4a --- /dev/null +++ b/.bin/OLD/play_remote @@ -0,0 +1,23 @@ +#!/bin/sh +# usage play_remote user@server.de "*.mp4" + +_remote=$1 +shift +IFS=' +' +_files="$*" +printf "Server: $_remote\n" +printf "Files: $_files\n\n" + +for _f in $_files; +do + printf "Playing: $_f\n" + ffmpeg -loglevel error \ + -i "$_f" \ + -c:a copy \ + -c:v copy \ + -preset ultrafast \ + -tune zerolatency \ + -f flv pipe: \ + | pv -B 200M | ssh $_remote 'export DISPLAY=:0; pv -B 200M - | ffplay -loglevel error -' +done diff --git a/.bin/pmake b/.bin/OLD/pmake similarity index 100% rename from .bin/pmake rename to .bin/OLD/pmake diff --git a/.bin/port b/.bin/OLD/port similarity index 100% rename from .bin/port rename to .bin/OLD/port diff --git a/.bin/OLD/port-deleter b/.bin/OLD/port-deleter new file mode 100755 index 0000000..d9c6897 --- /dev/null +++ b/.bin/OLD/port-deleter @@ -0,0 +1,11 @@ +#!/bin/sh + +while true; +do + PORT=$(pkg_info -mz | fzf -e --sync --bind start:last) + [ ! -z $PORT ] \ + && doas pkg_delete -c "$PORT" + [ -z $PORT ] \ + && exit 0 +done +pkg_delete -ac diff --git a/.bin/port-info b/.bin/OLD/port-info similarity index 100% rename from .bin/port-info rename to .bin/OLD/port-info diff --git a/.bin/port-list b/.bin/OLD/port-list similarity index 100% rename from .bin/port-list rename to .bin/OLD/port-list diff --git a/.bin/port-shlib-compare b/.bin/OLD/port-shlib-compare similarity index 100% rename from .bin/port-shlib-compare rename to .bin/OLD/port-shlib-compare diff --git a/.bin/portjump b/.bin/OLD/portjump similarity index 100% rename from .bin/portjump rename to .bin/OLD/portjump diff --git a/.bin/portsearch b/.bin/OLD/portsearch similarity index 100% rename from .bin/portsearch rename to .bin/OLD/portsearch diff --git a/.bin/OLD/print_pdf b/.bin/OLD/print_pdf new file mode 100755 index 0000000..e7d09a0 --- /dev/null +++ b/.bin/OLD/print_pdf @@ -0,0 +1,17 @@ +#!/bin/sh -x + +_file="${1%%.*}" +_ext="${1##*.}" +_out="/tmp/print-$(pwgen -1).ps" + +convert_pdf() { + pdf2ps "$_file.$_ext" "$_out" +} + +case $_ext in + [pP][dD][fF]) + convert_pdf; lpr $_out; + ;; +esac + +rm -vf "$_out" diff --git a/.bin/OLD/psearch b/.bin/OLD/psearch new file mode 100755 index 0000000..d54b9df --- /dev/null +++ b/.bin/OLD/psearch @@ -0,0 +1,29 @@ +#!/bin/sh + +_term="$@" +_dir="/usr/ports" + +find $_dir/* -mindepth 1 -maxdepth 1 -name "Makefile" \ + | while read _cmakefile +do + echo $_cmakefile | sed "s|$_dir/\(.*\)/Makefile|\1|g" \ + | while read _cat + do + cat $_dir/$_cat/Makefile \ + | fgrep SUBDIR \ + | cut -d"=" -f2 \ + | while read _port + do + if [ -f "$_dir/$_cat/$_port/pkg/DESCR" ] + then + fgrep -q "$_term" $_dir/$_cat/$_port/pkg/DESCR + if [ $? -eq 0 ] + then + echo "Match in $_cat/$_port:" + cat $_dir/$_cat/$_port/pkg/DESCR + echo "--------------------------" + fi + fi + done + done +done diff --git a/.bin/OLD/pview b/.bin/OLD/pview new file mode 100755 index 0000000..9c30f03 --- /dev/null +++ b/.bin/OLD/pview @@ -0,0 +1,22 @@ +#!/bin/sh +set -e + +CLIP="$(xclip -quiet -o | col -b | head -n 1 | sed 's/-[0-9].*//g' | tr -d ':;[]')" + +if [ -z "$CLIP" ] +then + echo "pview: no data" + exit 1 +fi + +if [ ! -d "/usr/ports/$CLIP" ] +then + echo "pview: invalid data \"$CLIP\"" + exit 1 +fi + +cd "/usr/ports/$CLIP" +P=$(make show=PKGNAME) +R=$(make show=REVISION) +echo "PKG: $P" +echo "REV: $R" diff --git a/.bin/OLD/pview-notify b/.bin/OLD/pview-notify new file mode 100755 index 0000000..4d5270b --- /dev/null +++ b/.bin/OLD/pview-notify @@ -0,0 +1,2 @@ +#!/bin/sh +notify-send "$(pview)" diff --git a/.bin/pwadd b/.bin/OLD/pwadd similarity index 100% rename from .bin/pwadd rename to .bin/OLD/pwadd diff --git a/.bin/OLD/qutebrowser b/.bin/OLD/qutebrowser new file mode 100755 index 0000000..a286d5a --- /dev/null +++ b/.bin/OLD/qutebrowser @@ -0,0 +1,7 @@ +#!/bin/sh +D=$(mktemp -d) +export XDG_RUNTIME_DIR=$D +rm -rf ~/.local/share/qutebrowser/sessions +sed -i 's/^mainwindow.*//' ~/.local/share/qutebrowser/state +/usr/local/bin/qutebrowser --override-restore --target window "$@" +rm -rf $D diff --git a/.bin/OLD/rc3-schedule b/.bin/OLD/rc3-schedule new file mode 100755 index 0000000..953a8c5 --- /dev/null +++ b/.bin/OLD/rc3-schedule @@ -0,0 +1,8 @@ +#!/bin/sh +curl -s "https://static.rc3.world/schedule/everything.json" \ + | jq -crM '.schedule.conference.days[].rooms[][] | [.date,.start,.room,.title]' \ + | sed 's/","/|/g' \ + | tr -d '["]' \ + | sed 's/^\(.[^T]*\)T.[^|]*\(.*\)/\1\2/g' \ + | sort \ + | column -s'|' -t diff --git a/.bin/OLD/rc3-streams b/.bin/OLD/rc3-streams new file mode 100755 index 0000000..5963d83 --- /dev/null +++ b/.bin/OLD/rc3-streams @@ -0,0 +1,34 @@ +#!/bin/sh + +#PLAYER="ffplay -loglevel error -infbuf" +PLAYER="mpv --loop=no" +ROOMS=\ +"cbase +abchillgleis +c3lounge +cwtv +r3s +csh +chaoszone +fem +franconiannet +aboutfuture +sendezentrum +haecksen +gehacktesfromhell +xhain +quit" + +[ -z $1 ] \ + && while true + do + set -e + SEL="$(echo "$ROOMS" | fzf)" + case "$SEL" in + quit) exit 0; ;; + *) ${0} ${SEL}; ;; + esac + done +set -x + +$PLAYER "https://cdn.c3voc.de/hls/${1}/native_hd.m3u8" diff --git a/.bin/OLD/rec_hdmi b/.bin/OLD/rec_hdmi new file mode 100755 index 0000000..ddaa06e --- /dev/null +++ b/.bin/OLD/rec_hdmi @@ -0,0 +1,10 @@ +#!/bin/sh +ffmpeg -loglevel error -y \ + -f v4l2 \ + -input_format mjpeg \ + -framerate 60 \ + -video_size 1920x1080 \ + -i /dev/video \ + -c:v copy \ + -c:a copy \ + /home/sdk/rec_hdmi.mkv diff --git a/.bin/rec_scr_fast b/.bin/OLD/rec_scr_fast similarity index 100% rename from .bin/rec_scr_fast rename to .bin/OLD/rec_scr_fast diff --git a/.bin/rec_scr_huff b/.bin/OLD/rec_scr_huff similarity index 100% rename from .bin/rec_scr_huff rename to .bin/OLD/rec_scr_huff diff --git a/.bin/rec_scr_noaudio b/.bin/OLD/rec_scr_noaudio similarity index 100% rename from .bin/rec_scr_noaudio rename to .bin/OLD/rec_scr_noaudio diff --git a/.bin/recio b/.bin/OLD/recio similarity index 100% rename from .bin/recio rename to .bin/OLD/recio diff --git a/.bin/rem2ics b/.bin/OLD/rem2ics similarity index 100% rename from .bin/rem2ics rename to .bin/OLD/rem2ics diff --git a/.bin/OLD/rem2ics2 b/.bin/OLD/rem2ics2 new file mode 100755 index 0000000..91e6d99 --- /dev/null +++ b/.bin/OLD/rem2ics2 @@ -0,0 +1,34 @@ +#!/usr/bin/awk -f +# rem2ics by Anthony J. Chivetta +# version 0.1 - 2006-06-09 +# Converts output of remind -s to iCalendar +# usage: remind -s | rem2ics +# +# THE FOLLOWING CODE IS RELEASED INTO THE PUBLIC DOMAIN +# +# This program 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 +BEGIN { +print "BEGIN:VCALENDAR" +print "VERSION:2.0" +} +{ +gsub("/","",$1) +print "BEGIN:VEVENT" +if ($5 != "*"){ +printf("DTSTART:%dT%02d%02d00\n",$1,$5/60,$5%60) +printf("DTEND:%dT%02d%02d00\n",$1,$5/60+$4/60,$5%60+$4%60) +split(substr($0,match($0,$7)),sumloc,"|") +print "SUMMARY:" sumloc[1] +} else { +printf("DTSTART:%d\n",$1) +split(substr($0,match($0,$6)),sumloc,"\|") +print "SUMMARY:" sumloc[1] +} +if (sumloc[2]) { +print "LOCATION:" sumloc[2] +} +print "END:VEVENT" +} +END {print "END:VCALENDAR"} diff --git a/.bin/OLD/remake b/.bin/OLD/remake new file mode 100755 index 0000000..1dda685 --- /dev/null +++ b/.bin/OLD/remake @@ -0,0 +1,5 @@ +#!/bin/sh -x +make clean=all +make -j30 fetch +FETCH_PACKAGES=-Dsnap make + diff --git a/.bin/rename_to_lowercase b/.bin/OLD/rename_to_lowercase similarity index 100% rename from .bin/rename_to_lowercase rename to .bin/OLD/rename_to_lowercase diff --git a/.bin/restore b/.bin/OLD/restore similarity index 100% rename from .bin/restore rename to .bin/OLD/restore diff --git a/.bin/OLD/rfile b/.bin/OLD/rfile new file mode 100755 index 0000000..5385902 --- /dev/null +++ b/.bin/OLD/rfile @@ -0,0 +1,49 @@ +#!/bin/ksh +. $HOME/.bin/_config + +_rdir=$1 + +list() { + _dir="$1" + _sel="$(ssh $USER@$DOMAIN "cd \"$_dir\" && ( printf 'GO BACK\nNEW FILE\n'; ls -lt .; )" \ + | egrep -v ^total | fzf)" + + [ $? -ne 0 ] && exit; + + case "$_sel" in + "NEW FILE") newfile "$_dir" ;; + "GO BACK") list "$_dir/.." ;; + *) dofile "$_dir" "$_sel" ;; + esac + list "$_dir" +} + +dofile() { + _dir="$1" + _sel="$2" + _do="$(printf 'EDIT\nDELETE\nDOWNLOAD\n' | fzf)"; + [ $? -ne 0 ] && exit; + + _entry=$(printf '%s' "$_sel" | tr -s ' ' | cut -d" " -f9-) + + if printf '%s' "$_sel" | egrep ^d; + then + list "$_dir/$_entry" + else + case "$_do" in + "EDIT") vim "sftp://$USER@$DOMAIN/$_dir/$_entry" ;; + "DELETE") ssh $USER@$DOMAIN "rm /$_dir/$_entry" ;; + "DOWNLOAD") scp "$USER@$DOMAIN:/$_dir/$_entry" . ;; + "GO BACK") list "$_dir" ;; + esac + fi +} + +newfile() { + _dir="$1" + printf 'Filename (%s)? ' "$(date +%Y-%m-%d-)" + read name; + vim "sftp://$USER@$DOMAIN/$_dir/$name" +} + +list "${_rdir:=$RPATH}" diff --git a/.bin/OLD/rmblog b/.bin/OLD/rmblog new file mode 100755 index 0000000..73aa4a2 --- /dev/null +++ b/.bin/OLD/rmblog @@ -0,0 +1,7 @@ +#!/bin/sh +. $HOME/.bin/_config + +[ -z $1 ] && printf "Usage: rmblog \n" && return +printf "Delete Entry:\n" +ssh $USER@$DOMAIN "rm $LOCAL_PATH/posts/$1" && printf "rm $1: done\n\n" + diff --git a/.bin/rmpaste b/.bin/OLD/rmpaste similarity index 100% rename from .bin/rmpaste rename to .bin/OLD/rmpaste diff --git a/.bin/OLD/rtservermon.pl b/.bin/OLD/rtservermon.pl new file mode 100755 index 0000000..5ee8224 --- /dev/null +++ b/.bin/OLD/rtservermon.pl @@ -0,0 +1,69 @@ +#!/usr/bin/perl +use strict; +use warnings; +# +# ONLY OpenBSD modules included with the default installation are permitted! +# +use HTTP::Tiny; +use Net::Ping; +use Time::HiRes; + +# Configuration hash (editable) +my %config = ( + 'timeout' => 0.20, # How long to wait before giving up on server response, in seconds + 'debug' => 1, # Debug output? + 'top' => 3, # How many entries to return? + 'protocol' => 'tcp', # tcp, udp, icmp, et al + 'port' => 'http', # (used in getservbyname sub) +); + +# hash to store servers and response times to protocol/port requests +my %serverstats; + +# create HTTP::Tiny instance +my $http = HTTP::Tiny->new; + +# Get a list of all current OpenBSD FTP servers +my $response = $http->get('http://ftp.eu.openbsd.org/pub/OpenBSD/ftplist'); +die "Failed!\n" unless $response->{success}; + +# Iterate through server list and get TCP/80 response time in ms +foreach my $line (split("\n", $response->{content})) { + if ($line !~ /(cdn)/) { + if ($line =~ /(http:\/\/)(.+?)(\/\S+)/) { + my $response = &httping($2); + $serverstats{$1.$2.$3} = $response if ($response); + } + } +} + +# Sort & print servers by response time in ms +my $i = 0; +foreach my $key (sort {$serverstats{$a} <=> $serverstats{$b} } keys %serverstats) { + $i++; + print "$key\n"; + last if $i eq $config{'top'}; +} + +# +# Ping TCP/80 and return response time or 0 if unresponsive + some diagnostic output +# + +sub httping ($) { + my $host = shift; + my $ping = Net::Ping->new($config{'protocol'}); + $ping->hires(); + $ping->{port_num} = getservbyname($config{'port'}, $config{'protocol'}); + print ("Trying $host... ") if $config{'debug'}; + my ($retval, $duration, $ip) = $ping->ping($host, $config{'timeout'}); + $ping->close(); + $duration = int($duration * 1000); + + if ($retval) { + print ("$duration ms\n") if $config{'debug'}; + return $duration; + } else { + print ("unresponsive\n") if $config{'debug'};; + return 0; + } +} diff --git a/.bin/OLD/scratchpad b/.bin/OLD/scratchpad new file mode 100755 index 0000000..1820876 --- /dev/null +++ b/.bin/OLD/scratchpad @@ -0,0 +1,5 @@ +#!/bin/sh +tmux ls | grep -q "^scratchpad.*attached" \ + && wmctrl -x -c scratchpad \ + || st -c scratchpad -g 128x38+250+150 -e \ + ksh -c "tmux att -t scratchpad || tmux new-session -s scratchpad" diff --git a/.bin/OLD/scratchpad-shell b/.bin/OLD/scratchpad-shell new file mode 100755 index 0000000..75de198 --- /dev/null +++ b/.bin/OLD/scratchpad-shell @@ -0,0 +1,4 @@ +#!/bin/sh +wmctrl -x -c scratchpad-shell \ + || st -c scratchpad-shell -g 140x40+250+150 -e \ + ksh -ic "ssh -t sdk@116.203.83.222 'LC_ALL=de_DE.UTF-8 tmux -u at || LC_ALL=de_DE.UTF-8 tmux -u'" diff --git a/.bin/OLD/scratchpad.sh b/.bin/OLD/scratchpad.sh new file mode 100755 index 0000000..9a0bd99 --- /dev/null +++ b/.bin/OLD/scratchpad.sh @@ -0,0 +1,64 @@ +#!/usr/bin/env bash + +# a i3-like scratchpad for arbitrary applications. +# +# this lets a new monitor called "scratchpad" appear in from the top into the +# current monitor. There the "scratchpad" will be shown (it will be created if +# it doesn't exist yet). If the monitor already exists it is scrolled out of +# the screen and removed again. +# +# Warning: this uses much resources because herbstclient is forked for each +# animation step. +# +# If a tag name is supplied, this is used instead of the scratchpad + +tag="${1:-scratchpad}" +hc() { "${herbstclient_command[@]:-herbstclient}" "$@" ;} + +mrect=( $(hc monitor_rect "" ) ) + +width=${mrect[2]} +height=${mrect[3]} + +rect=( + $((width/2)) + $((height/2)) + $((${mrect[0]}+(width/4))) + $((${mrect[1]}+(height/4))) +) + +hc chain , add "$tag" , set_attr tags.by-name."$tag".at_end true + +monitor=scratchpad + +exists=false +if ! hc add_monitor $(printf "%dx%d%+d%+d" "${rect[@]}") \ + "$tag" $monitor 2> /dev/null ; then + exists=true +else + # remember which monitor was focused previously + hc chain \ + , new_attr string monitors.by-name."$monitor".my_prev_focus \ + , substitute M monitors.focus.index \ + set_attr monitors.by-name."$monitor".my_prev_focus M +fi + +show() { + hc lock + hc raise_monitor "$monitor" + hc focus_monitor "$monitor" + hc unlock + hc lock_tag "$monitor" +} + +hide() { + # if q3terminal still is focused, then focus the previously focused monitor + # (that mon which was focused when starting q3terminal) + hc substitute M monitors.by-name."$monitor".my_prev_focus \ + and + compare monitors.focus.name = "$monitor" \ + + focus_monitor M + hc remove_monitor "$monitor" +} + +[ $exists = true ] && hide || show + diff --git a/.bin/OLD/scratchpad.tabbed b/.bin/OLD/scratchpad.tabbed new file mode 100755 index 0000000..f663502 --- /dev/null +++ b/.bin/OLD/scratchpad.tabbed @@ -0,0 +1,12 @@ +#!/bin/sh + +[ ! -f /tmp/scratchpad ] && echo invalid > /tmp/scratchpad + +WID="$(cat /tmp/scratchpad | sed 's/0x//g')" +if wmctrl -l | fgrep -q "${WID}"; +then + wmctrl -i -R 0x${WID} -b toggle,hidden,above,sticky +else + WID=$(tabbed -c -d -n scratchpad -g 1280x768+300+120 -r 2 st -w '') + echo ${WID} > /tmp/scratchpad +fi diff --git a/.bin/OLD/screenrecord b/.bin/OLD/screenrecord new file mode 100755 index 0000000..0ed49f3 --- /dev/null +++ b/.bin/OLD/screenrecord @@ -0,0 +1,100 @@ +#!/bin/sh + +set -e + +_vidfile="/home/sdk/rec-screen.mkv" +_outfile="/home/sdk/rec-encoded-$(date "+%Y%m%d_%H%M%S").mp4" + +while getopts 'ame' arg +do + case ${arg} in + a) MIC=1; ;; + m) MON=1; ;; + e) EONLY=1; ;; + esac +done + +_head_param="\ + -y \ + -loglevel error \ + -hide_banner" + +_mon_in="\ + -thread_queue_size 16 \ + -use_wallclock_as_timestamps 1 \ + -f sndio \ + -i snd/mon" + +_mon_proc="\ + -c:a pcm_s16le" + +_mic_in="\ + -thread_queue_size 16 \ + -use_wallclock_as_timestamps 1 \ + -f sndio \ + -i snd/default" + +_mic_proc="\ + -af pan='stereo|c0=FL|c1=FL' \ + -c:a pcm_s16le" + +_vid_in="\ + -probesize 10000000 \ + -f x11grab \ + -i :0.0" + +_vid_proc="\ + -framerate 30 \ + -c:v libx264rgb \ + -crf 0 \ + -qp 0 \ + -framerate 30 \ + -sws_flags neighbor \ + -preset ultrafast \ + -tune zerolatency" + +_map=0; + +_ffmpeg_map=0 +_ffmpeg_param_input="${_vid_in}" +_ffmpeg_param_procs="-map ${_ffmpeg_map}:v ${_vid_proc}" + +if [ "${MIC}" ]; then + _ffmpeg_map=$(( _ffmpeg_map + 1 )) + _ffmpeg_param_input="${_ffmpeg_param_input} ${_mic_in}" + _ffmpeg_param_procs="${_ffmpeg_param_procs} -map ${_ffmpeg_map}:a ${_mic_proc}" +fi + +if [ "${MON}" ]; then + _ffmpeg_map=$(( _ffmpeg_map + 1 )) + _ffmpeg_param_input="${_ffmpeg_param_input} ${_mon_in}" + _ffmpeg_param_procs="${_ffmpeg_param_procs} -map ${_ffmpeg_map}:a ${_mon_proc}" +fi + +_ffmpeg_param="${_ffmpeg_param_input} ${_ffmpeg_param_procs}" + +if [ -z "$EONLY" ]; then + printf 'Press q to stop.\n' + set -x + ffmpeg ${_head_param} ${_ffmpeg_param} "${_vidfile}" + set +x +fi + +if [ ${MON} ] || [ ${MIC} ]; then + _audio_encode_param="-filter_complex amix=inputs=${_ffmpeg_map},stereotools=phase=5,compand=attacks=0:points=-80/-115|-35.1/-80|-35/-35|20/20 -c:a aac -b:a 160k" +fi + +printf 'Encoding...\n' +set -x +ffmpeg -hide_banner -y \ + -i "${_vidfile}" \ + -c:v libx264 \ + -crf 28 \ + -s 1920x1080 \ + -preset veryfast \ + -movflags faststart \ + -threads 8 \ + ${_audio_encode_param} \ + "${_outfile}" +set +x +printf '%s\n' "${_outfile}" diff --git a/.bin/OLD/screenrecord2 b/.bin/OLD/screenrecord2 new file mode 100755 index 0000000..1ccca51 --- /dev/null +++ b/.bin/OLD/screenrecord2 @@ -0,0 +1,98 @@ +#!/bin/sh + +set -e + +_outfile="/home/sdk/rec-encoded-$(date "+%Y%m%d_%H%M%S").mp4" + +while getopts 'ame' arg +do + case ${arg} in + a) MIC=1; ;; + m) MON=1; ;; + e) EONLY=1; ;; + esac +done + +_head_param="\ + -y \ + -loglevel error \ + -hide_banner" + +_mon_in="\ + -thread_queue_size 16 \ + -f sndio \ + -i snd/mon" + +_mon_proc="\ + -c:a pcm_s16le" + +_mic_in="\ + -thread_queue_size 16 \ + -f sndio \ + -i snd/default" + +_mic_proc="\ + -af pan='stereo|c0=FL|c1=FL' \ + -c:a pcm_s16le" + +_vid_in="\ + -probesize 10000000 \ + -f x11grab \ + -i :0.0" + +_vid_proc="\ + -framerate 30 \ + -c:v libx264rgb \ + -crf 0 \ + -qp 0 \ + -framerate 30 \ + -sws_flags neighbor \ + -preset ultrafast \ + -tune zerolatency" + +_map=0; + +_ffmpeg_map=0 +_ffmpeg_param_input="${_vid_in}" +_ffmpeg_param_procs="-map ${_ffmpeg_map}:v ${_vid_proc}" + +if [ "${MIC}" ]; then + _ffmpeg_map=$(( _ffmpeg_map + 1 )) + _ffmpeg_param_input="${_ffmpeg_param_input} ${_mic_in}" + _ffmpeg_param_procs="${_ffmpeg_param_procs} -map ${_ffmpeg_map}:a ${_mic_proc}" +fi + +if [ "${MON}" ]; then + _ffmpeg_map=$(( _ffmpeg_map + 1 )) + _ffmpeg_param_input="${_ffmpeg_param_input} ${_mon_in}" + _ffmpeg_param_procs="${_ffmpeg_param_procs} -map ${_ffmpeg_map}:a ${_mon_proc}" +fi + +_ffmpeg_param="${_ffmpeg_param_input} ${_ffmpeg_param_procs}" + +if [ ${MON} ] || [ ${MIC} ]; then + _audio_encode_param="-filter_complex amix=inputs=${_ffmpeg_map},stereotools=phase=5,compand=attacks=0:points=-80/-115|-35.1/-80|-35/-35|20/20 -c:a aac -b:a 160k" +fi + +printf 'Press q to stop.\n' +set -x + +ffmpeg \ + ${_head_param} \ + ${_ffmpeg_param} \ + -f nut pipe: \ + | ffmpeg \ + -hide_banner \ + -y \ + -i pipe: \ + -c:v libx265 \ + -crf 28 \ + -s 1920x1080 \ + -preset veryfast \ + -movflags faststart \ + -threads 8 \ + ${_audio_encode_param} \ + "${_outfile}" + +set +x +printf '%s\n' "${_outfile}" diff --git a/.bin/OLD/screensort b/.bin/OLD/screensort new file mode 100755 index 0000000..ea50529 --- /dev/null +++ b/.bin/OLD/screensort @@ -0,0 +1,23 @@ +#!/bin/sh + + +PRIMARY= +SECONDARY= +OFFLINE= + +update() { + PRIMARY=$(xrandr --listmonitors | awk '/ 0:/{ print $4 }') + SECONDARY=$(xrandr | awk '/ connected/ { print $1 }' | fgrep -v $PRIMARY) + OFFLINE=$(xrandr | awk '/disconnected/ { print $1 }') +} +update + +menu() { +cat < " +read -r + +case $REPLY in + s) sndioctl -q server.device=0; ;; + [0-9]) sndioctl -q server.device=$(( REPLY + 1 )); ;; +esac diff --git a/.bin/setvideo b/.bin/OLD/setvideo similarity index 100% rename from .bin/setvideo rename to .bin/OLD/setvideo diff --git a/.bin/OLD/setvol b/.bin/OLD/setvol new file mode 100755 index 0000000..f16756d --- /dev/null +++ b/.bin/OLD/setvol @@ -0,0 +1,17 @@ +#!/bin/sh + +increase() { + _vol=$(echo "$(sndioctl -n output.level) + 0.05" | bc) + sndioctl output.level=$_vol 2>&1 || sndioctl output.level=1 + +} +decrease() { + _vol=$(echo "$(sndioctl -n output.level) - 0.05" | bc) + sndioctl output.level=$_vol || sndioctl output.level=0 +} + +case $1 in + "+") increase; ;; + "-") decrease; ;; +esac +dunstify -r 1 "Volume: $(sndioctl -n output.level | tr -d '.' | cut -b1-3 | bc)%" diff --git a/.bin/OLD/shagen b/.bin/OLD/shagen new file mode 100755 index 0000000..54cef54 --- /dev/null +++ b/.bin/OLD/shagen @@ -0,0 +1,4 @@ +#!/bin/sh +set -xe +cd /home/sdk/code/shagen +make $1 diff --git a/.bin/slowmouse b/.bin/OLD/slowmouse similarity index 100% rename from .bin/slowmouse rename to .bin/OLD/slowmouse diff --git a/.bin/smi b/.bin/OLD/smi similarity index 100% rename from .bin/smi rename to .bin/OLD/smi diff --git a/.bin/sp b/.bin/OLD/sp similarity index 100% rename from .bin/sp rename to .bin/OLD/sp diff --git a/.bin/OLD/sp.1 b/.bin/OLD/sp.1 new file mode 100755 index 0000000..6c33c1f --- /dev/null +++ b/.bin/OLD/sp.1 @@ -0,0 +1,52 @@ +#!/bin/sh + +# read resolution from xrandr: "1920x1080 60.03*+" +RES=$(xrandr | grep "*+" | awk '{print $1}') + +# parse xrandr output +RESH=${RES%x*} +RESV=${RES#*x} + +# calculate pixel gap that should surround the window +GAP=$(( RESH / 12 )) + +# Calculate the horzontal/vertical dimensions of the window +H=$(( RESH - 2 * GAP )) +V=$(( RESV - 2 * GAP )) + +# set the quirk in .config/spectrwm/spectrwm.conf +# quirk[scratchpad] = FLOAT + ANYWHERE + FOCUSPREV + +# get scratchpad window id +WID=$(wmctrl -x -l scratchpad | fgrep '.scratchpad' | cut -d" " -f1) + +if [ -z "$WID" ] +then + # start terminal (sterm is st.suckless.org) + sterm -c scratchpad -g 134x29+$GAP+$GAP & + # XXX we cannot resize with wmctrl here, because the window is not + # mapped yet. Adding a sleep here and resize then is visually + # unpleasant. Therefore st is started with hardcoded dimensions + # and resized when hidden. +else + # check if window is iconified or on another WS (or both) + if xwininfo -id $WID | fgrep -q IsUnMapped + then + # move window to current workspace + [ -z $_SWM_WS ] \ + && wmctrl -i -r $WID -t $(xprop -root _NET_CURRENT_DESKTOP | cut -d'=' -f2) \ + || wmctrl -i -r $WID -t $_SWM_WS + # remove hidden flag + wmctrl -i -r $WID -b remove,hidden + # activate (give focus) + wmctrl -i -a $WID + else + # window is visible => hide + wmctrl -i -r $WID -b add,hidden + # correct size while hidden + wmctrl -i -r $WID -e 0,$GAP,$GAP,$H,$V + # move it beyond the WS limit to completely hide it from the bar + # XXX could also be skip_pager / skip_taskbar? + wmctrl -i -r $WID -t 11 + fi +fi diff --git a/.bin/OLD/sp2 b/.bin/OLD/sp2 new file mode 100755 index 0000000..6a87fba --- /dev/null +++ b/.bin/OLD/sp2 @@ -0,0 +1,18 @@ +#/bin/sh +windowname="scratchpad-$1" +desk=`wmctrl -d | grep '*' | cut -d ' ' -f '1'` +scratch_desk=`wmctrl -l | grep $windowname | cut -d ' ' -f '3'` + +xprop -name "$windowname" + +if [ $? -eq 0 ]; then + if [ $desk -eq $scratch_desk ]; then + wmctrl -r $windowname -t $desk + wmctrl -r $windowname -b toggle,hidden + else + wmctrl -R $windowname + wmctrl -r $windowname -b remove,hidden + fi +else + st -c $windowname +fi diff --git a/.bin/ssh-tunnel b/.bin/OLD/ssh-tunnel similarity index 100% rename from .bin/ssh-tunnel rename to .bin/OLD/ssh-tunnel diff --git a/.bin/OLD/sshot b/.bin/OLD/sshot new file mode 100755 index 0000000..f8d1376 --- /dev/null +++ b/.bin/OLD/sshot @@ -0,0 +1,25 @@ +#!/bin/sh + +. ${HOME}/.bin/_config + +trap cleanup 1 2 3 6 +cleanup() { rm -f "$file"; } + + +# FILENAME +file="${HOME}/Downloads/Screenshots/$(date "+%Y-%m-%d_%H-%M-%S")-sshot.png" +mkdir -p "$(dirname "$file")" + +# TAKE SCREENSHOT +flameshot gui -p "$file" +test -f "$file" || exit 1 + +# COMPRESS +test -f /usr/local/bin/pngcrush \ + && pngcrush -reduce "$file" + +# UPLOAD +_SWM_WS=-1 texec "upload \"$file\"" + +# NOTIFY +NOTIFY_CMD "$(xclip -o)" diff --git a/.bin/OLD/start-on-ws b/.bin/OLD/start-on-ws new file mode 100755 index 0000000..381a768 --- /dev/null +++ b/.bin/OLD/start-on-ws @@ -0,0 +1,4 @@ +#!/bin/sh +ws=$1 +shift +_SWM_WS=$(( ws - 1 )) $@ diff --git a/.bin/OLD/startmud b/.bin/OLD/startmud new file mode 100755 index 0000000..afa251e --- /dev/null +++ b/.bin/OLD/startmud @@ -0,0 +1,2 @@ +config="$(basename $0).tin" +echo tt++ ~/.bin/mud/$config diff --git a/.bin/OLD/startpage b/.bin/OLD/startpage new file mode 100755 index 0000000..ddddf1b --- /dev/null +++ b/.bin/OLD/startpage @@ -0,0 +1,2 @@ +#!/bin/sh +curl -s "https://eu.startpage.com/do/search?prfe=00d4bb7f075582be9304aaad813ac6b4dc4bd733a098955c35c0586a99eaddf123ac81f1301f1e4f06fd014082141134ec5e0c5441250cf4c05557bed28fcfbced8de0007d01a0254332962533&query=${@}" diff --git a/.bin/OLD/startsway.sh b/.bin/OLD/startsway.sh new file mode 100755 index 0000000..18c3a4b --- /dev/null +++ b/.bin/OLD/startsway.sh @@ -0,0 +1,27 @@ +#! /bin/ksh +set -eu + +: ${WLR_DRM_DEVICES:=/dev/dri/card0} +: ${LIBSEAT_BACKEND:=noop} +: ${XDG_CURRENT_DESKTOP:=sway} +: ${XDG_RUNTIME_DIR:=${HOME}/.local/run} +: ${QT_QPA_PLATFORM:=wayland} +#: MOZ_ENABLE_WAYLAND:=1 # doesn't work yet + +export WLR_DRM_DEVICES LIBSEAT_BACKEND +export XDG_CURRENT_DESKTOP XDG_RUNTIME_DIR +export QT_QPA_PLATFORM + +if [ ! -d "${XDG_RUNTIME_DIR}" ]; then + mkdir -m 700 -p "${XDG_RUNTIME_DIR}" +fi + +#setxkbmap "de" +#ulimit -c 0 +#xset +fp $HOME/.fonts +#xsetroot -solid rgb:0A/0A/0A +#eval $(gnome-keyring-daemon --replace --components=secrets) +#dbus-update-activation-environment --all +#export GNOME_KEYRING_CONTROL GNOME_KEYRING_SOCKET GNOME_KEYRING_PID + +exec /usr/local/bin/sway "$@" diff --git a/.bin/OLD/stmin b/.bin/OLD/stmin new file mode 100755 index 0000000..6db4ed8 --- /dev/null +++ b/.bin/OLD/stmin @@ -0,0 +1,2 @@ +#!/bin/sh +st -f "-xos4-terminus-medium-r-normal--13-200-72-72-c-100-iso10646-1" diff --git a/.bin/OLD/stromgedacht.sh b/.bin/OLD/stromgedacht.sh new file mode 100755 index 0000000..80a0074 --- /dev/null +++ b/.bin/OLD/stromgedacht.sh @@ -0,0 +1,22 @@ +#!/bin/sh + +PLZ=$1 +PLZ=${PLZ:=68766} + +STATE=$(curl -s -X GET -H "accept":"application/json" \ + https://api.stromgedacht.de/v1/now?zip=$PLZ | jq -rc .state) + +case $STATE in + -1) echo "superGreen" + ;; + 1) echo "Green" + ;; + 3) echo "Green" + ;; + 4) echo "Green" + ;; + *) echo "Unkown state code: $STATE" + ;; +esac + + diff --git a/.bin/subsonic b/.bin/OLD/subsonic similarity index 100% rename from .bin/subsonic rename to .bin/OLD/subsonic diff --git a/.bin/OLD/sudo b/.bin/OLD/sudo new file mode 100755 index 0000000..af99b67 --- /dev/null +++ b/.bin/OLD/sudo @@ -0,0 +1,2 @@ +#!/bin/sh +doas $@ diff --git a/.bin/OLD/sysclean-rm b/.bin/OLD/sysclean-rm new file mode 100755 index 0000000..10cfce1 --- /dev/null +++ b/.bin/OLD/sysclean-rm @@ -0,0 +1,37 @@ +#!/bin/sh + +LIST="$(doas sysclean -a)" + +FILES="$(echo "$LIST" | grep -v ^@)" +USERS="$(echo "$LIST" | grep ^@user | cut -d" " -f2 | cut -d":" -f1)" +GROUPS="$(echo "$LIST" | grep ^@group | cut -d" " -f2 | cut -d":" -f1)" + +if [ ! -z "$FILES" ] +then + echo "$FILES" + echo -n "Delete these? [y/N] " + read + case $REPLY in + [yY]) echo "$FILES" | xargs doas rm -rf; ;; + esac +fi + +if [ ! -z "$USERS" ] +then + echo "$USERS" + echo -n "Delete these users? [y/N] " + read + case $REPLY in + [yY]) echo "$USERS" | xargs -n1 doas userdel; ;; + esac +fi + +if [ ! -z "$GROUPS" ] +then + echo "$GROUPS" + echo -n "Delete these groups? [y/N] " + read + case $REPLY in + [yY]) echo "$GROUPS" | xargs -n1 doas groupdel; ;; + esac +fi diff --git a/.bin/OLD/syspatch-all b/.bin/OLD/syspatch-all new file mode 100755 index 0000000..68f3a8d --- /dev/null +++ b/.bin/OLD/syspatch-all @@ -0,0 +1,17 @@ +#!/bin/sh + +SERVERS=" +irc.uugrn.org +www.uugrn.org +mail2.uugrn.org +mail.codevoid.de +dns.codevoid.de +codevoid.de +home.codevoid.de +" + + +for srv in $SERVERS +do + ssh $srv "doas syspatch" +done diff --git a/.bin/OLD/t2i/Makefile b/.bin/OLD/t2i/Makefile new file mode 100644 index 0000000..068989c --- /dev/null +++ b/.bin/OLD/t2i/Makefile @@ -0,0 +1,10 @@ +all: build test + +build: + cc -o text2ical text2ical.c + +clean: + rm -f text2ical + +test: + ./text2ical < test.txt diff --git a/.bin/OLD/t2i/test.txt b/.bin/OLD/t2i/test.txt new file mode 100644 index 0000000..3a7b87c --- /dev/null +++ b/.bin/OLD/t2i/test.txt @@ -0,0 +1,24 @@ +FIXME 07.10.2022 19:00 +FIXME 11.11.2022 19:00 statt 04.11, Grund: Raumsituation +FIXME 02.12.2022 19:00 +FIXME 13.01.2023 19:00 statt 06.01.2023, Grund: Raumsituation +FIXME 03.02.2023 19:00 +FIXME 03.03.2023 19:00 +FIXME 14.04.2023 19:00 statt 07.04.2023, Grund: Raumsituation +FIXME 05.05.2023 19:00 +FIXME 02.06.2023 19:00 +FIXME 07.07.2023 19:00 +FIXME 04.08.2023 19:00 +FIXME 01.09.2023 19:00 +FIXME 06.10.2023 19:00 +FIXME 03.11.2023 19:00 +FIXME 01.12.2023 19:00 + + +STAMMTISCH 19.12.2022 18:00 +STAMMTISCH 17.01.2023 18:00 +STAMMTISCH 20.02.2023 18:00 +STAMMTISCH 20.03.2023 18:00 +STAMMTISCH 17.04.2023 18:00 +STAMMTISCH 15.05.2023 18:00 +STAMMTISCH 19.06.2023 18:00 diff --git a/.bin/OLD/t2i/text2ical b/.bin/OLD/t2i/text2ical new file mode 100755 index 0000000..31c63ac Binary files /dev/null and b/.bin/OLD/t2i/text2ical differ diff --git a/.bin/OLD/t2i/text2ical.c b/.bin/OLD/t2i/text2ical.c new file mode 100644 index 0000000..3ca8097 --- /dev/null +++ b/.bin/OLD/t2i/text2ical.c @@ -0,0 +1,88 @@ +#include +#include +#include + +int main(int argc, const char *argv[]) +{ + char buf[256]; + int bufpos = 0; + int sepno = 0; + int newevent = 1; + struct tm timeptr; + + char *pevent, *pdate, *ptime, *comment = &buf[0]; + char c; + + memset(buf, 0x0, sizeof(buf)); + + printf("BEGIN:VCALENDAR\n"); + printf("VERSION:2.0\n"); + printf("PRODID:-//uugrn.org//Event Calendar 1.0//EN\n"); + printf("CALSCALE:GREGORIAN\n"); + printf("METHOD:PUBLISH\n"); + printf("ORGANIZER:Unix User Group Rhein-Neckar\n\n"); + + while((c = getc(stdin)) != EOF) { + + if(newevent) { + printf("BEGIN:VEVENT\n"); + newevent = 0; + } + + /* append the current charater to our buffer */ + buf[bufpos] = c; + + /* we found a tab or newline */ + if(c == 0x9 || c == 0x0a) { + + /* count it */ + sepno++; + + /* ... and terminate here, so we can print buf */ + buf[bufpos] = 0x0; + + /* skip lines without at least two tabs and one newline */ + if(sepno < 3 && c == 0x0a) { + bufpos = sepno = 0; + continue; + } + + if (sepno == 1) + printf("SUMMARY:%s\n", buf); + + else if (sepno == 2) { + strptime(buf, "%d.%m.%Y", &timeptr); + printf("DTSTART:%.4d%.2d%.2d", + timeptr.tm_year + 1900, + timeptr.tm_mon + 1, + timeptr.tm_mday); + + } else if (sepno == 3) { + strptime(buf, "%H:%M", &timeptr); + printf("%.2d%.2d\n", + timeptr.tm_hour, + timeptr.tm_min); + printf("DTEND:%.2d%.2d\n", + timeptr.tm_hour + 3, + timeptr.tm_min); + } + + else if (sepno == 4) + printf("DESCRIPTION:%s\n", buf); + + if (c == 0x0a) { + printf("END:VEVENT\n\n"); + newevent = 1; + + sepno = 0; + } + + bufpos = 0; + } else + bufpos++; + } + + printf("END:VCALENDAR\n"); + + return 0; +} diff --git a/.bin/OLD/t2i/timetest b/.bin/OLD/t2i/timetest new file mode 100755 index 0000000..5e90a46 Binary files /dev/null and b/.bin/OLD/t2i/timetest differ diff --git a/.bin/OLD/t2i/timetest.c b/.bin/OLD/t2i/timetest.c new file mode 100644 index 0000000..54592c2 --- /dev/null +++ b/.bin/OLD/t2i/timetest.c @@ -0,0 +1,13 @@ +#include +#include + +int main(int argc, const char *argv[]) +{ + char str[] = "07.10.2022"; + struct tm timeptr; + strptime(str, "%d.%m.%Y", &timeptr); + printf("%d%d%d\n", timeptr.tm_year + 1900, timeptr.tm_mon + 1, timeptr.tm_mday); + + + return 0; +} diff --git a/.bin/OLD/tapebackup.sh.orig b/.bin/OLD/tapebackup.sh.orig new file mode 100755 index 0000000..1f9be9f --- /dev/null +++ b/.bin/OLD/tapebackup.sh.orig @@ -0,0 +1,107 @@ +#!/bin/sh + +export LANG="UTF-16" + +# v0.6 add finish time prediction +# v0.5 change + bsd tar +# v0.4 read with 4m buffer, write with 128k +# v0.3 added mbuffer to restore +# v0.2 merge restore/backup script and add parameter handling +# v0.1 initial version + +### CONFIG ### + +_key="/etc/keyfile" +_dev="/dev/nsa0" +_buffer="8G" +_tapeln="10320" # full tape read/write time in seconds + +### FUNCTIONS ### + +V=0.6 + +usage() { + printf '%s%s\n%s\n%s\n%s\n\n' \ + "$0" ": " \ + " -b backup mode" \ + " -r restore mode" \ + " directory to backup or restore to" + exit 2 +} + +_src="$(readlink -f "$2")" +[ -z $_src ] && printf 'File or Directory does not exist: %s\n\n' "$1" && usage + +dates() { + printf 'Start: %s\nEnd: %s (predicted)\n' "$(date)" "$(date -r $(($(date +%s)+$_tapeln)))" +} + +backup() { + printf 'Calculating...\n' + printf 'Backing up %s with a total size of %s\n' "$_src" "$(du -hs $_src | awk '{ print $1 }')" + dates + tar -b 2048 -cf - "$_src" \ + | zstd -T0 \ + | openssl enc -e -pbkdf2 -aes256 -pass file:$_key \ + | mbuffer -v 1 -t -m $_buffer -P 90 -s 4096k \ + | dd of=$_dev ibs=4096k obs=128k + printf 'End: %s\n' "$(date)" +} + +restore() { + printf 'Restoring data to %s (logging to restore.log)\n' "$_src" + dates | tee restore.log + dd if=$_dev ibs=128k obs=4096k \ + | openssl enc -d -pbkdf2 -aes256 -pass file:$_key \ + | zstd -T0 -d \ + | mbuffer -v 1 -t -m $_buffer -s 4096k \ + | tar -C "$_src" -b 2048 -xvf - >> restore.log 2>&1 + printf 'End: %s\n' "$(date)" | tee restore.log +} + +list() { + printf 'Reading Index\n' + printf 'Start: %s\n Predicted End: %s\n'\ + "$(date)" "date -r $(($(date +%s)+$_tapeln))" + + dd if=$_dev ibs=128k obs=4096k \ + | openssl enc -d -pbkdf2 -aes256 -pass file:$_key \ + | gtar --zstd -tf /dev/stdin + date +} + +### MAIN PROGRAM ### + +blogo() { +printf '%s%s%s\n\n' \ +' + ______ ____ __ + /_ __/___ _____ ___ / __ )____ ______/ /____ ______ + / / / __ `/ __ \/ _ \ / __ / __ `/ ___/ //_/ / / / __ \ + / / / /_/ / /_/ / __/ / /_/ / /_/ / /__/ ,< / /_/ / /_/ / +/_/ \__,_/ .___/\___/ /_____/\__,_/\___/_/|_|\__,_/ .___/ + /_/ CODEVOID BACKUP TOOL v'"$V"' /_/ +' +} + +rlogo() { +printf '%s%s\n\n' \ +' + ______ ____ __ + /_ __/___ _____ ___ / __ \___ _____/ /_____ ________ + / / / __ `/ __ \/ _ \ / /_/ / _ \/ ___/ __/ __ \/ ___/ _ \ + / / / /_/ / /_/ / __/ / _, _/ __(__ ) /_/ /_/ / / / __/ +/_/ \__,_/ .___/\___/ /_/ |_|\___/____/\__/\____/_/ \___/ + /_/ CODEVOID BACKUP TOOL v'"$V" +} + +case $1 in + -b) blogo; + backup; + ;; + -r) rlogo; + restore; + ;; + *) usage; + ;; +esac diff --git a/.bin/tarsnap-delete b/.bin/OLD/tarsnap-delete similarity index 100% rename from .bin/tarsnap-delete rename to .bin/OLD/tarsnap-delete diff --git a/.bin/OLD/tclsh b/.bin/OLD/tclsh new file mode 120000 index 0000000..82ae3cd --- /dev/null +++ b/.bin/OLD/tclsh @@ -0,0 +1 @@ +/usr/local/bin/tclsh8.6 \ No newline at end of file diff --git a/.bin/OLD/test.cc b/.bin/OLD/test.cc new file mode 100755 index 0000000..e69de29 diff --git a/.bin/OLD/text2ical b/.bin/OLD/text2ical new file mode 100755 index 0000000..f95860b Binary files /dev/null and b/.bin/OLD/text2ical differ diff --git a/.bin/OLD/tftuv b/.bin/OLD/tftuv new file mode 100755 index 0000000..e2dab65 --- /dev/null +++ b/.bin/OLD/tftuv @@ -0,0 +1,2 @@ +#!/bin/sh +python3 /home/sdk/Games/TFTUV/TFTUV.py diff --git a/.bin/OLD/timer.c b/.bin/OLD/timer.c new file mode 100644 index 0000000..87a2390 --- /dev/null +++ b/.bin/OLD/timer.c @@ -0,0 +1,67 @@ +#include +#include +#include +#include +#include + +void sig_handler(int signo) +{ + if (signo == SIGINFO) + printf("received SIGINFO\n"); +} + +int main(int argc, const char *argv[]) +{ + char inputMinutes[6]; + char inputText[256]; + + // register signal handler + if (signal(SIGINFO, sig_handler) == SIG_ERR) + printf("\ncan't catch SIGINFO\n"); + + FILE *fp; + + // READ INPUT MINUTES + fp = popen("echo | dmenu -p \"Set timer (minutes): \" -i -fn \"Droid Sans Mono for Powerline-14\" -nb \"#181818\" -sb \"#282828\"", "r"); + if (fp == NULL) { + printf("Failed to run command\n" ); + exit(1); + } + while (fgets(inputMinutes, sizeof(inputMinutes)-1, fp) != NULL) { + printf("%s", inputMinutes); + } + pclose(fp); + + fp = popen("echo | dmenu -p \"Set timer (text): \" -i -fn \"Droid Sans Mono for Powerline-14\" -nb \"#181818\" -sb \"#282828\"", "r"); + if (fp == NULL) { + printf("Failed to run command\n" ); + exit(1); + } + while (fgets(inputText, sizeof(inputText)-1, fp) != NULL) { + printf("%s", inputText); + } + pclose(fp); + + inputText[strcspn(inputText, "\n")] = 0; + if(!strlen(inputText)) { + strcat(inputText, "Beep Beep"); + } + + int delaySeconds = atoi(inputMinutes) * 60; + printf("Timer set for %i minute(s) with text \"%s\"\n", delaySeconds / 60, inputText); + + int elapsedSeconds = 1; + while((delaySeconds + 1) > elapsedSeconds) { + elapsedSeconds = elapsedSeconds + 1; + nanosleep(&(struct timespec){.tv_sec=1}, NULL); + } + + char command[512]; + + strcpy(command, "i3-nagbar -m \"Timer: "); + strcat(command, inputText); + strcat(command, "!\" -t warning -f \"-*-helvetica-bold-r-*-*-20-*-*-*-*-*-*-*\""); + system(command); + + return 0; +} diff --git a/.bin/OLD/tkremind b/.bin/OLD/tkremind new file mode 100755 index 0000000..d70696b --- /dev/null +++ b/.bin/OLD/tkremind @@ -0,0 +1,4199 @@ +#!/bin/sh +# -*-Mode: TCL;-*- + +#-------------------------------------------------------------- +# TKREMIND +# +# A cheesy graphical front/back end for Remind using Tcl/Tk +# +# This file is part of REMIND. +# Copyright (C) 1992-2022 Dianne Skoll +# +#-------------------------------------------------------------- + +# the next line restarts using wish \ +exec /usr/local/bin/wish8.6 "$0" ${1+"$@"} + +# We need at least version 8.5 because of {*} list expansion operator +if {[catch {package require Tcl 8.5}]} { + puts stderr "This program requires Tcl 8.5 or higher." + puts stderr "You have version [info tclversion]" + exit 1 +} + +wm withdraw . + +set Hostname [exec hostname] + +# Our icon photo +catch { + image create photo rpicon -data { +R0lGODlhFwAgAOecABUTERYTERYUERcVEhgWExkXFBkXFRoXFRsZFhwZFxwa +GB0bGR4cGR4cGh8dGiAeHCEfHCEfHSIgHSIgHiQiHyYkISknJCooJispJywq +Jy4sKTIwLjUzMDUzMTo4Njs5Nzs5ODw7ODw7OT07OT48OkE/PUJAPkNBP0RC +QEVDQUVEQkdFQ0lIRkpJR01LSU5MSlBPTVFQTlNSUFRSUFRSUVVTUlVUUllY +VltZV1xaWF1cWmBfXmJgX2RiYGZlY2dmZGppZ2tqaG1ram9tbHFwb3Jwb3Rz +cXV0c3Z0c3Z1c3Z1dHd1dHh2dXh3dnt5eHx7eXx7en18en59e4B/foGAf4KB +f4SDgYWEgoWEg4eGhIiHhouKiI2Mio6Ni46NjJCQj5KRkJSTkZeWlpiXlpmY +l5qZmJybmp6dnKCfnqGgoKKhoKOioaSjoqinp6qpqKurqq+urbCvrrCwr7Gw +r7OysbW1tLi3tri3t7u6ur28vMTDw8TEw8XFxMbFxcfGxsfHxsrJycrKyczM +y83My83MzM3NzdDQz9LR0dPS0tPT09fX19jY19ra2dvb29zc29zc3Ojn5+jo +6Orq6uzs7O/v7/T09PX19fb29vf39/r6+vv7+/7+/v////////////////// +//////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////// +/////////////////////yH5BAEKAP8ALAAAAAAXACAAAAj+AP8JHEiwoMGD +CAcusRAAQEKDBQIcEBAAwUODAQJAsBGAwsWCBzJuUBLgI0ENGVM2dACg5UWV +KU+Y/JfRQBknPoq8ATQz4wxOQIFa6vMx5ZSgQetczJDSClKgcF6mFDEnE9I2 +D0fADOChUdA1D7dmTBEUTditDQRQAnomIQaxICpoAmomoUoAGS2YIBIUDEIu +YndI8FAJaBaEMlIuSEkloxugUBBOSLkh44AvGfkAPYJQpYqMLIQEILB205DO +KW9kJHMhQAmgkaKgzsgjggM5GbEAxaNmdoAPOoz8CCAgEVAtg3wPEPMnQQAU +QWsg5AAzDZSMbIBeaoHwAUwSDAI2XMAENA8ThAPEBvAStEkc3yonrOW0aUMk ++BkBVAlaKATC8Fsp8Igid5ABgxMHtaTgggy6ZFBAADs= } + + wm iconphoto . -default rpicon +} + +proc missing_tcllib { pkg } { + catch { puts stderr "Could not find the '$pkg' package -- you must install tcllib.\nPlease see http://tcllib.sourceforge.net/" } + tk_dialog .err "Error: tcllib not installed" "Could not find the '$pkg' package -- you must install tcllib. Please see http://tcllib.sourceforge.net/" error 0 OK + exit 1 +} +if {[catch {package require mime}]} { + missing_tcllib mime +} + +if {[catch {package require smtp}]} { + missing_tcllib smtp +} +if {[catch {package require json}]} { + missing_tcllib json +} + +if {$tcl_platform(platform) == "windows"} { + tk_dialog .error Error "Please do not port Remind to Windows" error 0 OK + exit 1 +} + +#--------------------------------------------------------------------------- +# GLOBAL VARIABLES +#--------------------------------------------------------------------------- + +set Option(ConfirmQuit) 0 +set OptDescr(ConfirmQuit) "(0/1) If 1, TkRemind prompts you to confirm 'Quit' operation" +set Option(AutoClose) 1 +set OptDescr(AutoClose) "(0/1) If 1, TkRemind automatically closes pop-up reminders after a minute" +set Option(RingBell) 0 +set OptDescr(RingBell) "(0/1) If 1, TkRemind beeps the terminal when a pop-up reminder appears" + +set Option(StartIconified) 0 +set OptDescr(StartIconified) "(0/1) If 1, TkRemind starts up in the iconified state" + +set Option(Deiconify) 0 +set OptDescr(Deiconify) "(0/1) If 1, TkRemind deiconifies the calendar window when a reminder pops up" + +set Option(ShowTodaysReminders) 1 +set OptDescr(ShowTodaysReminders) "(0/1) If 1, TkRemind shows all of today's non-timed reminders in a window at startup and when the date changes" + +set Option(RunCmd) "" +set OptDescr(RunCmd) "(String) If non-blank, run specified command when a pop-up reminder appears" +set Option(FeedReminder) 0 +set OptDescr(FeedReminder) "(0/1) If 1, feed the reminder to RunCmd on standard input (see RunCmd option)" + +set Option(DayAnchor) "center" +set OptDescr(DayAnchor) "(w/center/e) Anchor the day number to the left (w), center or right (e) of its container" + +set Option(Editor) "emacs +%d %s" +set OptDescr(Editor) "(String) Specify command to edit a file. %d is replaced with line number and %s with filename" + +set Option(MailAddr) "" +set OptDescr(MailAddr) "(String) Specify an e-mail address to which reminders should be sent if the popup window is not manually dismissed" + +set Option(SMTPServer) "127.0.0.1" +set OptDescr(SMTPServer) "(String) IP address or host name of SMTP server to use for sending e-mail" + +set Option(ExtraRemindArgs) "" +set OptDescr(ExtraRemindArgs) "(String) Extra arguments when invoking remind" + +set Option(CalboxFont) [font actual TkFixedFont] +set OptDescr(CalboxFont) "Font to use in calendar boxes in Tk font format" + +set Option(HeadingFont) [font actual TkDefaultFont] +set OptDescr(HeadingFont) "Font to use in calendar headings in Tk font format" + +set Option(BackgroundColor) "#d9d9d9" +set OptDescr(BackgroundColor) "Default background color of calendar boxes" + +set Option(TextColor) "#000000" +set OptDescr(TextColor) "Default text color in calendar boxes" + +set Option(TodayColor) "#00C0C0" +set OptDescr(TodayColor) "Background color for today heading" + +set Option(LineColor) "#000000" +set OptDescr(LineColor) "Color of gridlines on calendar" + +set Option(LabelColor) "#000000" +set OptDescr(LabelColor) "Default label color for headings" + +set Option(WinBackground) "#d9d9d9" +set OptDescr(WinBackground) "Background color of calendar window" + +set TimerUpdateForChanges "" + +# Remind program to execute -- supply full path if you want +set Remind "remind" + +# Rem2PS program to execute -- supply full path if you want +set Rem2PS "rem2ps" + +# Rem2PDF program to execute -- supply full path if you want +set Rem2PDF "rem2pdf" + +# Check if we have Rem2PDF +set HaveRem2PDF 0 + +set a [exec sh -c "$Rem2PDF < /dev/null 2>&1 || true"] + +if {[string match "rem2pdf:*" "$a"]} { + set HaveRem2PDF 1 +} + +# Reminder file to source -- default +set ReminderFile {NOSUCHFILE} +set ReminderFile [file nativename "~/.reminders"] + +# Default options file +set ConfigFile "" + +set EditorPid -1 + +# Inotify file +set InotifyFP "" + +# Errors from last remind run +set RemindErrors "" + +# Reminder file to append to -- default +set AppendFile {NOSUCHFILE} +catch {set AppendFile $ReminderFile} + +# Array of tags -> JSON dicts +array unset TagToObj + +set SetFontsWorked 0 +#---------------- DON'T CHANGE STUFF BELOW HERE ------------------ + +# 24-hour clock mode +set TwentyFourHourMode 0 + +# Is Monday in first column? +set MondayFirst 0 + +# Month names in English +set MonthNames {January February March April May June July August September October November December} + +# Day name in English +set EnglishDayNames {Sunday Monday Tuesday Wednesday Thursday Friday Saturday} + +# Day names in Remind's pre-selected language - will be overwritten +set DayNames $EnglishDayNames + +# Current month and year -- will be set by Initialize procedure +set CurMonth -1 +set CurYear -1 + +# Background reminder counter +set BgCounter 0 + +# Absolutely today -- unlike the CurMonth and CurYear, these won't change +set now [clock seconds] + +set TodayMonth [expr [string trim [clock format $now -format %N]] - 1] +set TodayYear [clock format $now -format %Y] +set TodayDay [string trim [clock format $now -format %e]] +set CurMonth $TodayMonth +set CurYear $TodayYear + +# Reminder option types and skip types +set OptionType 1 +set SkipType 1 +# Remind command line +set CommandLine {} +set PSCmd {} + +# Print options -- destination file; letter-size; landscape; fill page; default +# encoding; 36pt margins; print small calendars +set OptDescr(PrintDest) "Print destination: file or command" +set Option(PrintDest) file + +set OptDescr(PrintSize) "Page size: a4 or letter" +set Option(PrintSize) letter + +set OptDescr(PrintOrient) "Page orientation: portrait or landscape" +set Option(PrintOrient) landscape + +set OptDescr(PrintFill) "(0/1) If 1, fill entire page when printing" +set Option(PrintFill) 1 + +set OptDescr(PrintDaysRight) "(0/1) If 1, put day numbers in the top-right of each calendar box" +set Option(PrintDaysRight) 1 + +set OptDescr(PrintEncoding) "(0/1) If 1, apply ISO-8859-1 encoding to PostScript output" +set Option(PrintEncoding) 0 + +set OptDescr(PrintMargins) "Print margins: One of 24pt, 36pt or 48pt" +set Option(PrintMargins) 36pt + +set OptDescr(PrintSmallCalendars) "(0/1) If 1, print small calendars in PostScript output" +set Option(PrintSmallCalendars) 1 + +set OptDescr(PrintFormat) "Print format: pdf or ps" +set Option(PrintFormat) ps + +set WarningHeaders [list "# Lines staring with REM TAG TKTAGnnn ... were created by tkremind" "# Do not edit them by hand or results may be unpredictable."] + +# Highest tag seen so far. Array of tags is stored in ReminderTags() +set HighestTagSoFar 0 + +proc get_weekday { yyyymmdd } { + global EnglishDayNames + return [lindex $EnglishDayNames [clock format [clock scan $yyyymmdd] -format %w -locale C]] +} + +proc write_warning_headers { out } { + global WarningHeaders + foreach h $WarningHeaders { + puts $out $h + } +} + +proc is_warning_header { line } { + global WarningHeaders + foreach h $WarningHeaders { + if {"$line" == "$h"} { + return 1 + } + } + return 0 +} + +#*********************************************************************** +# %PROCEDURE: Initialize +# %ARGUMENTS: +# None +# %RETURNS: +# Nothing +# %DESCRIPTION: +# Initializes TkRemind -- sets day names, Remind command line, +# MondayFirst flag, current date, etc. +#*********************************************************************** +proc Initialize {} { + global DayNames argc argv CommandLine ReminderFile AppendFile Remind PSCmd + global MondayFirst TwentyFourHourMode ReminderFileModTime + global TodayDay TodayMonth TodayYear + + global Option ConfigFile + + # In case date has rolled over, recalculate Today* values + set now [clock seconds] + + set TodayMonth [expr [string trim [clock format $now -format %N]] - 1] + set TodayYear [clock format $now -format %Y] + set TodayDay [string trim [clock format $now -format %e]] + + set CommandLine "|$Remind -itkremind=1 -pp -y -l EXTRA" + set PSCmd "$Remind -itkremind=1 -itkprint=1 -pp -l EXTRA" + set i 0 + while {$i < $argc} { + if {[regexp -- {-[bgxim].*} [lindex $argv $i]]} { + append CommandLine " [lindex $argv $i]" + append PSCmd " [lindex $argv $i]" + if {[regexp -- {m} [lindex $argv $i]]} { + set MondayFirst 1 + } + if {"[lindex $argv $i]" == "-b1"} { + set TwentyFourHourMode 1 + } + } else { + break + } + incr i + } + if {$i < $argc} { + set ReminderFile [lindex $argv $i] + set AppendFile $ReminderFile + incr i + if {$i < $argc} { + set AppendFile [lindex $argv $i] + incr i + if {$i < $argc} { + set ConfigFile [lindex $argv $i] + incr i + } + } + } + + # If reminder file is a directory and appendfile is the same as + # reminder file, choose append file to be $ReminderFile/100-tkremind.rem + if {[file isdirectory $ReminderFile]} { + if {"$ReminderFile" == "$AppendFile"} { + set AppendFile [file join $ReminderFile "100-tkremind.rem"] + } + } + + # Check system sanity + if {! [file readable $ReminderFile]} { + set ans [tk_dialog .error "TkRemind: Warning" "Can't read reminder file `$ReminderFile'" warning 0 "Create it and continue" "Exit"] + if {$ans != 0} { + exit 1 + } + catch { + set out [open $ReminderFile w] + write_warning_headers $out + puts $out "" + close $out + } + } + if {! [file readable $ReminderFile]} { + tk_dialog .error "TkRemind: Error" "Could not create reminder file `$ReminderFile'" error 0 "Exit" + exit 1 + } + + if {[file isdirectory $ReminderFile] && ! [file exists $AppendFile]} { + if {![catch { + set out [open $AppendFile "a"] + write_warning_headers $out + puts $out "" + close $out}]} { + tk_dialog .error "Created File" "Created blank file `$AppendFile'" info 0 "OK" + } + } + + if {! [file writable $AppendFile]} { + tk_dialog .error Error "Can't write reminder file `$AppendFile'" error 0 Ok + exit 1 + } + + append CommandLine " $ReminderFile" + append PSCmd " $ReminderFile" + + # Get modification time of ReminderFile + set ReminderFileModTime -1 + catch { + set ReminderFileModTime [file mtime $ReminderFile] + } + + MonitorReminderFile + +# puts "CommandLine: $CommandLine" +} + +#--------------------------------------------------------------------------- +# MonitorReminderFile +# If Reminder File modtime changes, restart daemon +#--------------------------------------------------------------------------- +proc MonitorReminderFile {} { + global ReminderFileModTime ReminderFile + + if {$ReminderFileModTime < 0} { + # Could not stat file + return + } + + set mtime -1 + catch { + set mtime [file mtime $ReminderFile] + } + if {$mtime < 0} { + # Doh! + return + } + + # Run ourselves again + after 60000 MonitorReminderFile + + # Redraw calendar and restart daemon if needed + if {$ReminderFileModTime < $mtime} { + set ReminderFileModTime $mtime + ScheduleUpdateForChanges + } +} + +#*********************************************************************** +# %PROCEDURE: CalEntryOffset +# %ARGUMENTS: +# firstDay -- first day of month (0=Sunday, 6=Saturday) +# %RETURNS: +# Offset mapping day numbers (1-31) to window numbers (0-41) +# %DESCRIPTION: +# Computes offset from day number to window number +#*********************************************************************** +proc CalEntryOffset { firstDay } { + global MondayFirst + if {$MondayFirst} { + incr firstDay -1 + if {$firstDay < 0} { + set firstDay 6 + } + } + return [expr $firstDay-1] +} + +#*********************************************************************** +# %PROCEDURE: CreateCalFrame +# %ARGUMENTS: +# w -- name of frame window +# dayNames -- names of weekdays +# %RETURNS: +# Nothing +# %DESCRIPTION: +# Creates a frame holding a grid of labels and a grid of text entries +#*********************************************************************** +proc CreateCalFrame { w dayNames } { + # Figure out reasonable height for text frames + global SetFontsWorked + global Option + global MondayFirst + set h [winfo screenheight .] + if {$h <= 480} { + if {$SetFontsWorked} { + set h 3 + } else { + set h 2 + } + } elseif {$h <= 600} { + set h 4 + } else { + set h 5 + } + + frame $w -background $Option(LineColor) + for {set i 0} {$i < 7} {incr i} { + if {$MondayFirst} { + set index [expr ($i+1)%7] + } else { + set index $i + } + + label $w.day$i -bd 0 -text [lindex $dayNames $index] -justify center -font HeadingFont -foreground $Option(LabelColor) -background $Option(WinBackground) -highlightthickness 0 + grid configure $w.day$i -row 0 -column $i -sticky ew -padx 1 -pady 1 + } + for {set i 0} {$i < 6} {incr i} { + set n [expr $i*7] + for {set j 0} {$j < 7} {incr j} { + set f [expr $n+$j] + button $w.l$f -text "" -justify center -command "" -anchor $Option(DayAnchor) \ + -state disabled -relief flat -bd 0 -padx 0 -pady 0 -font HeadingFont -highlightthickness 1 + text $w.t$f -width 12 -height $h -bd 0 -spacing3 3 -wrap word -relief flat \ + -state disabled -takefocus 0 -cursor {} -font CalboxFont -foreground $Option(TextColor) -background $Option(BackgroundColor) \ + -highlightthickness 0 + frame $w.f$f -padx 0 -pady 0 -highlightthickness 0 -relief flat -bd 0 + $w.t$f tag bind TAGGED "EditTaggedReminder $w.t$f" + $w.t$f tag bind REM "FireEditor $w.t$f" + pack $w.l$f -in $w.f$f -side top -expand 0 -fill x + pack $w.t$f -in $w.f$f -side top -expand 1 -fill both + grid configure $w.f$f -row [expr $i+1] -column $j -sticky nsew -padx 1 -pady 1 + } + } + + for {set i 0} {$i < 7} {incr i} { + grid columnconfigure $w $i -weight 1 + } + for {set i 1} {$i < 7} {incr i} { + grid rowconfigure $w $i -weight 1 + } +} + +#*********************************************************************** +# %PROCEDURE: ConfigureCalFrame +# %ARGUMENTS: +# w -- window name of calendar frame +# firstDay -- first weekday of month +# numDays -- number of days in month +# %RETURNS: +# Nothing +# %DESCRIPTION: +# Sets up button labels; configures text justification +#*********************************************************************** +proc ConfigureCalFrame { w firstDay numDays } { + global CurMonth CurYear TodayMonth TodayYear TodayDay + global tk_version Option + + CreateMoonWindows + set offset [CalEntryOffset $firstDay] + set first [expr $offset+1] + set last [expr $offset+$numDays] + + for {set i 0} {$i < $first} {incr i} { + grid $w.f$i + pack $w.l$i -in $w.f$i -side top -expand 0 -fill x + pack $w.t$i -in $w.f$i -side top -expand 1 -fill both + raise $w.l$i + raise $w.t$i + $w.l$i configure -text "" -command "" -state normal -relief flat -foreground $Option(LabelColor) -background $Option(WinBackground) -highlightcolor $Option(LineColor) -highlightbackground $Option(WinBackground) + $w.l$i configure -state disabled + balloon_add_help $w.l$i "" + $w.t$i configure -relief flat -takefocus 0 -state normal -background $Option(WinBackground) + $w.t$i delete 1.0 end + foreach t [$w.t$i tag names] { + $w.t$i tag delete $t + } + $w.t$i tag bind TAGGED "EditTaggedReminder $w.t$i" + $w.t$i tag bind REM "FireEditor $w.t$i" + $w.t$i configure -state disabled -takefocus 0 + } + for {set i $first} {$i <= $last} {incr i} { + set row [expr ($i/7)+1] + grid $w.f$i + grid rowconfigure $w $row -weight 1 + pack $w.l$i -in $w.f$i -side top -expand 0 -fill x + pack $w.t$i -in $w.f$i -side top -expand 1 -fill both + raise $w.l$i + raise $w.t$i + set d [expr $i-$first+1] + $w.l$i configure -text $d -state normal -relief flat \ + -command "ModifyDay $d $firstDay" -foreground $Option(LabelColor) -background $Option(WinBackground) -highlightcolor $Option(LineColor) -highlightbackground $Option(WinBackground) + balloon_add_help $w.l$i "Add a reminder..." + $w.t$i configure -relief sunken -takefocus 1 -state normal -foreground $Option(TextColor) -background $Option(BackgroundColor) + $w.t$i delete 1.0 end + foreach t [$w.t$i tag names] { + $w.t$i tag delete $t + } + $w.t$i tag bind TAGGED "EditTaggedReminder $w.t$i" + $w.t$i tag bind REM "FireEditor $w.t$i" + $w.t$i configure -state disabled -takefocus 0 + } + set forgetIt 0 + for {set i [expr $last+1]} {$i < 42} {incr i} { + if {$i%7 == 0} { + set forgetIt 1 + } + set row [expr ($i/7)+1] + if {$forgetIt} { + grid remove $w.f$i + grid rowconfigure $w $row -weight 0 + grid rowconfigure $w [expr $row+1] -weight 0 + } else { + grid $w.f$i + pack $w.l$i -in $w.f$i -side top -expand 0 -fill x + pack $w.t$i -in $w.f$i -side top -expand 1 -fill both + raise $w.l$i + raise $w.t$i + grid rowconfigure $w $row -weight 1 + } + $w.l$i configure -text "" -command "" -state normal -relief flat -foreground $Option(LabelColor) -background $Option(WinBackground) -highlightcolor $Option(LineColor) -highlightbackground $Option(WinBackground) + $w.l$i configure -state disabled + balloon_add_help $w.l$i "" + $w.t$i configure -relief flat -takefocus 0 -state normal -background $Option(WinBackground) + $w.t$i delete 1.0 end + foreach t [$w.t$i tag names] { + $w.t$i tag delete $t + } + $w.t$i tag bind TAGGED "EditTaggedReminder $w.t$i" + $w.t$i tag bind REM "FireEditor $w.t$i" + $w.t$i configure -state disabled -takefocus 0 + } + if { $CurMonth == $TodayMonth && $CurYear == $TodayYear } { + set n [expr $TodayDay + $offset] + $w.l$n configure -background $Option(TodayColor) + } +} + +proc DoQueue {} { + global DaemonFile + puts $DaemonFile "JSONQUEUE" + flush $DaemonFile +} + +#--------------------------------------------------------------------------- +# CreateCalWindow -- create the calendar window. +# Arguments: +# dayNames -- names of weekdays in current language {Sun .. Sat} +#--------------------------------------------------------------------------- +proc CreateCalWindow { dayNames } { + global Option + frame .h -background $Option(LineColor) + label .h.title -text "" -justify center -pady 2 -bd 0 -relief flat -font HeadingFont -background $Option(WinBackground) -foreground $Option(LabelColor) + pack .h.title -side top -fill x -pady 1 -padx 1 + pack .h -side top -expand 0 -fill x + . configure -background $Option(LineColor) + CreateCalFrame .cal $dayNames + + frame .b -background $Option(LineColor) + button .b.prev -text "\u2b9c" -command {MoveMonth -1} -bd 0 -foreground $Option(LabelColor) -background $Option(WinBackground) -highlightthickness 1 -highlightcolor $Option(LineColor) -highlightbackground $Option(WinBackground) + balloon_add_help .b.prev "Go to previous month" + button .b.this -text {Today} -command {ThisMonth} -bd 0 -foreground $Option(LabelColor) -background $Option(WinBackground) -highlightthickness 1 -highlightcolor $Option(LineColor) -highlightbackground $Option(WinBackground) + balloon_add_help .b.this "Go to this month" + button .b.next -text "\u2b9e" -command {MoveMonth 1} -bd 0 -foreground $Option(LabelColor) -background $Option(WinBackground) -highlightthickness 1 -highlightcolor $Option(LineColor) -highlightbackground $Option(WinBackground) + balloon_add_help .b.next "Go to next month" + button .b.goto -text {Go To Date...} -command {GotoDialog} -bd 0 -foreground $Option(LabelColor) -background $Option(WinBackground) -highlightthickness 1 -highlightcolor $Option(LineColor) -highlightbackground $Option(WinBackground) + balloon_add_help .b.goto "Go to a specific date" + button .b.print -text {Print...} -command {DoPrint} -bd 0 -foreground $Option(LabelColor) -background $Option(WinBackground) -highlightthickness 1 -highlightcolor $Option(LineColor) -highlightbackground $Option(WinBackground) + balloon_add_help .b.print "Print a PostScript or PDF calendar" + button .b.options -text {Options...} -command EditOptions -bd 0 -foreground $Option(LabelColor) -background $Option(WinBackground) -highlightthickness 1 -highlightcolor $Option(LineColor) -highlightbackground $Option(WinBackground) + balloon_add_help .b.options "Set TkRemind options" + button .b.queue -text {Queue...} -command {DoQueue} -bd 0 -foreground $Option(LabelColor) -background $Option(WinBackground) -highlightthickness 1 -highlightcolor $Option(LineColor) -highlightbackground $Option(WinBackground) + balloon_add_help .b.queue "See the queue of pending reminders (debugging purposes only)" + button .b.quit -text {Quit} -command {Quit} -bd 0 -foreground $Option(LabelColor) -background $Option(WinBackground) -highlightthickness 1 -highlightcolor $Option(LineColor) -highlightbackground $Option(WinBackground) + balloon_add_help .b.quit "Quit TkRemind" + label .b.status -text "" -width 25 -relief flat -bd 0 -foreground $Option(LabelColor) -background $Option(WinBackground) -highlightthickness 0 + label .b.nqueued -text "" -width 20 -relief flat -bd 0 -foreground $Option(LabelColor) -background $Option(WinBackground) -highlightthickness 0 + pack .b.prev .b.this .b.next .b.goto .b.print .b.options .b.queue .b.quit -side left -fill both -padx 1 + pack .b.status -side left -fill both -expand 1 -padx 1 + pack .b.nqueued -side left -fill both -padx 1 + pack .b -side bottom -fill x -expand 0 -pady 1 + pack .cal -side top -fill both -expand 1 + wm title . "TkRemind" + wm iconname . "" + wm protocol . WM_DELETE_WINDOW Quit + wm deiconify . + bind . Quit + bind . ".b.prev flash; .b.prev invoke" + bind . ".b.next flash; .b.next invoke" + bind . ".b.prev flash; .b.prev invoke" + bind . ".b.next flash; .b.next invoke" + bind . ".b.this flash; .b.this invoke" + + . configure -background $Option(WinBackground) + if {$Option(StartIconified)} { + wm iconify . + } + update + grid propagate .cal 0 +} + +#*********************************************************************** +# %PROCEDURE: EditOptions +# %ARGUMENTS: +# None +# %RETURNS: +# Nothing +# %DESCRIPTION: +# Lets user edit options +#*********************************************************************** +proc EditOptions {} { + global Option tmpOpt + + # Make a working copy of current option set + foreach name [array names Option] { + set tmpOpt($name) $Option($name) + } + + set w .opt + catch { destroy $w } + toplevel $w + wm title $w "TkRemind Options" + wm iconname $w "Options" + frame $w.f + frame $w.b + pack $w.f -side top -expand 1 -fill both + pack $w.b -side top -expand 0 -fill x + + # Start iconified + checkbutton $w.startIconified -text "Start up Iconified" \ + -anchor w -justify left \ + -variable tmpOpt(StartIconified) + + # Show today's reminders on startup + checkbutton $w.showTodays -text "Show Today's Reminders on Startup" \ + -anchor w -justify left \ + -variable tmpOpt(ShowTodaysReminders) + + # Confirm quit + checkbutton $w.confirmQuit -text "Confirm Quit" -anchor w -justify left \ + -variable tmpOpt(ConfirmQuit) + + # Bring down reminder windows after one minute + checkbutton $w.bringDown \ + -text "Automatically close pop-up reminders after a minute" \ + -anchor w -justify left -variable tmpOpt(AutoClose) + + # Ring bell when popping up reminder + checkbutton $w.ring -text "Beep terminal when popping up a reminder" \ + -anchor w -justify left -variable tmpOpt(RingBell) + + checkbutton $w.deic -text "Deiconify calendar window when popping up a reminder" \ + -anchor w -justify left -variable tmpOpt(Deiconify) + + # Run command when popping up reminder + frame $w.rf + label $w.rl -text "Run command when popping up reminder:" -anchor w \ + -justify left + entry $w.cmd -width 30 + pack $w.rl -in $w.rf -side left -expand 0 -fill none + pack $w.cmd -in $w.rf -side left -expand 1 -fill x + $w.cmd insert 0 $tmpOpt(RunCmd) + + frame $w.sep3 -bd 1 -relief sunken + # E-mail reminder if popup not dismissed + frame $w.eml + label $w.lab_email_address -text "E-mail reminders here if popup not dismissed:" -anchor w -justify left + entry $w.email_address -width 30 + pack $w.lab_email_address -in $w.eml -side left -expand 0 -fill none + pack $w.email_address -in $w.eml -side left -expand 1 -fill x + $w.email_address insert 0 $tmpOpt(MailAddr) + + frame $w.fsmtp + label $w.lab_smtp -text "Name or IP address of SMTP server:" -anchor w -justify left + entry $w.smtp -width 30 + pack $w.lab_smtp -in $w.fsmtp -side left -expand 0 -fill none + pack $w.smtp -in $w.fsmtp -side left -expand 1 -fill x + $w.smtp insert 0 $tmpOpt(SMTPServer) + + # Editor + frame $w.ef + label $w.el -text "Text Editor:" -anchor w -justify left + entry $w.editor -width 30 + pack $w.el -in $w.ef -side left -expand 0 -fill none + pack $w.editor -in $w.ef -side left -expand 1 -fill x + $w.editor insert 0 $tmpOpt(Editor) + + # extra args + frame $w.eaf + label $w.eal -text "Extra Arguments for Remind:" -anchor w -justify left + entry $w.extraargs -width 30 + pack $w.eal -in $w.eaf -side left -expand 0 -fill none + pack $w.extraargs -in $w.eaf -side left -expand 1 -fill x + $w.extraargs insert 0 $tmpOpt(ExtraRemindArgs) + + # Fonts + frame $w.fframe + button $w.font -text "Change entry font..." -command "ChooseCalboxFont" + button $w.hfont -text "Change heading font..." -command "ChooseHeadingFont" + pack $w.font $w.hfont -in $w.fframe -side left -expand 1 -fill x + + # Colors + frame $w.colors1 + label $w.textcolor -text "Text Color:" + button $w.btextcolor -background $Option(TextColor) -command [list PickColor TextColor $w.btextcolor] -text ... + label $w.bgcolor -text " Background color:" + button $w.bbgcolor -background $Option(BackgroundColor) -command [list PickColor BackgroundColor $w.bbgcolor] -text ... + + label $w.tbgcolor -text "Color for highlighting \"today\":" + button $w.tbbgcolor -background $Option(TodayColor) -command [list PickColor TodayColor $w.tbbgcolor] -text ... + + label $w.gridcolor -text " Gridline color:" + button $w.gridbcolor -background $Option(LineColor) -command [list PickColor LineColor $w.gridbcolor] -text ... + + grid $w.textcolor $w.btextcolor $w.bgcolor $w.bbgcolor -in $w.colors1 + grid $w.bgcolor $w.bbgcolor -in $w.colors1 + + label $w.headcolor -text "Heading Color:" + button $w.bheadcolor -background $Option(LabelColor) -command [list PickColor LabelColor $w.bheadcolor] -text ... + label $w.wincolor -text " Window color:" + button $w.bwincolor -background $Option(WinBackground) -command [list PickColor WinBackground $w.bwincolor] -text ... + grid $w.headcolor $w.bheadcolor $w.wincolor $w.bwincolor -in $w.colors1 + grid $w.tbgcolor $w.tbbgcolor $w.gridcolor $w.gridbcolor -in $w.colors1 + + grid columnconfigure $w.colors1 0 -weight 1 + grid columnconfigure $w.colors1 2 -weight 1 + frame $w.sep1 -bd 1 -relief sunken + frame $w.sep2 -bd 1 -relief sunken + + checkbutton $w.feed \ + -text "Feed popped-up reminder to command's standard input" \ + -variable tmpOpt(FeedReminder) -anchor w -justify left + + frame $w.ancFrame + label $w.ancLabel -text "Anchor day numbers to:" + radiobutton $w.ancLeft \ + -text "Left" \ + -variable tmpOpt(DayAnchor) -value "w" -anchor w -justify left + radiobutton $w.ancCenter \ + -text "Center" \ + -variable tmpOpt(DayAnchor) -value "center" -anchor w -justify left + radiobutton $w.ancRight \ + -text "Right" \ + -variable tmpOpt(DayAnchor) -value "e" -anchor w -justify left + pack $w.ancLabel $w.ancLeft $w.ancCenter $w.ancRight -in $w.ancFrame -side left + + pack $w.startIconified -in $w.f -side top -expand 0 -fill x + pack $w.showTodays -in $w.f -side top -expand 0 -fill x + pack $w.confirmQuit -in $w.f -side top -expand 0 -fill x + pack $w.bringDown -in $w.f -side top -expand 0 -fill x + pack $w.ring -in $w.f -side top -expand 0 -fill x + pack $w.deic -in $w.f -side top -expand 0 -fill x + pack $w.ancFrame -in $w.f -side top -expand 0 -fill x + pack $w.sep1 -in $w.f -side top -expand 0 -fill x -ipady 1 + pack $w.rf -in $w.f -side top -expand 0 -fill x + pack $w.feed -in $w.f -side top -expand 0 -fill x + pack $w.sep3 -in $w.f -side top -expand 0 -fill x -ipady 1 + pack $w.eml -in $w.f -side top -expand 0 -fill x + pack $w.fsmtp -in $w.f -side top -expand 0 -fill x + pack $w.ef -in $w.f -side top -expand 0 -fill x + pack $w.eaf -in $w.f -side top -expand 0 -fill x + pack $w.fframe -in $w.f -side top -expand 0 -fill x + pack $w.colors1 -in $w.f -side top -expand 0 -fill x + pack $w.sep2 -in $w.f -side top -expand 0 -fill x -ipady 1 + + button $w.default -text "Light Theme" -command [list set_default_colors $w] + button $w.dark -text "Dark Theme" -command [list set_dark_colors $w] + button $w.save -text "Save Options" -command "SaveOptions $w; destroy $w" + button $w.cancel -text "Cancel" -command "CancelOptions; destroy $w" + wm protocol $w WM_DELETE_WINDOW "CancelOptions; destroy $w" + pack $w.default $w.dark $w.save $w.cancel -in $w.b -side left -expand 0 -fill x + CenterWindow $w . +} + +proc CancelOptions { } { + global Option + font configure CalboxFont {*}$Option(CalboxFont) + font configure HeadingFont {*}$Option(HeadingFont) +} + +#*********************************************************************** +# %PROCEDURE: ApplyOptions +# %ARGUMENTS: +# w -- edit options window path +# %RETURNS: +# Nothing +# %DESCRIPTION: +# Applies options set in the edit options box. +#*********************************************************************** +proc ApplyOptions { w } { + global Option tmpOpt + + set tmpOpt(RunCmd) [$w.cmd get] + set tmpOpt(Editor) [$w.editor get] + set tmpOpt(ExtraRemindArgs) [$w.extraargs get] + set tmpOpt(MailAddr) [$w.email_address get] + set tmpOpt(SMTPServer) [$w.smtp get] + + set need_restart 0 + if {"$tmpOpt(ExtraRemindArgs)" != "$Option(ExtraRemindArgs)"} { + set need_restart 1 + } + # Copy working copy to real option set + foreach name [array names tmpOpt] { + set Option($name) $tmpOpt($name) + } + if {$need_restart != 0} { + FillCalWindow + StopBackgroundRemindDaemon + StartBackgroundRemindDaemon + } +} + +#*********************************************************************** +# %PROCEDURE: SaveOptions +# %ARGUMENTS: +# w -- edit options window path +# %RETURNS: +# Nothing +# %DESCRIPTION: +# Saves options in specified config file +#*********************************************************************** +proc SaveOptions { w } { + global Option OptDescr + ApplyOptions $w + WriteOptionsToFile + FillCalWindow + .h.title configure -background $Option(WinBackground) -foreground $Option(LabelColor) + for {set i 0} {$i < 7} {incr i} { + .cal.day$i configure -foreground $Option(LabelColor) -background $Option(WinBackground) + } + for {set i 0} {$i < 6} {incr i} { + set n [expr $i*7] + for {set j 0} {$j < 7} {incr j} { + set f [expr $n+$j] + .cal.l$f configure -anchor $Option(DayAnchor); + } + } + .b.status configure -foreground $Option(LabelColor) -background $Option(WinBackground) + .b.nqueued configure -foreground $Option(LabelColor) -background $Option(WinBackground) + .b configure -background $Option(WinBackground) + .b.prev configure -foreground $Option(LabelColor) -background $Option(WinBackground) + .b.this configure -foreground $Option(LabelColor) -background $Option(WinBackground) + .b.next configure -foreground $Option(LabelColor) -background $Option(WinBackground) + .b.goto configure -foreground $Option(LabelColor) -background $Option(WinBackground) + .b.print configure -foreground $Option(LabelColor) -background $Option(WinBackground) + .b.queue configure -foreground $Option(LabelColor) -background $Option(WinBackground) + .b.quit configure -foreground $Option(LabelColor) -background $Option(WinBackground) + .b.options configure -foreground $Option(LabelColor) -background $Option(WinBackground) + . configure -background $Option(LineColor); + .h configure -background $Option(LineColor); + .cal configure -background $Option(LineColor) + .b configure -background $Option(LineColor) +} + +proc WriteOptionsToFile {} { + global ConfigFile + global Option OptDescr + set problem [catch {set f [open "$ConfigFile.tmp" "w"]} err] + if {$problem} { + tk_dialog .error Error "Can't write $ConfigFile.tmp: $err" 0 OK + return + } + + puts $f "# TkRemind option file -- created automatically" + puts $f "# [clock format [clock seconds]]" + puts $f "# Format of each line is 'key value' where 'key'" + puts $f "# specifies the option name, and 'value' is a" + puts $f "# *legal Tcl list element* specifying the option value." + foreach name [lsort [array names Option]] { + puts $f "" + puts $f "# $OptDescr($name)" + puts $f [list $name $Option($name)] + } + puts $f "" + close $f + file rename -force "$ConfigFile.tmp" $ConfigFile +} + +#*********************************************************************** +# %PROCEDURE: LoadOptions +# %ARGUMENTS: +# None +# %RETURNS: +# Nothing +# %DESCRIPTION: +# Loads options from $ConfigFile +#*********************************************************************** +proc LoadOptions {} { + global Option ConfigFile + global MondayFirst + set problem [catch {set f [open "$ConfigFile" "r"]}] + if {$problem} { + return + } + while {[gets $f line] >= 0} { + if {[string match "#*" $line]} { + continue + } + if {$line == ""} { + continue + } + foreach {key val} $line {} + if {![info exists Option($key)]} { + puts stderr "Unknown option in $ConfigFile: $key" + continue + } + set Option($key) $val + } + close $f + if {[regexp -- {-m.*} $Option(ExtraRemindArgs)]} { + set MondayFirst 1 + } + font configure CalboxFont {*}$Option(CalboxFont) + font configure HeadingFont {*}$Option(HeadingFont) +} + + + +#*********************************************************************** +# %PROCEDURE: ConfigureCalWindow +# %ARGUMENTS: +# month -- month name +# year -- the year +# firstDay -- first day in month +# numDays -- number of days in month +# %RETURNS: +# Nothing +# %DESCRIPTION: +# Configures the calendar window for a month and year +# %PRECONDITIONS: +# Any preconditions +# %POSTCONDITIONS: +# Any postconditions +# %SIDE EFFECTS: +# Any side effects +#*********************************************************************** +proc ConfigureCalWindow { month year firstDay numDays } { + global Hostname + .h.title configure -text "$month $year" + wm title . "$month $year - TkRemind on $Hostname" + wm iconname . "$month $year" + ConfigureCalFrame .cal $firstDay $numDays +} + +#--------------------------------------------------------------------------- +# FillCalWindow -- Fill in the calendar for global CurMonth and CurYear. +#--------------------------------------------------------------------------- +proc FillCalWindow {} { + set FileName "" + set LineNo 0 + global DayNames CurYear CurMonth MonthNames CommandLine Option TagToObj RemindErrors MondayFirst + + array unset TagToObj + + Status "Firing off Remind..." + set_button_to_queue + set month [lindex $MonthNames $CurMonth] + + set cmd [regsub EXTRA $CommandLine $Option(ExtraRemindArgs)] + set file [open "$cmd $month $CurYear" r] + # Look for # rem2ps2 begin line + while { [gets $file line] >= 0 } { + if { [string compare "$line" "# rem2ps2 begin"] == 0 } { break } + } + + if { [string compare "$line" "# rem2ps2 begin"] != 0 } { + Status "Problem reading results from Remind!" + after 5000 DisplayTime + catch { close $file } + return 0 + } + + # Read month name, year, number of days in month, first weekday, Mon flag + gets $file line + regexp {^([^ ]*) ([0-9][0-9][0-9][0-9]) ([0-9][0-9]?) ([0-9]) ([0-9])} $line dummy monthName year daysInMonth firstWkday mondayFirst + + set monthName [regsub -all {_} $monthName " "] + # Get the day names + gets $file line + set DayNames {} + foreach day $line { + set day [regsub -all {_} $day " "]; + lappend DayNames $day + } + + ConfigureCalWindow $monthName $year $firstWkday $daysInMonth + + # Update the day names in the calendar window + for {set i 0} {$i < 7} {incr i} { + if {$MondayFirst} { + set index [expr ($i+1)%7] + } else { + set index $i + } + .cal.day$i configure -text [lindex $DayNames $index] + } + set offset [CalEntryOffset $firstWkday] + + while { [gets $file line] >= 0 } { + set fntag "x" + # Ignore unless begins with left brace + if { ! [string match "\{*" $line]} { + continue + } + + if {[catch {set obj [::json::json2dict $line]}]} { + continue + } + + if {[dict exists $obj filename]} { + set fname [dict get $obj filename] + # Don't make INCLUDECMD output editable + if {![string match "*|" $fname]} { + set fntag [string cat "FILE_" [dict get $obj lineno] "_" $fname] + } + } + + set date [dict get $obj date] + regexp {^([0-9][0-9][0-9][0-9]).([0-9][0-9]).([0-9][0-9])} $date all year month day + if {[dict exists $obj passthru]} { + set type [dict get $obj passthru] + } else { + set type "*" + } + if {[dict exist $obj tags]} { + set tag [dict get $obj tags] + } else { + set tag "*" + } + if {[dict exists $obj calendar_body]} { + set stuff [dict get $obj calendar_body] + } elseif {[dict exists $obj plain_body]} { + set stuff [dict get $obj plain_body] + } else { + set stuff [dict get $obj body] + } + set day [string trimleft $day 0] + set n [expr $day+$offset] + set month [string trimleft $month 0] + set extratags "" + switch -nocase -- $type { + "WEEK" { + set stuff [string trimleft $stuff] + set stuff [string trimright $stuff] + set offset [CalEntryOffset $firstWkday] + set label [expr $offset + $day] + .cal.l$label configure -text "$day $stuff" + continue + } + "SHADE" { + DoShadeSpecial $n [dict get $obj r] [dict get $obj g] [dict get $obj b] + continue + } + "MOON" { + DoMoonSpecial $n $stuff $fntag $day + continue + } + "COLOUR" - + "COLOR" { + set r [dict get $obj r] + set g [dict get $obj g] + set b [dict get $obj b] + if {$r > 255} { + set r 255 + } elseif {$r < 0} { + set r 0 + } + if {$g > 255} { + set g 255 + } elseif {$g < 0} { + set g 0 + } + if {$b > 255} { + set b 255 + } elseif {$b < 0} { + set b 0 + } + set color [format "%02X%02X%02X" $r $g $b] + set extratags "clr$color" + .cal.t$n configure -state normal + .cal.t$n tag configure $extratags -foreground "#$color" + .cal.t$n configure -state disabled -takefocus 0 + set stuff $stuff + set type "COLOR" + } + } + if { $type != "*" && $type != "COLOR" && $type != "COLOUR"} { + continue + } + .cal.t$n configure -state normal + if {[regexp {TKTAG([0-9]+)} $tag all tagno] && "$fntag" != "x"} { + .cal.t$n insert end [string trim $stuff] [list REM TAGGED "TKTAG$tagno" "date_$date" $extratags $fntag] + .cal.t$n tag bind "TKTAG$tagno" "TaggedEnter .cal.t$n" + .cal.t$n tag bind "TKTAG$tagno" "TaggedLeave .cal.t$n" + set TagToObj(TKTAG$tagno) $obj + } else { + if {"$fntag" == "x" } { + .cal.t$n insert end [string trim $stuff] [list REM $extratags] + } else { + .cal.t$n insert end [string trim $stuff] [list REM $extratags $fntag] + .cal.t$n tag bind $fntag "EditableEnter .cal.t$n" + .cal.t$n tag bind $fntag "EditableLeave .cal.t$n" + .cal.t$n tag bind $fntag "FireEditor .cal.t$n" + } + } + .cal.t$n insert end "\n" + .cal.t$n configure -state disabled -takefocus 0 + + } + set problem [catch { close $file } errmsg] + if {$problem} { + set RemindErrors [unique_lines $errmsg] + set_button_to_errors + } + DisplayTime +} + +proc unique_lines { s } { + set l [split $s "\n"] + foreach line $l { + if {"$line" != ""} { + dict set d $line 1 + } + } + return [join [dict keys $d] "\n"] +} + +#--------------------------------------------------------------------------- +# MoveMonth -- move by +1 or -1 months +# Arguments: +# delta -- +1 or -1 -- months to move. +#--------------------------------------------------------------------------- +proc MoveMonth {delta} { + global CurMonth CurYear + set CurMonth [expr $CurMonth + $delta] + if {$CurMonth < 0} { + set CurMonth 11 + set CurYear [expr $CurYear-1] + } + + if {$CurMonth > 11} { + set CurMonth 0 + incr CurYear + } + + FillCalWindow +} + +#--------------------------------------------------------------------------- +# ThisMonth -- move to current month +#--------------------------------------------------------------------------- +proc ThisMonth {} { + global CurMonth CurYear TodayMonth TodayYear + + # Do nothing if already there + if { $CurMonth == $TodayMonth && $CurYear == $TodayYear } { + return 0; + } + set CurMonth $TodayMonth + set CurYear $TodayYear + FillCalWindow +} + +#--------------------------------------------------------------------------- +# Status -- set status string +# Arguments: +# stuff -- what to set string to. +#--------------------------------------------------------------------------- +proc Status { stuff } { + catch { .b.status configure -text $stuff } + update idletasks +} + +#--------------------------------------------------------------------------- +# DoPrint -- print a calendar +# Arguments: +# None +#--------------------------------------------------------------------------- +proc DoPrint {} { + global Rem2PS Rem2PDF HaveRem2PDF PSCmd Option PrintStatus + global CurMonth CurYear MonthNames + + catch {destroy .p} + toplevel .p + wm title .p "TkRemind Print..." + wm iconname .p "Print..." + frame .p.f1 -relief sunken -bd 2 + frame .p.f11 + frame .p.f12 + frame .p.f2 -relief sunken -bd 2 + frame .p.f2a -relief sunken -bd 2 + frame .p.f3 -relief sunken -bd 2 + frame .p.f3a -relief sunken -bd 2 + frame .p.f4 + + radiobutton .p.tofile -text "To file: " -variable Option(PrintDest) -value file + entry .p.filename + button .p.browse -text "Browse..." -command PrintFileBrowse + radiobutton .p.tocmd -text "To command: " -variable Option(PrintDest) -value command + entry .p.command + .p.command insert end "lpr" + + if { $HaveRem2PDF } { + frame .p.ff -relief sunken -bd 2 + label .p.format -text "Output Format:" + radiobutton .p.pdf -text "PDF" -variable Option(PrintFormat) -value pdf + radiobutton .p.ps -text "PostScript" -variable Option(PrintFormat) -value ps + } + + label .p.size -text "Paper Size:" + radiobutton .p.letter -text "Letter" -variable Option(PrintSize) -value letter + radiobutton .p.a4 -text "A4" -variable Option(PrintSize) -value a4 + + label .p.margin -text "Margins:" + radiobutton .p.24pt -text "24pt margins" -variable Option(PrintMargins) -value 24pt + radiobutton .p.36pt -text "36pt margins" -variable Option(PrintMargins) -value 36pt + radiobutton .p.48pt -text "48pt margins" -variable Option(PrintMargins) -value 48pt + + label .p.orient -text "Orientation:" + radiobutton .p.landscape -text "Landscape" -variable Option(PrintOrient) -value landscape + radiobutton .p.portrait -text "Portrait" -variable Option(PrintOrient) -value portrait + + checkbutton .p.fill -text "Fill page" -variable Option(PrintFill) + checkbutton .p.right -text "Day numbers at top-right" -variable Option(PrintDaysRight) + checkbutton .p.encoding -text "ISO 8859-1 PostScript encoding" -variable Option(PrintEncoding) + checkbutton .p.calendars -text "Print small calendars" -variable Option(PrintSmallCalendars) + + button .p.print -text "Print" -command {set PrintStatus print} + button .p.cancel -text "Cancel" -command {set PrintStatus cancel} + + if {$HaveRem2PDF} { + pack .p.f1 .p.ff .p.f2 .p.f2a .p.f3 .p.f3a \ + -side top -fill both -expand 1 -anchor w + } else { + pack .p.f1 .p.f2 .p.f2a .p.f3 .p.f3a \ + -side top -fill both -expand 1 -anchor w + } + pack .p.fill .p.right .p.encoding .p.calendars -in .p.f3a \ + -side top -anchor w -fill none -expand 0 + pack .p.f4 -side top -fill both -expand 1 -anchor w + pack .p.f11 .p.f12 -in .p.f1 -side top -fill none -expand 0 -anchor w + pack .p.tofile .p.filename .p.browse -in .p.f11 -side left -fill none -expand 0 -anchor w + pack .p.tocmd .p.command -in .p.f12 -side left -fill none -expand 0 -anchor w + if { $HaveRem2PDF } { + pack .p.format .p.pdf .p.ps -in .p.ff -side top -fill none -expand 0 -anchor w + } + pack .p.size .p.letter .p.a4 -in .p.f2 -side top -fill none -expand 0 -anchor w + pack .p.margin .p.24pt .p.36pt .p.48pt -in .p.f2a -side top -anchor w -fill none -expand 0 + pack .p.orient .p.landscape .p.portrait -in .p.f3 -side top -fill none -expand 0 -anchor w + pack .p.print .p.cancel -in .p.f4 -side left -fill none -expand 0 + + bind .p ".p.cancel flash; .p.cancel invoke" + bind .p ".p.print flash; .p.print invoke" + set PrintStatus 2 + CenterWindow .p . + tkwait visibility .p + set oldFocus [focus] + focus .p.filename + grab .p + tkwait variable PrintStatus + catch {focus $oldFocus} + set fname [.p.filename get] + set cmd [.p.command get] + destroy .p + if {$PrintStatus == "cancel"} { + return + } + WriteOptionsToFile + if {$Option(PrintDest) == "file"} { + if {$fname == ""} { + tk_dialog .error Error "No filename specified" error 0 Ok + return + } + if {[file isdirectory $fname]} { + tk_dialog .error Error "$fname is a directory" error 0 Ok + return + } + if {[file readable $fname]} { + set ans [tk_dialog .error Overwrite? "Overwrite $fname?" question 0 No Yes] + if {$ans == 0} { + return + } + } + set fname "> $fname" + } else { + set fname "| $cmd" + } + + if {$HaveRem2PDF && $Option(PrintFormat) == "pdf"} { + set p [regsub EXTRA $PSCmd "-itkpdf=1 $Option(ExtraRemindArgs)"] + set cmd "$p 1 [lindex $MonthNames $CurMonth] $CurYear | $Rem2PDF" + } else { + set p [regsub EXTRA $PSCmd $Option(ExtraRemindArgs)] + set cmd "$p 1 [lindex $MonthNames $CurMonth] $CurYear | $Rem2PS" + set Option(PrintFormat) ps + } + + if {$Option(PrintSize) == "letter"} { + if {$Option(PrintFormat) == "ps"} { + append cmd " -m Letter" + } else { + append cmd " --media=Letter" + } + } else { + if {$Option(PrintFormat) == "ps"} { + append cmd " -m A4" + } else { + append cmd " --media=A4" + } + } + + if {$Option(PrintMargins) == "24pt"} { + if {$Option(PrintFormat) == "ps"} { + append cmd " -or 24 -ol 24 -ot 24 -ob 24" + } else { + append cmd " --margin-right=24 --margin-left=24 --margin-top=24 --margin-bottom=24" + } + } elseif {$Option(PrintMargins) == "36pt"} { + if {$Option(PrintFormat) == "ps"} { + append cmd " -or 36 -ol 36 -ot 36 -ob 36" + } else { + append cmd " --margin-right=36 --margin-left=36 --margin-top=36 --margin-bottom=36" + } + } else { + if {$Option(PrintFormat) == "ps"} { + append cmd " -or 48 -ol 48 -ot 48 -ob 48" + } else { + append cmd " --margin-right=48 --margin-left=48 --margin-top=48 --margin-bottom=48" + } + } + + if {$Option(PrintOrient) == "landscape"} { + append cmd " -l" + } + + if {$Option(PrintFill)} { + append cmd " -e" + } + + if {!$Option(PrintDaysRight)} { + append cmd " -x" + } + if {$Option(PrintEncoding)} { + if {$Option(PrintFormat) == "ps"} { + append cmd " -i" + } + } + + if {$Option(PrintSmallCalendars)} { + append cmd " -c3" + } else { + append cmd " -c0" + } + + append cmd " $fname" + Status "Printing..." + if {[catch {eval "exec $cmd"} err]} { + tk_dialog .error Error "Error during printing: $err" error 0 Ok + } + DisplayTime +} + +#--------------------------------------------------------------------------- +# PrintFileBrowse -- browse for a filename for Print dialog +# Arguments: none +#--------------------------------------------------------------------------- +proc PrintFileBrowse {} { + set ans [BrowseForFile .filebrowse "Print to file..." "Ok" 0 "*.ps"] + if {$ans != ""} { + .p.filename delete 0 end + .p.filename insert end $ans + .p.filename icursor end + .p.filename xview end + } +} + +#--------------------------------------------------------------------------- +# GotoDialog -- Do the "Goto..." dialog +#--------------------------------------------------------------------------- +proc GotoDialog {} { + global CurMonth MonthNames CurYear + catch { destroy .g } + + set month [lindex $MonthNames $CurMonth] + toplevel .g + wm title .g "Go To Date" + menubutton .g.mon -text "$month" -menu .g.mon.menu -relief raised + balloon_add_help .g.mon "Select a month" + menu .g.mon.menu -tearoff 0 + + foreach m $MonthNames { + .g.mon.menu add command -label $m -command ".g.mon configure -text $m" + } + + frame .g.y + label .g.y.lab -text "Year: " + entry .g.y.e -width 4 + balloon_add_help .g.y.e "Enter a year" + .g.y.e insert end $CurYear + bind .g.y.e ".g.b.go flash; .g.b.go invoke" + frame .g.b + button .g.b.go -text "Go" -command {DoGoto} + balloon_add_help .g.b.go "Go to specified month and year" + button .g.b.cancel -text "Cancel" -command { destroy .g } + pack .g.b.go .g.b.cancel -expand 1 -fill x -side left + pack .g.mon -fill x -expand 1 + + pack .g.y.lab -side left + pack .g.y.e -side left -fill x -expand 1 + pack .g.y -expand 1 -fill x + pack .g.b -expand 1 -fill x + bind .g ".g.b.cancel flash; .g.b.cancel invoke" + CenterWindow .g . + set oldFocus [focus] + grab .g + focus .g.y.e + tkwait window .g + catch {focus $oldFocus} +} + +#--------------------------------------------------------------------------- +# DoGoto -- go to specified date +#--------------------------------------------------------------------------- +proc DoGoto {} { + global CurYear CurMonth MonthNames + set year [.g.y.e get] + if { ! [regexp {^[0-9]+$} $year] } { + tk_dialog .error Error {Illegal year specified (1990-5990)} error 0 Ok + return + } + if { $year < 1990 || $year > 5990 } { + tk_dialog .error Error {Illegal year specified (1990-5990)} error 0 Ok + return + } + set month [lsearch -exact $MonthNames [.g.mon cget -text]] + set CurMonth $month + set CurYear $year + destroy .g + FillCalWindow +} + +#--------------------------------------------------------------------------- +# Quit -- handle the Quit button +#--------------------------------------------------------------------------- +proc Quit {} { + global Option + global InotifyFP + if { !$Option(ConfirmQuit) } { + destroy . + StopBackgroundRemindDaemon + catch { exec kill [pid $InotifyFP] } + catch { close $InotifyFP } + exit 0 + } + if { [tk_dialog .question "Confirm..." {Really quit?} question 0 No Yes] } { + destroy . + StopBackgroundRemindDaemon + catch { exec kill [pid $InotifyFP] } + catch { close $InotifyFP } + exit 0 + } +} + +#--------------------------------------------------------------------------- +# CreateModifyDialog -- create dialog for adding a reminder +# Arguments: +# w -- path of parent window +# day -- day number of month +# firstDay -- day number of first day of month +# args -- buttons to add to bottom frame. First sets result to 1, next +# to 2, and so on. FIRST BUTTON MUST BE "Cancel" +#--------------------------------------------------------------------------- +proc CreateModifyDialog {w day firstDay args} { + + # Set up: Year, Month, Day, WeekdayName + global CurYear CurMonth EnglishDayNames MonthNames OptionType SkipType + global ModifyDialogResult TwentyFourHourMode + + set OptionType 1 + set SkipType 1 + + set year $CurYear + set month [lindex $MonthNames $CurMonth] + set wkday [lindex $EnglishDayNames [expr ($day+$firstDay-1) % 7]] + + frame $w.o -bd 4 -relief ridge + frame $w.o1 -bd 4 + frame $w.o2 -bd 4 + frame $w.o3 -bd 4 + frame $w.exp -bd 4 + frame $w.adv -bd 4 + frame $w.weekend -bd 4 + frame $w.durationbox -bd 4 + frame $w.time -bd 4 + frame $w.hol -bd 4 + frame $w.msg + frame $w.buttons + pack $w.o1 $w.o2 $w.o3 -side top -anchor w -in $w.o + pack $w.o $w.exp $w.adv $w.weekend $w.time $w.durationbox $w.hol $w.msg -side top -anchor w -pady 4 -expand 1 -fill both + pack $w.buttons -side top -anchor w -pady 4 -expand 1 -fill x + + # TYPE 1 REMINDER + radiobutton $w.type1 -variable OptionType -value 1 + menubutton $w.day1 -text $day -relief raised -menu $w.day1.menu + balloon_add_help $w.day1 "Select a day" + CreateDayMenu $w.day1 + menubutton $w.mon1 -text $month -relief raised -menu $w.mon1.menu + balloon_add_help $w.mon1 "Select a month" + CreateMonthMenu $w.mon1 + menubutton $w.year1 -text $year -relief raised -menu $w.year1.menu + balloon_add_help $w.year1 "Select a year" + CreateYearMenu $w.year1 + checkbutton $w.repbut -text "and repeating every" + balloon_add_help $w.repbut "Select to enable a recurring reminder" + $w.repbut deselect + menubutton $w.repdays -text 1 -relief raised -menu $w.repdays.menu + balloon_add_help $w.repdays "Select the repeat interval in days" + CreateDayMenu $w.repdays 1 28 0 + label $w.label1a -text "day(s) thereafter" + pack $w.type1 $w.day1 $w.mon1 $w.year1 $w.repbut $w.repbut $w.repdays $w.label1a -side left -anchor w -in $w.o1 + + # TYPE 2 REMINDER + radiobutton $w.type2 -variable OptionType -value 2 + label $w.label2a -text First + menubutton $w.wkday2 -text $wkday -relief raised -menu $w.wkday2.menu + balloon_add_help $w.wkday2 "Select a day of the week" + CreateWeekdayMenu $w.wkday2 + label $w.label2b -text "on or after" + menubutton $w.day2 -text $day -relief raised -menu $w.day2.menu + balloon_add_help $w.day2 "Select a day" + CreateDayMenu $w.day2 1 31 0 + menubutton $w.mon2 -text $month -relief raised -menu $w.mon2.menu + balloon_add_help $w.mon2 "Select a month" + CreateMonthMenu $w.mon2 + menubutton $w.year2 -text $year -relief raised -menu $w.year2.menu + balloon_add_help $w.year2 "Select a year" + CreateYearMenu $w.year2 + pack $w.type2 $w.label2a $w.wkday2 $w.label2b $w.day2 $w.mon2 $w.year2 -side left -anchor w -in $w.o2 + + # TYPE 3 REMINDER + if { $day <= 7 } { + set which "First" + } elseif {$day <= 14} { + set which "Second" + } elseif {$day <= 21} { + set which "Third" + } elseif {$day <= 28} { + set which "Fourth" + } else { + set which "Last" + } + radiobutton $w.type3 -variable OptionType -value 3 + menubutton $w.ordinal -text $which -relief raised -menu $w.ordinal.menu + balloon_add_help $w.ordinal "Select the first, second, etc. weekday in a month" + menu $w.ordinal.menu -tearoff 0 + $w.ordinal.menu add command -label "First" -command "$w.ordinal configure -text First" + $w.ordinal.menu add command -label "Second" -command "$w.ordinal configure -text Second" + $w.ordinal.menu add command -label "Third" -command "$w.ordinal configure -text Third" + $w.ordinal.menu add command -label "Fourth" -command "$w.ordinal configure -text Fourth" + $w.ordinal.menu add command -label "Last" -command "$w.ordinal configure -text Last" + $w.ordinal.menu add command -label "Every" -command "$w.ordinal configure -text Every" + menubutton $w.wkday3 -text $wkday -relief raised -menu $w.wkday3.menu + balloon_add_help $w.wkday3 "Select a day of the week" + CreateWeekdayMenu $w.wkday3 + label $w.label3 -text "in" + menubutton $w.mon3 -text $month -relief raised -menu $w.mon3.menu + balloon_add_help $w.mon3 "Select a month" + CreateMonthMenu $w.mon3 + menubutton $w.year3 -text $year -relief raised -menu $w.year3.menu + balloon_add_help $w.year3 "Select a year" + CreateYearMenu $w.year3 + pack $w.type3 $w.ordinal $w.wkday3 $w.label3 $w.mon3 $w.year3 -side left -anchor w -in $w.o3 + + # EXPIRY DATE + checkbutton $w.expbut -text "Expire after" + balloon_add_help $w.expbut "Select to enable an expiry date" + $w.expbut deselect + menubutton $w.expday -text $day -relief raised -menu $w.expday.menu + balloon_add_help $w.expday "Select expiry day" + CreateDayMenu $w.expday 1 31 0 + menubutton $w.expmon -text $month -relief raised -menu $w.expmon.menu + balloon_add_help $w.expmon "Select expiry month" + CreateMonthMenu $w.expmon 0 + menubutton $w.expyear -text $year -relief raised -menu $w.expyear.menu + balloon_add_help $w.expyear "Select expiry year" + CreateYearMenu $w.expyear 0 + + pack $w.expbut $w.expday $w.expmon $w.expyear -side left -anchor w -in $w.exp + + # ADVANCE NOTICE + checkbutton $w.advbut -text "Issue" + balloon_add_help $w.advbut "Select to enable advance notification" + $w.advbut deselect + menubutton $w.advdays -text 3 -menu $w.advdays.menu -relief raised + balloon_add_help $w.advdays "Select number of days of advance warning" + CreateDayMenu $w.advdays 1 10 0 + label $w.advlab -text "day(s) in advance" + checkbutton $w.advcount -text "not counting holidays/weekend" + balloon_add_help $w.advcount "Select to avoid counting holidays/weekend as in advance warning days" + $w.advcount select + pack $w.advbut $w.advdays $w.advlab $w.advcount -side left -anchor w -in $w.adv + + # WEEKEND + label $w.weeklab -text "Weekend is: " + pack $w.weeklab -side left -anchor w -in $w.weekend + foreach d $EnglishDayNames { + checkbutton $w.d$d -text $d + balloon_add_help $w.d$d "Select to include $d in the definition of \"Weekend\"" + $w.d$d deselect + pack $w.d$d -side left -anchor w -in $w.weekend + } + $w.dSaturday select + $w.dSunday select + + # TIMED REMINDER + checkbutton $w.timebut -text "Timed reminder at" + balloon_add_help $w.timebut "Select if this event starts at a specific time" + $w.timebut deselect + menubutton $w.timehour -text "12" -menu $w.timehour.menu -relief raised + balloon_add_help $w.timehour "Select the starting time's hour" + if {$TwentyFourHourMode} { + CreateDayMenu $w.timehour 0 23 0 + } else { + CreateDayMenu $w.timehour 1 12 0 + } + menubutton $w.timemin -text "00" -menu $w.timemin.menu -relief raised + balloon_add_help $w.timemin "Select the starting time's minute" + menu $w.timemin.menu -tearoff 0 + foreach i {00 05 10 15 20 25 30 35 40 45 50 55} { + $w.timemin.menu add command -label $i \ + -command "$w.timemin configure -text $i" + } + + if {!$TwentyFourHourMode} { + menubutton $w.ampm -text "PM" -menu $w.ampm.menu -relief raised + balloon_add_help $w.ampm "Select whether the time is AM or PM" + menu $w.ampm.menu -tearoff 0 + $w.ampm.menu add command -label "AM" -command "$w.ampm configure -text {AM}" + $w.ampm.menu add command -label "PM" -command "$w.ampm configure -text {PM}" + } + + checkbutton $w.timeadvbut -text "with" + balloon_add_help $w.timeadvbut "Select to be given advance warning prior to the start time" + $w.timeadvbut deselect + menubutton $w.timeadv -text "15" -menu $w.timeadv.menu -relief raised + balloon_add_help $w.timeadv "Select the number of minutes of advance warning" + menu $w.timeadv.menu -tearoff 0 + foreach i {5 10 15 30 45 60} { + $w.timeadv.menu add command -label $i -command "$w.timeadv configure -text $i" + } + label $w.timelab1 -text "minutes advance notice" + + checkbutton $w.timerepbut -text "repeated every" + balloon_add_help $w.timerepbut "Select to repeat the advance notice" + $w.timerepbut deselect + menubutton $w.timerep -text "5" -menu $w.timerep.menu -relief raised + balloon_add_help $w.timerep "Select how often to repeat the advance notice" + menu $w.timerep.menu -tearoff 0 + foreach i {3 5 10 15 30} { + $w.timerep.menu add command -label $i -command "$w.timerep configure -text $i" + } + label $w.timelab2 -text "minutes" + if {$TwentyFourHourMode} { + pack $w.timebut $w.timehour $w.timemin $w.timeadvbut $w.timeadv $w.timelab1 $w.timerepbut $w.timerep $w.timelab2 -side left -anchor w -in $w.time + } else { + pack $w.timebut $w.timehour $w.timemin $w.ampm $w.timeadvbut $w.timeadv $w.timelab1 $w.timerepbut $w.timerep $w.timelab2 -side left -anchor w -in $w.time + } + + # DURATION + checkbutton $w.durationbut -text "Duration" + balloon_add_help $w.durationbut "Select if this event has a specific duration" + $w.durationbut deselect + menubutton $w.durationh -text "1" -menu $w.durationh.menu -relief raised + balloon_add_help $w.durationh "Select how many hours the event lasts" + menu $w.durationh.menu -tearoff 0 + foreach i {0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24} { + $w.durationh.menu add command -label $i -command "$w.durationh configure -text $i" + } + label $w.durationcolon -text ":" + menubutton $w.durationm -text "00" -menu $w.durationm.menu -relief raised + balloon_add_help $w.durationm "Select how many minutes the event lasts (in addition to the hours)" + menu $w.durationm.menu -tearoff 0 + foreach i {00 15 30 45} { + $w.durationm.menu add command -label $i -command "$w.durationm configure -text $i" + } + pack $w.durationbut $w.durationh $w.durationcolon $w.durationm -side left -anchor w -in $w.durationbox + + # SKIP TYPE + label $w.labhol -text "On holidays or weekends:" + radiobutton $w.issue -variable SkipType -value 1 -text "Issue reminder as usual" + radiobutton $w.skip -variable SkipType -value 2 -text "Skip reminder" + radiobutton $w.before -variable SkipType -value 3 -text "Move reminder before holiday or weekend" + radiobutton $w.after -variable SkipType -value 4 -text "Move reminder after holiday or weekend" + pack $w.labhol $w.issue $w.skip $w.before $w.after -side top -anchor w -in $w.hol + + # TEXT ENTRY + label $w.msglab -text "Body:" + entry $w.entry + balloon_add_help $w.entry "Enter the text of the reminder" + pack $w.msglab -side left -anchor w -in $w.msg + pack $w.entry -side left -anchor w -expand 1 -fill x -in $w.msg + + # BUTTONS + set nbut 0 + foreach but $args { + incr nbut + button $w.but$nbut -text $but -command "set ModifyDialogResult $nbut" + pack $w.but$nbut -side left -anchor w -in $w.buttons -expand 1 -fill x + } + + bind $w "$w.but1 flash; $w.but1 invoke" + if {$nbut >= 2} { + bind $w.entry "$w.but2 flash; $w.but2 invoke" + } + set ModifyDialogResult 0 + + # Center the window on the root + CenterWindow $w . +} + +#*********************************************************************** +# %PROCEDURE: RemindDialogToOptions +# %ARGUMENTS: +# w -- dialog window +# %RETURNS: +# A list of flag/value pairs representing the current state of +# the "create reminder" dialog. +#*********************************************************************** +proc RemindDialogToOptions { w } { + global OptionType SkipType repbut expbut advbut advcount + global timebut timeadvbut timerepbut durationbut + global dSaturday dSunday dMonday dTuesday dWednesday dThursday dFriday + set ans {} + lappend ans "-global-OptionType" $OptionType + lappend ans "-global-SkipType" $SkipType + foreach win [winfo children $w] { + set winstem [winfo name $win] + switch -exact -- [winfo class $win] { + "Menubutton" { + lappend ans "-text-$winstem" [$win cget -text] + } + "Checkbutton" { + lappend ans "-global-$winstem" [eval set $winstem] + } + "Entry" { + lappend ans "-entry-$winstem" [string map -nocase {"\n" " "} [$win get]] + } + } + } + return $ans +} + +#*********************************************************************** +# %PROCEDURE: OptionsToRemindDialog +# %ARGUMENTS: +# w -- Remind dialog window +# opts -- option list set by RemindDialogToOptions +# %RETURNS: +# Nothing +# %DESCRIPTION: +# Sets parameters in the dialog box according to saved options. +#*********************************************************************** +proc OptionsToRemindDialog { w opts } { + global OptionType SkipType repbut expbut advbut advcount + global timebut timeadvbut timerepbut TwentyFourHourMode durationbut + global dSaturday dSunday dMonday dTuesday dWednesday dThursday dFriday + set hour "" + set ampm "" + foreach {flag value} $opts { + switch -glob -- $flag { + "-text-*" { + set win [string range $flag 6 end] + catch { $w.$win configure -text $value } + if {"$flag" == "-text-ampm"} { + set ampm $value + } elseif {"$flag" == "-text-timehour"} { + set hour $value + } + } + "-global-*" { + set win [string range $flag 8 end] + set $win $value + } + "-entry-*" { + set win [string range $flag 7 end] + $w.$win delete 0 end + $w.$win insert end $value + } + } + } + if {"$hour" != ""} { + if {$TwentyFourHourMode} { + if {"$ampm" != ""} { + if {"$ampm" == "PM" && $hour < 12} { + incr hour 12 + $w.timehour configure -text $hour + } + } + } else { + if {$hour > 12} { + incr hour -12 + $w.timehour configure -text $hour + $w.ampm configure -text "PM" + } else { + if {"$ampm" == ""} { + $w.ampm configure -text "AM" + } + } + } + } +} + +#--------------------------------------------------------------------------- +# CreateMonthMenu -- create a menu with all the months of the year +# Arguments: +# w -- menu button -- becomes parent of menu +# every -- if true, include an "every month" entry +#--------------------------------------------------------------------------- +proc CreateMonthMenu {w {every 1}} { + global MonthNames + menu $w.menu -tearoff 0 + + if {$every} { + $w.menu add command -label "every month" -command "$w configure -text {every month}" + } + + foreach month $MonthNames { + $w.menu add command -label $month -command "$w configure -text $month" + } +} + +#--------------------------------------------------------------------------- +# CreateWeekdayMenu -- create a menu with all the weekdays +# Arguments: +# w -- menu button -- becomes parent of menu +#--------------------------------------------------------------------------- +proc CreateWeekdayMenu {w} { + global EnglishDayNames + menu $w.menu -tearoff 0 + + foreach d $EnglishDayNames { + $w.menu add command -label $d -command "$w configure -text $d" + } + $w.menu add command -label "weekday" -command "$w configure -text weekday" +} + +#--------------------------------------------------------------------------- +# CreateDayMenu -- create a menu with entries 1-31 and possibly "every day" +# Arguments: +# w -- menu button -- becomes parent of menu +# min -- minimum day to start from. +# max -- maximum day to go up to +# every -- if true, include an "every day" entry +#--------------------------------------------------------------------------- +proc CreateDayMenu {w {min 1} {max 31} {every 1}} { + menu $w.menu -tearoff 0 + if {$every} { + $w.menu add command -label "every day" -command "$w configure -text {every day}" + } + set d $min + while { $d <= $max } { + $w.menu add command -label $d -command "$w configure -text $d" + incr d + } +} + +#--------------------------------------------------------------------------- +# CreateYearMenu -- create a menu with entries from this year to this year+10 +# and possibly "every year" +# Arguments: +# w -- menu button -- becomes parent of menu +# every -- if true, include an "every year" entry +#--------------------------------------------------------------------------- +proc CreateYearMenu {w {every 1}} { + menu $w.menu -tearoff 0 + if {$every} { + $w.menu add command -label "every year" -command "$w configure -text {every year}" + } + global CurYear + set d $CurYear + while { $d < [expr $CurYear + 11] } { + $w.menu add command -label $d -command "$w configure -text $d" + incr d + } +} + +#--------------------------------------------------------------------------- +# ModifyDay -- bring up dialog for adding reminder. +# Arguments: +# d -- which day to modify +# firstDay -- first weekday in month (0-6) +#--------------------------------------------------------------------------- +proc ModifyDay {d firstDay} { + global ModifyDialogResult AppendFile HighestTagSoFar ReminderTags + catch {destroy .mod} + toplevel .mod + CreateModifyDialog .mod $d $firstDay "Cancel" "Add to reminder file" "Preview reminder" + wm title .mod "TkRemind Add Reminder..." + wm iconname .mod "Add Reminder" + tkwait visibility .mod + set oldFocus [focus] + while {1} { + grab .mod + raise .mod + focus .mod.entry + set ModifyDialogResult -1 + tkwait variable ModifyDialogResult + if {$ModifyDialogResult == 1} { + catch {focus $oldFocus} + destroy .mod + return 0 + } + set problem [catch {set rem [CreateReminder .mod]} err] + if {$problem} { + tk_dialog .error Error "$err" error 0 Ok + } else { + if {$ModifyDialogResult == 3} { + set rem [EditReminder $rem Cancel "Add reminder"] + if {$ModifyDialogResult == 1} { + continue + } + } + set opts [RemindDialogToOptions .mod] + catch {focus $oldFocus} + destroy .mod + Status "Writing reminder..." + set f [open $AppendFile a] + incr HighestTagSoFar + set ReminderTags($HighestTagSoFar) 1 + + WriteReminder $f TKTAG$HighestTagSoFar $rem $opts + close $f + + ScheduleUpdateForChanges + return 0 + } + } +} + +#--------------------------------------------------------------------------- +# CenterWindow -- center a window on the screen or over a parent. +# Stolen from tk_dialog code +# Arguments: +# w -- window to center +# parent -- window over which to center. Defaults to screen if not supplied. +#--------------------------------------------------------------------------- +proc CenterWindow {w {parent {}}} { + wm withdraw $w + update idletasks + if {"$parent" == ""} { + set x [expr [winfo screenwidth $w]/2 - [winfo reqwidth $w]/2 \ + - [winfo vrootx [winfo parent $w]]] + set y [expr [winfo screenheight $w]/2 - [winfo reqheight $w]/2 \ + - [winfo vrooty [winfo parent $w]]] + } else { + set x [expr [winfo rootx $parent] + [winfo width $parent]/2 - [winfo reqwidth $w]/2] + set y [expr [winfo rooty $parent] + [winfo height $parent]/2 - [winfo reqheight $w]/2] + } + wm geom $w +$x+$y + wm deiconify $w +} + +#--------------------------------------------------------------------------- +# CreateReminder -- create the reminder +# Arguments: +# w -- the window containing the add reminder dialog box. +# Returns: +# The reminder as a string. +#--------------------------------------------------------------------------- +proc CreateReminder {w} { + global DidOmit TwentyFourHourMode + + set body [string trim [$w.entry get]] + + if {"$body" == ""} { + error "Blank body in reminder" + } + + set DidOmit 0 + set needOmit 0 + # Delegate the first part to CreateReminder1, CreateReminder2, or + # CreateReminder3 + global OptionType SkipType repbut expbut advbut advcount + global timebut timeadvbut timerepbut durationbut + + set rem [CreateReminder$OptionType $w] + + # Do the "until" part + if {$expbut} { + append rem " UNTIL " + append rem [consolidate [$w.expyear cget -text] [$w.expmon cget -text] [$w.expday cget -text]] + } + + # Advance warning + if {$advbut} { + append rem " +" + if {!$advcount} { + append rem "+" + } else { + set needOmit 1 + } + append rem [$w.advdays cget -text] + } + + # Timed reminder + if {$timebut} { + set hour [$w.timehour cget -text] + set min [$w.timemin cget -text] + if {!$TwentyFourHourMode} { + if {[$w.ampm cget -text] == "PM"} { + if {$hour < 12} { + incr hour 12 + } + } else { + if {$hour == 12} { + set hour 0 + } + } + } + append rem " AT $hour:$min" + if {$timeadvbut} { + append rem " +[$w.timeadv cget -text]" + } + if {$timerepbut} { + append rem " *[$w.timerep cget -text]" + } + if {$durationbut} { + append rem " DURATION [$w.durationh cget -text]:[$w.durationm cget -text]" + } + } + + global SkipType + if {$SkipType == 2} { + append rem " SKIP" + set needOmit 1 + } elseif {$SkipType == 3} { + append rem " BEFORE" + set needOmit 1 + } elseif {$SkipType == 4} { + append rem " AFTER" + set needOmit 1 + } + + if {$needOmit && !$DidOmit} { + append rem " OMIT [GetWeekend $w 1]" + } + + + # Check it out! + global Remind + set f [open "|$Remind -arq -e - 2>@1" r+] + puts $f "BANNER %" + puts $f "$rem MSG %" + puts $f "MSG %_%_%_%_" + puts $f "FLUSH" + flush $f + set err {} + catch {set err [gets $f]} + catch {close $f} + if {"$err" != ""} { + # Clean up the message a bit + regsub -- {^-stdin-\([0-9]*\): } $err {} err + error "Error from Remind: $err" + } + append rem " MSG " [string map -nocase {"\n" " "} $body] + return $rem +} + +# We used to return YYYY-MM-DD, but reverted to +# day monthname year because this lets Remind produce +# much better error messages. +proc consolidate {y m d} { + global MonthNames + if {![regexp {^[0-9]+$} $m]} { + set m [lsearch -exact $MonthNames $m] + incr m + } + set mname [lindex $MonthNames [expr $m-1]] + return "$d $mname $y" +} + +#--------------------------------------------------------------------------- +# CreateReminder1 -- Create the first part of a type-1 reminder +# Arguments: +# w -- add reminder dialog window +# Returns: first part of reminder +#--------------------------------------------------------------------------- +proc CreateReminder1 {w} { + + global repbut + + set rem "REM" + set gotDay 0 + set gotMon 0 + set gotYear 0 + set d [$w.day1 cget -text] + set m [$w.mon1 cget -text] + set y [$w.year1 cget -text] + if {"$d" != "every day" && "$m" != "every month" && $y != "every year"} { + set gotDay 1 + set gotMon 1 + set gotYear 1 + append rem " " + append rem [consolidate $y $m $d] + } else { + if {"$d" != "every day"} { + append rem " $d" + set gotDay 1 + } + if {"$m" != "every month"} { + append rem " $m" + set gotMon 1 + } + if {"$y" != "every year"} { + append rem " $y" + set gotYear 1 + } + } + + # Check for repetition + if {$repbut} { + if {!$gotDay || !$gotMon || !$gotYear} { + error "All components of a date must be specified if you wish to use the repeat feature." + } + append rem " *[$w.repdays cget -text]" + } + + return $rem +} + +#--------------------------------------------------------------------------- +# CreateReminder2 -- Create the first part of a type-2 reminder +# Arguments: +# w -- add reminder dialog window +# Returns: first part of reminder +#--------------------------------------------------------------------------- +proc CreateReminder2 {w} { + set wkday [$w.wkday2 cget -text] + if {"$wkday" == "weekday"} { + set wkday [GetWeekend $w 0] + } + set day [$w.day2 cget -text] + set mon [$w.mon2 cget -text] + set year [$w.year2 cget -text] + if {$mon != "every month" && $year != "every year"} { + set rem "REM $wkday " + append rem [consolidate $year $mon $day] + } else { + set rem "REM $wkday $day" + if {$mon != "every month"} { + append rem " $mon" + } + if {$year != "every year"} { + append rem " $year" + } + } + return $rem +} + +#--------------------------------------------------------------------------- +# CreateReminder3 -- Create the first part of a type-3 reminder +# Arguments: +# w -- add reminder dialog window +# Returns: first part of reminder +#--------------------------------------------------------------------------- +proc CreateReminder3 {w} { + global MonthNames DidOmit + set which [$w.ordinal cget -text] + set day [$w.wkday3 cget -text] + set mon [$w.mon3 cget -text] + set year [$w.year3 cget -text] + set rem "REM" + if {$which != "Last"} { + if {$which == "First"} { + append rem " 1" + } elseif {$which == "Second"} { + append rem " 8" + } elseif {$which == "Third"} { + append rem " 15" + } elseif {$which == "Fourth"} { + append rem " 22" + } + if {$day != "weekday"} { + append rem " $day" + } else { + append rem " [GetWeekend $w 0]" + } + if {$mon != "every month"} { + append rem " $mon" + } + if {$year != "every year"} { + append rem " $year" + } + } else { + if {$day != "weekday"} { + append rem " $day 1 --7" + } else { + append rem " 1 -1 OMIT [GetWeekend $w 1]" + set DidOmit 1 + } + if {$mon != "every month"} { + set i [lsearch -exact $MonthNames $mon] + if {$i == 11} { + set i 0 + } else { + incr i + } + append rem " [lindex $MonthNames $i]" + } + if {$year != "every year"} { + if {$mon == "December"} { + incr year + } + append rem " $year" + } + } + return $rem +} + +#--------------------------------------------------------------------------- +# GetWeekend -- returns a list of weekdays or weekend days +# Arguments: +# w -- add reminder dialog window +# wkend -- if 1, we want weekend. If 0, we want weekdays. +# Returns: +# list of weekdays or weekend-days +#--------------------------------------------------------------------------- +proc GetWeekend {w wkend} { + global dSaturday dSunday dMonday dTuesday dWednesday dThursday dFriday + global EnglishDayNames + set ret {} + foreach d $EnglishDayNames { + set v [set d$d] + if {$v == $wkend} { + lappend ret $d + } + } + return $ret +} + +#--------------------------------------------------------------------------- +# EditReminder -- allow user to edit what gets put in reminder file +# Arguments: +# rem -- current reminder +# args -- buttons to add to bottom +# Returns: +# edited version of rem +#--------------------------------------------------------------------------- +proc EditReminder {rem args} { + catch {destroy .edit} + global ModifyDialogResult + toplevel .edit + wm title .edit "TkRemind Preview reminder" + wm iconname .edit "Preview reminder" + text .edit.t -width 80 -height 5 -relief sunken + .edit.t insert end $rem + frame .edit.f + set n 0 + foreach but $args { + incr n + button .edit.but$n -text $but -command "set ModifyDialogResult $n" + pack .edit.but$n -in .edit.f -side left -fill x -expand 1 + } + pack .edit.t -side top -fill both -expand 1 + pack .edit.f -side top -fill x -expand 1 + bind .edit ".edit.but1 flash; .edit.but1 invoke" + set ModifyDialogResult 0 + CenterWindow .edit . + tkwait visibility .edit + set oldFocus [focus] + focus .edit.t + grab .edit + tkwait variable ModifyDialogResult + catch {focus $oldFocus} + set rem [.edit.t get 1.0 end] + catch {destroy .edit} + return $rem +} + +#--------------------------------------------------------------------------- +# SetWinAttr -- sets an attribute for a window +# Arguments: +# w -- window name +# attr -- attribute name +# val -- value to set it to +# Returns: +# $val +#--------------------------------------------------------------------------- +proc SetWinAttr {w attr val} { + global attrPriv + set attrPriv($w-$attr) $val +} + +#--------------------------------------------------------------------------- +# GetWinAttr -- gets an attribute for a window +# Arguments: +# w -- window name +# attr -- attribute name +# Returns: +# Value of attribute +#--------------------------------------------------------------------------- +proc GetWinAttr {w attr} { + global attrPriv + return $attrPriv($w-$attr) +} + +#--------------------------------------------------------------------------- +# WaitWinAttr -- wait for a window attribute to change +# Arguments: +# w -- window name +# attr -- attribute name +# Returns: +# Value of attribute +#--------------------------------------------------------------------------- +proc WaitWinAttr {w attr} { + global attrPriv + tkwait variable attrPriv($w-$attr) + return $attrPriv($w-$attr) +} + +#--------------------------------------------------------------------------- +# BrowseForFile -- creates and operates a file browser dialog. +# Arguments: +# w -- dialog window. +# title -- dialog title +# oktext -- text for "OK" button +# showdots -- if non-zero, shows "dot" files as well. +# Returns: +# complete path of filename chosen, or "" if Cancel pressed. +#--------------------------------------------------------------------------- +proc BrowseForFile {w title {oktext "OK"} {showdots 0} {filter "*"}} { + catch {destroy $w} + toplevel $w + wm title $w $title + + # Global array to hold window attributes + global a${w} + + SetWinAttr $w status busy + SetWinAttr $w showdots $showdots + + frame $w.fileframe + frame $w.butframe + label $w.cwd -text [pwd] + entry $w.entry + label $w.masklab -text "Match: " + listbox $w.list -yscrollcommand "$w.scroll set" + scrollbar $w.scroll -command "$w.list yview" + button $w.ok -text $oktext -command "BrowseForFileOK $w" + button $w.cancel -text "Cancel" -command "BrowseForFileCancel $w" + entry $w.filter -width 7 + $w.filter insert end $filter + + pack $w.cwd $w.entry -side top -expand 0 -fill x + pack $w.fileframe -side top -expand 1 -fill both + pack $w.butframe -side top -expand 0 -fill x + pack $w.list -in $w.fileframe -side left -expand 1 -fill both + pack $w.scroll -in $w.fileframe -side left -expand 0 -fill y + pack $w.ok -in $w.butframe -side left -expand 1 -fill x + pack $w.cancel -in $w.butframe -side left -expand 1 -fill x + pack $w.masklab -in $w.butframe -side left -expand 0 + pack $w.filter -in $w.butframe -side left -expand 1 -fill x + + # Fill in the box and wait for status to change + BrowseForFileRead $w [pwd] + + bind $w "$w.cancel flash; $w.cancel invoke" + bind $w.list "$w.entry delete 0 end; $w.entry insert 0 \[selection get\]" + bind $w.list "$w.ok flash; $w.ok invoke" + bind $w.list "$w.entry delete 0 end; $w.entry insert 0 \[selection get\]; $w.ok flash; $w.ok invoke" + bind $w.entry "$w.ok flash; $w.ok invoke" + bind $w.filter "BrowseForFileRead $w" + bind $w.entry "CompleteFile $w" + bind $w.entry "ExpandFile $w" + bindtags $w.entry "Entry $w.entry $w all" + + bindtags $w.list "Listbox $w.list $w all" + CenterWindow $w . + set oldFocus [focus] + tkwait visibility $w + focus $w.entry + set oldGrab [grab current $w] + grab set $w + WaitWinAttr $w status + catch {focus $oldFocus} + catch {grab set $oldGrab} + set ans [GetWinAttr $w status] + destroy $w + return $ans +} + +proc CompleteFile {w} { + set index [lsearch [$w.list get 0 end] [$w.entry get]* ] + if {$index > -1} { + $w.list see $index + $w.list selection clear 0 end + $w.list selection set $index + } +} + +proc ExpandFile {w} { + set stuff [$w.list curselection] + if {[string compare $stuff ""]} { + $w.entry delete 0 end + $w.entry insert end [$w.list get $stuff] + } +} + +proc BrowseForFileCancel {w} { + SetWinAttr $w status {} +} + +proc BrowseForFileOK {w} { + set fname [$w.entry get] + if {[string compare $fname ""]} { + # If it starts with a slash, handle it specially. + if {[string match "/*" $fname]} { + if {[file isdirectory $fname]} { + BrowseForFileRead $w $fname + return + } else { + SetWinAttr $w status $fname + return + } + } + if {[string match */ $fname]} { + set fname [string trimright $fname /] + } + if {[$w.cwd cget -text] == "/"} { + set fname "/$fname" + } else { + set fname "[$w.cwd cget -text]/$fname" + } + # If it's a directory, change directories + if {[file isdirectory $fname]} { + BrowseForFileRead $w $fname + } else { + SetWinAttr $w status $fname + } + } +} + +#--------------------------------------------------------------------------- +# BrowseForFileRead -- read the current directory into the file browser +# Arguments: +# w -- window name +# dir -- directory +# Returns: +# nothing +#--------------------------------------------------------------------------- +proc BrowseForFileRead {w {dir ""}} { + # Save working dir + set cwd [pwd] + if {$dir == ""} { + set dir [$w.cwd cget -text] + } + if {[catch "cd $dir" err]} { + tk_dialog .error Error "$err" error 0 Ok + return + } + $w.cwd configure -text [pwd] + if {[GetWinAttr $w showdots]} { + set flist [glob -nocomplain .* *] + } else { + set flist [glob -nocomplain *] + } + set flist [lsort $flist] + set filter [$w.filter get] + if {$filter == ""} { + set filter "*" + } + $w.list delete 0 end + foreach item $flist { + if {$item != "." && $item != ".."} { + if {[file isdirectory $item]} { + $w.list insert end "$item/" + } else { + if {[string match $filter $item]} { + $w.list insert end $item + } + } + } + } + if {[pwd] != "/"} { + $w.list insert 0 "../" + } + cd $cwd + $w.entry delete 0 end +} + +#--------------------------------------------------------------------------- +# StartBackgroundRemindDaemon +# Arguments: +# none +# Returns: +# nothing +# Description: +# Starts a background Remind daemon to handle timed reminders +#--------------------------------------------------------------------------- +proc StartBackgroundRemindDaemon {} { + global Remind DaemonFile ReminderFile Option TwentyFourHourMode + if {$TwentyFourHourMode} { + set problem [catch { set DaemonFile [open "|$Remind -b1 -z0 -itkremind=1 $Option(ExtraRemindArgs) $ReminderFile" "r+"] } err] + } else { + set problem [catch { set DaemonFile [open "|$Remind -z0 -itkremind=1 $Option(ExtraRemindArgs) $ReminderFile" "r+"] } err] + } + if {$problem} { + tk_dialog .error Error "Can't start Remind daemon in background: $err" error 0 OK + } else { + fileevent $DaemonFile readable "DaemonReadable $DaemonFile" + puts $DaemonFile "STATUS" + flush $DaemonFile + } +} + +#--------------------------------------------------------------------------- +# StopBackgroundRemindDaemon +# Arguments: +# none +# Returns: +# nothing +# Description: +# Stops the background Remind daemon +#--------------------------------------------------------------------------- +proc StopBackgroundRemindDaemon {} { + global DaemonFile + catch { + puts $DaemonFile "EXIT" + flush $DaemonFile + close $DaemonFile + } +} + +#--------------------------------------------------------------------------- +# RestartBackgroundRemindDaemon +# Arguments: +# none +# Returns: +# nothing +# Description: +# Restarts the background Remind daemon +#--------------------------------------------------------------------------- +proc RestartBackgroundRemindDaemon {} { + global DaemonFile ReminderFile ReminderFileModTime + + # Don't let the background handler trigger another reread + catch { + set mtime [file mtime $ReminderFile] + set ReminderFileModTime $mtime + } + + catch { + puts $DaemonFile "REREAD" + flush $DaemonFile + } +} + +#--------------------------------------------------------------------------- +# ShowQueue +# Arguments: +# file -- file channel that is readable +# Returns: +# nothing +# Description: +# Dumps the debugging queue listing +#--------------------------------------------------------------------------- +proc ShowQueue { file } { + set w .queuedbg + catch { destroy $w } + toplevel $w + wm title $w "Queue (Debugging Output)" + wm iconname $w "Queue Dbg" + text $w.t -width 80 -height 30 -wrap word -yscrollcommand "$w.sb set" + scrollbar $w.sb -orient vertical -command "$w.text yview" + button $w.ok -text "OK" -command "destroy $w" + grid $w.t -row 0 -column 0 -sticky nsew + grid $w.sb -row 0 -column 1 -sticky ns + grid $w.ok -row 1 -column 0 -sticky w + grid columnconfigure $w 0 -weight 1 + grid columnconfigure $w 1 -weight 0 + grid rowconfigure $w 0 -weight 1 + grid rowconfigure $w 1 -weight 0 + CenterWindow $w . + while (1) { + # We should only get one line + gets $file line + if {$line == "NOTE ENDJSONQUEUE"} { + break + } + if {[catch {set obj [::json::json2dict $line]}]} { + continue; + } + set obj [lsort -command sort_q $obj] + foreach q $obj { + $w.t insert end "$q\n" + } + } + $w.t configure -state disabled +} + +proc sort_q { a b } { + set a_ttime [dict get $a nextttime] + set b_ttime [dict get $b nextttime] + if {$a_ttime < $b_ttime} { + return -1 + } + if {$a_ttime > $b_ttime} { + return 1 + } + return 0 +} + +#--------------------------------------------------------------------------- +# DaemonReadable +# Arguments: +# file -- file channel that is readable +# Returns: +# nothing +# Description: +# Reads data from the Remind daemon and handles it appropriately +#--------------------------------------------------------------------------- +proc DaemonReadable { file } { + global Ignore + set line "" + catch { set num [gets $file line] } + if {$num < 0} { + catch { close $file } + return + } + switch -glob -- $line { + "NOTE reminder*" { + scan $line "NOTE reminder %s %s %s" time now tag + IssueBackgroundReminder $file $time $now $tag + } + "NOTE JSONQUEUE" { + ShowQueue $file + } + "NOTE newdate" { + # Date has rolled over -- clear "ignore" list + catch { unset Ignore} + Initialize + FillCalWindow + ShowTodaysReminders + } + "NOTE reread" { + puts $file "STATUS" + flush $file + } + "NOTE queued*" { + scan $line "NOTE queued %d" n + if {$n == 1} { + .b.nqueued configure -text "1 reminder queued" + } else { + .b.nqueued configure -text "$n reminders queued" + } + } + default { + puts stderr "Unknown message from daemon: $line\n" + } + } +} + +#--------------------------------------------------------------------------- +# IssueBackgroundReminder +# Arguments: +# file -- file channel that is readable +# time -- time of reminder +# now -- current time according to Remind daemon +# tag -- tag for reminder, or "*" if no tag +# Returns: +# nothing +# Description: +# Reads a background reminder from daemon and pops up window. +#--------------------------------------------------------------------------- +proc IssueBackgroundReminder { file time now tag } { + global BgCounter Option Ignore + if {$Option(Deiconify)} { + wm deiconify . + } + + set msg "" + set line "" + while (1) { + gets $file line + if {$line == "NOTE endreminder"} { + break + } + if {$msg != ""} { + append msg "\n"; + } + append msg $line + } + # Do nothing if it's blank -- was probably a RUN-type reminder. + if {$msg == ""} { + return + } + + # Do nothing if user told us to ignore this reminder + if {[info exists Ignore($tag)]} { + return + } + + incr BgCounter + set w .bg$BgCounter + toplevel $w + wm iconname $w "Reminder" + wm title $w "Timed reminder ($time)" + label $w.l -text "Reminder for $time issued at $now" + message $w.msg -width 6i -text $msg + frame $w.b + + # Automatically shut down window after a minute if option says so + set after_token [after 60000 [list ClosePopup $w "" $Option(MailAddr) $Option(AutoClose) "" $tag $msg $time]] + + wm protocol $w WM_DELETE_WINDOW [list ClosePopup $w $after_token "" 1 "" $tag $msg $time] + button $w.ok -text "OK" -command [list ClosePopup $w $after_token "" 1 "" $tag $msg $time] + if {$tag != "*"} { + button $w.nomore -text "Don't remind me again today" -command [list ClosePopup $w $after_token "" 1 "ignore" $tag $msg $time] + button $w.kill -text "Delete this reminder completely" -command [list ClosePopup $w $after_token "" 1 "kill" $tag $msg $time] + } + pack $w.l -side top + pack $w.msg -side top -expand 1 -fill both + pack $w.b -side top + pack $w.ok -in $w.b -side left + if {$tag != "*"} { + pack $w.nomore $w.kill -in $w.b -side left + } + + CenterWindow $w . + + update + if {$Option(RingBell)} { + bell + } + if {$Option(RunCmd) != ""} { + if {$Option(FeedReminder)} { + FeedReminderToCommand $Option(RunCmd) "$time: $msg" + } else { + exec "/bin/sh" "-c" $Option(RunCmd) "&" + } + } + + # reread status + if {$file != "stdin"} { + puts $file "STATUS" + flush $file + } +} + +#*********************************************************************** +# %PROCEDURE: FeedReminderToCommand +# %ARGUMENTS: +# cmd -- command to execute +# msg -- what to feed it +# %RETURNS: +# Nothing +# %DESCRIPTION: +# Feeds "$msg" to a command. +#*********************************************************************** +proc FeedReminderToCommand { cmd msg } { + catch { + set f [open "|$cmd" "w"] + fconfigure $f -blocking 0 + fileevent $f writable [list CommandWritable $f $msg] + } +} + +#*********************************************************************** +# %PROCEDURE: CommandWritable +# %ARGUMENTS: +# f -- file which is writable +# msg -- message to write +# %RETURNS: +# Nothing +# %DESCRIPTION: +# Writes $msg to $f; closes $f. +#*********************************************************************** +proc CommandWritable { f msg } { + puts $f $msg + flush $f + close $f +} + + +proc main {} { + global ConfigFile + + font create CalboxFont {*}[font actual TkFixedFont] + font create HeadingFont {*}[font actual TkDefaultFont] + font configure TkTextFont -size 6 + + global AppendFile HighestTagSoFar DayNames + catch { + puts "\nTkRemind Copyright (C) 1996-2021 Dianne Skoll" + } + catch { SetFonts } + Initialize + + # If no $ConfigFile file, create an empty one + if {![file exists $ConfigFile]} { + catch { + set f [open $ConfigFile "w"] + close $f + } + } + FindConfigFile + LoadOptions + ShowTodaysReminders + ScanForTags $AppendFile + CreateCalWindow $DayNames + FillCalWindow + StartBackgroundRemindDaemon + SetupInotify + DisplayTimeContinuously +} + +#*********************************************************************** +# %PROCEDURE: ScanForTags +# %ARGUMENTS: +# fname -- name of file to scan +# %RETURNS: +# Nothing +# %DESCRIPTION: +# Scans the file for all tags of the form "TKTAGnnnn" and builds +# the tag array. Also adjusts HighestTagSoFar +#*********************************************************************** +proc ScanForTags { fname } { + global HighestTagSoFar ReminderTags + if {[catch { set f [open $fname "r"]}]} { + return + } + while {[gets $f line] >= 0} { + switch -regexp -- $line { + {^REM TAG TKTAG[0-9]+} { + regexp {^REM TAG TKTAG([0-9]+)} $line dummy tagno + if {$tagno > $HighestTagSoFar} { + set HighestTagSoFar $tagno + } + set ReminderTags($tagno) 1 + } + } + } + close $f +} + +#*********************************************************************** +# %PROCEDURE: ReadTaggedOptions +# %ARGUMENTS: +# tag -- tag to match +# date -- today's date +# %RETURNS: +# A list of options for the dialog box for the tagged reminder +# %DESCRIPTION: +# Converts the JSON dictionary to a list of options for dialog box +#*********************************************************************** +proc ReadTaggedOptions { tag date } { + global TagToObj MonthNames EnglishDayNames TwentyFourHourMode + if {![info exists TagToObj($tag)]} { + return "" + } + set obj $TagToObj($tag) + set ans "" + regexp {^([0-9][0-9][0-9][0-9]).([0-9][0-9]).([0-9][0-9])} $date all y m d + set m [string trimleft $m 0] + set d [string trimleft $d 0] + set y [string trimleft $y 0] + if {![dict exists $obj skip]} { + lappend ans -global-SkipType 1 + } else { + set s [dict get $obj skip] + if {"$s" == "SKIP"} { + lappend ans -global-SkipType 2 + } elseif {"$s" == "BEFORE"} { + lappend ans -global-SkipType 3 + } elseif {"$s" == "AFTER"} { + lappend ans -global-SkipType 4 + } else { + lappend ans -global-SkipType 1 + } + } + + if {[dict exists $obj d]} { + lappend ans -text-day1 [dict get $obj d] + lappend ans -text-day2 [dict get $obj d] + } else { + lappend ans -text-day1 {every day} + lappend ans -text-day2 $d + } + if {[dict exists $obj m]} { + set m [dict get $obj m] + set mm [string trimleft $m 0] + lappend ans -text-mon1 [lindex $MonthNames [expr $mm -1]] + lappend ans -text-mon2 [lindex $MonthNames [expr $mm -1]] + lappend ans -text-mon3 [lindex $MonthNames [expr $mm -1]] + } else { + lappend ans -text-mon1 {every month} + lappend ans -text-mon2 {every month} + lappend ans -text-mon3 {every month} + } + if {[dict exists $obj y]} { + lappend ans -text-year1 [dict get $obj y] + lappend ans -text-year2 [dict get $obj y] + lappend ans -text-year3 [dict get $obj y] + } else { + lappend ans -text-year1 {every year} + lappend ans -text-year2 {every year} + lappend ans -text-year3 {every year} + } + + set wd {} + if {[dict exists $obj wd]} { + set wd [dict get $obj wd] + if {[llength $wd] == 1} { + lappend ans -text-wkday2 [lindex $wd 0] + lappend ans -text-wkday3 [lindex $wd 0] + } elseif {"$wd" == "Monday Tuesday Wednesday Thursday Friday"} { + lappend ans -text-wkday2 weekday + lappend ans -text-wkday3 weekday + } + } else { + lappend ans -text-wkday2 [get_weekday $date] + lappend ans -text-wkday3 [get_weekday $date] + } + + if {[llength $wd] > 0} { + if {[dict exists $obj d]} { + set day [dict get $obj d] + if {$day < 8} { + if {[dict exists $obj back]} { + lappend ans -text-ordinal Last + # Adjust month down and possibly year? + if {[dict exists $obj m]} { + set mm [string trimleft [dict get $obj m] 0] + set idx [expr $mm -1] + if {$idx <= 0} { + set idx 12 + } + lappend ans -text-mon1 [lindex $MonthNames [expr $idx -1]] + lappend ans -text-mon2 [lindex $MonthNames [expr $idx -1]] + lappend ans -text-mon3 [lindex $MonthNames [expr $idx -1]] + if {[dict exists $obj y]} { + set year [dict get $obj y] + if {$idx == 12} { + lappend ans -text-year1 [expr $year - 1] + lappend ans -text-year2 [expr $year - 1] + lappend ans -text-year3 [expr $year - 1] + } + } + } + } else { + lappend ans -text-ordinal First + } + } elseif {$day < 15} { + lappend ans -text-ordinal Second + } elseif {$day < 22} { + lappend ans -text-ordinal Third + } else { + lappend ans -text-ordinal Fourth + } + } else { + lappend ans -text-ordinal Every + } + } else { + if {$d < 8} { + lappend ans -text-ordinal First + } elseif {$d < 15} { + lappend ans -text-ordinal Second + } elseif {$d < 22} { + lappend ans -text-ordinal Third + } elseif {$d < 29} { + lappend ans -text-ordinal Fourth + } else { + lappend ans -text-ordinal Last + } + } + + if {[dict exists $obj until]} { + set u [dict get $obj until] + regexp {^([0-9][0-9][0-9][0-9]).([0-9][0-9]).([0-9][0-9])} $u all yu mu du + # Trim leading zeros, or Tcl complains + set mu [string trimleft $mu 0] + lappend ans -global-expbut 1 + lappend ans -text-expday $du + lappend ans -text-expmon [lindex $MonthNames [expr $mu-1]] + lappend ans -text-expyear $yu + + } else { + set mm [string trimleft $m 0] + lappend ans -global-expbut 0 + lappend ans -text-expday $d + lappend ans -text-expmon [lindex $MonthNames [expr $mm-1]] + lappend ans -text-expyear $y + } + + if {[dict exists $obj delta]} { + set delta [dict get $obj delta] + if {$delta == 0} { + lappend ans -global-advbut 0 + lappend ans -text-advdays 3 + lappend ans -global-advcount 1 + } elseif {$delta < 0} { + set delta [expr abs($delta)] + lappend ans -global-advbut 1 + lappend ans -text-advdays $delta + lappend ans -global-advcount 0 + } else { + lappend ans -global-advbut 1 + lappend ans -text-advdays $delta + lappend ans -global-advcount 1 + } + } else { + lappend ans -global-advbut 0 + lappend ans -text-advdays 3 + lappend ans -global-advcount 1 + } + + if {[dict exists $obj localomit]} { + set lo [dict get $obj localomit] + foreach w $EnglishDayNames { + if {[lsearch -exact $lo $w] >= 0} { + lappend ans "-global-d$w" 1 + } else { + lappend ans "-global-d$w" 0 + } + } + } else { + lappend ans -global-dSunday 1 + lappend ans -global-dMonday 0 + lappend ans -global-dTuesday 0 + lappend ans -global-dWednesday 0 + lappend ans -global-dThursday 0 + lappend ans -global-dFriday 0 + lappend ans -global-dSaturday 1 + } + if {[dict exists $obj rep]} { + lappend ans -global-repbut 1 + lappend ans -text-repdays [dict get $obj rep] + } else { + lappend ans -global-repbut 0 + lappend ans -text-repdays 1 + } + + if {[dict exists $obj time]} { + set t [dict get $obj time] + lappend ans -global-timebut 1 + set hour [expr $t / 60] + set minute [format %02d [expr $t % 60]] + if {$hour == 0 && !$TwentyFourHourMode} { + lappend ans -text-timehour 12 + lappend ans -text-ampm AM + } else { + if {$TwentyFourHourMode} { + lappend ans -text-timehour $hour + } else { + if {$hour >= 12} { + incr $hour -12 + lappend ans -text-timehour $hour + lappend ans -text-ampm PM + } else { + lappend ans -text-timehour $hour + lappend ans -text-ampm AM + } + } + } + lappend ans -text-timemin $minute + if {[dict exists $obj tdelta]} { + lappend ans -global-timeadvbut 1 + lappend ans -text-timeadv [dict get $obj tdelta] + } else { + lappend ans -global-timeadvbut 0 + lappend ans -text-timeadv 15 + } + if {[dict exists $obj trep]} { + lappend ans -global-timerepbut 1 + lappend ans -text-timerep [dict get $obj trep] + } else { + lappend ans -global-timerepbut 0 + lappend ans -text-timerep 5 + } + if {[dict exists $obj duration]} { + lappend ans -global-durationbut 1 + set dur [dict get $obj duration] + lappend ans -text-durationh [expr $dur / 60] + lappend ans -text-durationm [format %02d [expr $dur % 60]] + } else { + lappend ans -global-durationbut 0 + lappend ans -text-durationh 1 + lappend ans -text-durationm 00 + } + } else { + lappend ans -global-timebut 0 + lappend ans -text-timehour 12 + lappend ans -text-timemin 00 + lappend ans -text-timeadv 15 + lappend ans -global-timerepbut 0 + lappend ans -text-timerep 5 + lappend ans -global-durationbut 0 + lappend ans -text-durationh 1 + lappend ans -text-durationm 00 + } + if {[dict exists $obj rawbody]} { + lappend ans -entry-entry [dict get $obj rawbody] + } else { + lappend ans -entry-entry [dict get $obj body] + } + + # Figure out the reminder type + if {[dict exists $obj rep]} { + # Repeat must be type 1 + lappend ans -global-OptionType 1 + lappend ans -text-day2 $d + lappend ans -text-mon2 [lindex $MonthNames [expr $m - 1]] + lappend ans -text-mon3 [lindex $MonthNames [expr $m - 1]] + lappend ans -text-year2 $y + lappend ans -text-year3 $y + } elseif {![dict exists $obj wd]} { + # No weekdays - must be type 1 + lappend ans -global-OptionType 1 + lappend ans -text-day2 $d + lappend ans -text-mon2 [lindex $MonthNames [expr $m - 1]] + lappend ans -text-mon3 [lindex $MonthNames [expr $m - 1]] + lappend ans -text-year2 $y + lappend ans -text-year3 $y + } elseif {![dict exists $obj d]} { + # No day... must be "every wkday in ..." + lappend ans -global-OptionType 3 + lappend ans -text-day1 $d + lappend ans -text-mon1 [lindex $MonthNames [expr $m - 1]] + lappend ans -text-year1 $y + lappend ans -text-day2 $d + lappend ans -text-mon2 [lindex $MonthNames [expr $m - 1]] + lappend ans -text-year2 $y + } else { + set day [dict get $obj d] + # Take a guess based on day + if {$day == 1 || $day == 8 || $day == 15 || $day == 22} { + lappend ans -global-OptionType 3 + lappend ans -text-day1 $d + lappend ans -text-mon1 [lindex $MonthNames [expr $m - 1]] + lappend ans -text-year1 $y + lappend ans -text-day2 $d + lappend ans -text-mon2 [lindex $MonthNames [expr $m - 1]] + lappend ans -text-year2 $y + } else { + lappend ans -global-OptionType 2 + lappend ans -text-day1 $d + lappend ans -text-mon1 [lindex $MonthNames [expr $m - 1]] + lappend ans -text-year1 $y + lappend ans -text-mon3 [lindex $MonthNames [expr $m - 1]] + lappend ans -text-year3 $y + } + } + return $ans +} +proc FireEditor { w {fntag ""}} { + global Option + global EditorPid + if {"$fntag" == ""} { + set tags [$w tag names current] + set index [lsearch -glob $tags "FILE_*"] + if {$index < 0} { + return + } + set fntag [lindex $tags $index] + } + if {![regexp {^FILE_([0-9]+)_(.*)} $fntag all line file]} { + return + } + set editor $Option(Editor) + regsub -all "%s" $editor $file editor + regsub -all "%d" $editor $line editor + + # Don't fire up a second editor if first is running + if {$EditorPid >= 0} { + if {![catch {exec kill -0 $EditorPid}]} { + Status "Editor already active!" + after 2500 DisplayTime + bell + return + } + } + Status "Firing up editor..." + after 1500 DisplayTime + set EditorPid [exec sh -c $editor &] +} + +#*********************************************************************** +# %PROCEDURE: GetCurrentReminder +# %ARGUMENTS: +# w -- text window +# %RETURNS: +# The tag (TKTAGnnnn) for current editable reminder, or "" if no +# current editable reminder. +#*********************************************************************** +proc GetCurrentReminder { w } { + set tags [$w tag names current] + set index [lsearch -glob $tags "TKTAG*"] + if {$index < 0} { + return "" + } + set tag [lindex $tags $index] + return $tag +} + +#*********************************************************************** +# %PROCEDURE: TaggedEnter +# %ARGUMENTS: +# w -- text window +# %RETURNS: +# Nothing +# %DESCRIPTION: +# Highlights an "editable" reminder as mouse moves into it +#*********************************************************************** +proc TaggedEnter { w } { + set tag [GetCurrentReminder $w] + if {$tag != ""} { + $w tag configure $tag -foreground #FF0000 + } +} + +#*********************************************************************** +# %PROCEDURE: TaggedLeave +# %ARGUMENTS: +# w -- text window +# %RETURNS: +# Nothing +# %DESCRIPTION: +# Removes highlight from an "editable" reminder as mouse leaves it +#*********************************************************************** +proc TaggedLeave { w } { + global Option + set tag [GetCurrentReminder $w] + if {$tag != ""} { + set tags [$w tag names current] + set index [lsearch -glob $tags "clr*"] + if {$index < 0} { + set fg $Option(TextColor) + } else { + set fg [string range [lindex $tags $index] 3 end] + set fg "#$fg" + } + $w tag configure $tag -foreground $fg + } +} + +proc EditableEnter { w } { + set tags [$w tag names current] + set index [lsearch -glob $tags "FILE_*"] + if {$index < 0} { + return + } + set tag [lindex $tags $index] + + set c "" + set index [lsearch -glob $tags "clr*"] + if {$index >= 0} { + set ctag [lindex $tags $index] + set c [$w tag cget $ctag -foreground] + } + if {"$c" != ""} { + $w tag configure $tag -underline 1 -underlinefg $c + } else { + $w tag configure $tag -underline 1 + } +} +proc EditableLeave { w } { + set tags [$w tag names current] + set index [lsearch -glob $tags "FILE_*"] + if {$index < 0} { + return + } + set tag [lindex $tags $index] + $w tag configure $tag -underline 0 +} +#*********************************************************************** +# %PROCEDURE: EditTaggedReminder +# %ARGUMENTS: +# w -- text window +# %RETURNS: +# Nothing +# %DESCRIPTION: +# Opens a dialog box to edit the current editable reminder +#*********************************************************************** +proc EditTaggedReminder { w } { + global ModifyDialogResult + set tag [GetCurrentReminder $w] + if {$tag == ""} { + return + } + + # Get the date + set index [lsearch -glob [$w tag names current] "date_*"] + if {$index < 0} { + return + } + set date [string range [lindex [$w tag names current] $index] 5 end] + # Read in options + set opts [ReadTaggedOptions $tag $date] + if {$opts == ""} { + return + } + + toplevel .mod + CreateModifyDialog .mod 1 0 "Cancel" "Replace reminder" "Delete reminder" "Preview reminder" + wm title .mod "TkRemind Edit Reminder..." + wm iconname .mod "Edit Reminder" + OptionsToRemindDialog .mod $opts + + tkwait visibility .mod + set oldFocus [focus] + while {1} { + raise .mod + grab .mod + focus .mod.entry + set ModifyDialogResult -1 + tkwait variable ModifyDialogResult + if {$ModifyDialogResult == 1} { + catch {focus $oldFocus} + destroy .mod + return 0 + } + set problem [catch {set rem [CreateReminder .mod]} err] + if {$problem} { + tk_dialog .error Error "$err" error 0 Ok + continue + } + if {$ModifyDialogResult == 4} { + set rem [EditReminder $rem "Cancel" "Replace reminder"] + if {$ModifyDialogResult == 1} { + continue + } + } + set opts [RemindDialogToOptions .mod] + catch {focus $oldFocus} + destroy .mod + set problem [catch { + if {$ModifyDialogResult == 2} { + ReplaceTaggedReminder $tag $rem $opts + } else { + DeleteTaggedReminder $tag + } + } err] + if {$problem} { + tk_dialog .error Error "Error: $err" error 0 Ok + return 1 + } + + ScheduleUpdateForChanges + return 0 + } +} + + +#*********************************************************************** +# %PROCEDURE: UpdateForChanges +# Updates the calendar window and restarts background daemon because +# something has changed. +# %ARGUMENTS: +# None +# %RETURNS: +# Nothing +#*********************************************************************** +proc UpdateForChanges {} { + global TimerUpdateForChanges + catch { after cancel $TimerUpdateForChanges } + FillCalWindow + RestartBackgroundRemindDaemon +} + +# Schedule an update for 100ms in the future. +# That way, if we get a rapid succession of +# change notifications, we (probably) only +# end up doing one call to UpdateForChanges +proc ScheduleUpdateForChanges {} { + global TimerUpdateForChanges + catch { after cancel $TimerUpdateForChanges } + set TimerUpdateForChanges [after 100 UpdateForChanges] +} + +#*********************************************************************** +# %PROCEDURE: UniqueFileName +# %ARGUMENTS: +# stem -- base name of file +# %RETURNS: +# A filename of the form "stem.xxx" which does not exist +#*********************************************************************** +proc UniqueFileName { stem } { + set n 1 + while {[file exists $stem.$n]} { + incr n + } + return $stem.$n +} + + +#*********************************************************************** +# %PROCEDURE: DeleteTaggedReminder +# %ARGUMENTS: +# tag -- tag of reminder to delete +# %RETURNS: +# Nothing +# %DESCRIPTION: +# Deletes tagged reminder from reminder file +#*********************************************************************** +proc DeleteTaggedReminder { tag } { + global AppendFile + global HighestTagSoFar + + set tmpfile [UniqueFileName $AppendFile] + set out [open $tmpfile "w"] + write_warning_headers $out + set in [open $AppendFile "r"] + + set found 0 + + set tagno 0 + while {[gets $in line] >= 0} { + if {[is_warning_header $line]} { + continue + } + if {[string match "REM TAG $tag *" $line]} { + set found 1 + continue + } + # Delete the old comment lines + if {[string match "# TKTAG*" $line]} { + continue + } + if {[string match "# -global-OptionType *" $line]} { + continue + } + if {[string match "# TKEND" $line]} { + continue + } + + # Renumber tags + if {[regexp {^REM TAG TKTAG([0-9]+) (.*)$} $line all oldtag rest]} { + incr tagno + puts $out "REM TAG TKTAG$tagno $rest" + } else { + puts $out $line + } + } + + if {! $found } { + close $in + close $out + file delete $tmpfile + error "Did not find reminder with tag $tag" + } + + set HighestTagSoFar $tagno + close $in + close $out + file rename -force -- $tmpfile $AppendFile +} + +#*********************************************************************** +# %PROCEDURE: ReplaceTaggedReminder +# %ARGUMENTS: +# tag -- tag of reminder to replace +# rem -- text to replace it with +# opts -- edit options +# %RETURNS: +# Nothing +# %DESCRIPTION: +# Replaces a tagged reminder in the reminder file +#*********************************************************************** +proc ReplaceTaggedReminder { tag rem opts } { + global AppendFile + + set tmpfile [UniqueFileName $AppendFile] + set out [open $tmpfile "w"] + write_warning_headers $out + set in [open $AppendFile "r"] + + set found 0 + + while {[gets $in line] >= 0} { + if {[is_warning_header $line]} { + continue + } + if {[string match "REM TAG $tag *" $line]} { + # Write the new reminder + WriteReminder $out $tag $rem $opts + set found 1 + } else { + # Delete the old comment lines + if {[string match "# TKTAG*" $line]} { + continue + } + if {[string match "# -global-OptionType *" $line]} { + continue + } + if {[string match "# TKEND" $line]} { + continue + } + puts $out $line + } + } + + if {! $found} { + close $in + close $out + file delete $tmpfile + error "Did not find reminder with tag $tag" + } + + close $in + close $out + file rename -force -- $tmpfile $AppendFile +} + +#*********************************************************************** +# %PROCEDURE: WriteReminder +# %ARGUMENTS: +# out -- file to write to +# tag -- reminder tag +# rem -- reminder body +# opts -- edit options +# %RETURNS: +# Nothing +# %DESCRIPTION: +# Writes a reminder to a file +#*********************************************************************** +proc WriteReminder { out tag rem opts } { + #puts $out "# $tag Next reminder was created with TkRemind. DO NOT EDIT" + #puts $out "# $opts" + if {[string range $rem 0 3] == "REM "} { + puts $out "REM TAG $tag [string range $rem 4 end]" + } else { + puts $out $rem + } + #puts $out "# TKEND" +} + +#*********************************************************************** +# %PROCEDURE: DoShadeSpecial +# %ARGUMENTS: +# n -- calendar box to shade +# r, g, b -- colour components +# %RETURNS: +# Nothing +# %DESCRIPTION: +# Handles the "SHADE" special -- shades a box. +#*********************************************************************** +proc DoShadeSpecial { n r g b } { + if {$r < 0 || $r > 255 || $g < 0 || $g > 255 || $b < 0 || $b > 255} { + return + } + set bg [format "#%02x%02x%02x" $r $g $b] + .cal.t$n configure -background $bg +} + +#*********************************************************************** +# %PROCEDURE: DoMoonSpecial +# %ARGUMENTS: +# n -- calendar box for moon +# stuff -- Remind command line +# fntag - filename tag, if any +# %RETURNS: +# Nothing +# %DESCRIPTION: +# Handles the "MOON" special -- draws a moon symbol +#*********************************************************************** +proc DoMoonSpecial { n stuff fntag day } { + set msg "" + set num [scan $stuff "%d %d %d %s" phase junk1 junk2 msg] + if {$num < 1} { + return + } + if {$phase < 0 || $phase > 3} { + return + } + + switch -exact -- $phase { + 0 { set win .moon_new } + 1 { set win .moon_first } + 2 { set win .moon_full } + 3 { set win .moon_last } + } + + # We need two sets of moon phase windows. There can be + # two of a given phase in the same month, but Tk does + # not allow the same embedded window in two separate + # text boxes. So we use this hack to make sure + # we use a different window if the same moon phase + # happens twice in a month. + if {$day > 16} { + append win "2" + } + + .cal.t$n configure -state normal + .cal.t$n window create 1.0 -window $win + + if {$msg != ""} { + if {"$fntag" == "x"} { + .cal.t$n insert 1.1 " $msg\n" + } else { + .cal.t$n insert 1.1 " $msg\n" [list REM $fntag] + .cal.t$n tag bind $fntag "EditableEnter .cal.t$n" + .cal.t$n tag bind $fntag "EditableLeave .cal.t$n" + .cal.t$n tag bind $fntag "FireEditor .cal.t$n $fntag" + bind $win "FireEditor .cal.t$n $fntag" + bind $win "FireEditor .cal.t$n $fntag" + } + } else { + if {"$fntag" == "x"} { + .cal.t$n insert 1.1 "\n" + } else { + .cal.t$n insert 1.1 "\n" [list REM $fntag] + .cal.t$n tag bind $fntag "EditableEnter .cal.t$n" + .cal.t$n tag bind $fntag "EditableLeave .cal.t$n" + .cal.t$n tag bind $fntag "FireEditor .cal.t$n $fntag" + } + } + .cal.t$n configure -state disabled -takefocus 0 +} +#*********************************************************************** +# %PROCEDURE: DisplayTime +# %ARGUMENTS: +# None +# %RETURNS: +# Nothing +# %DESCRIPTION: +# Displays current date and time in status window +#*********************************************************************** +proc DisplayTime {} { + global TwentyFourHourMode + if {$TwentyFourHourMode} { + set msg [clock format [clock seconds] -format "%e %b %Y %H:%M"] + } else { + set msg [clock format [clock seconds] -format "%e %b %Y %I:%M%p"] + } + Status $msg +} + +#*********************************************************************** +# %PROCEDURE: CreateMoonWindows +# %ARGUMENTS: +# None +# %RETURNS: +# Nothing +# %DESCRIPTION: +# Creates the moon windows .moon_new, .moon_first, .moon_full and +# .moon_last +#*********************************************************************** +proc CreateMoonWindows {} { + global Option; + catch { destroy .moon_new } + catch { destroy .moon_first } + catch { destroy .moon_full } + catch { destroy .moon_last } + + catch { destroy .moon_new2 } + catch { destroy .moon_first2} + catch { destroy .moon_full2 } + catch { destroy .moon_last2 } + + set extra 1 + set wid [font metrics CalboxFont -ascent] + set orig_wid $wid + incr wid $extra + incr wid $extra + incr wid $extra + incr wid $extra + incr orig_wid $extra + incr orig_wid $extra + + set w [expr $extra+$orig_wid] + + foreach win {.moon_new .moon_new2 } { + canvas $win -background $Option(BackgroundColor) -width $wid -height $wid -borderwidth 0 -highlightthickness 0 + $win create oval $extra $extra $w $w -outline $Option(TextColor) -width 1 + balloon_add_help $win "New Moon" + } + + foreach win {.moon_first .moon_first2 } { + canvas $win -background $Option(BackgroundColor) -width $wid -height $wid -borderwidth 0 -highlightthickness 0 + $win create oval $extra $extra $w $w -outline $Option(TextColor) -width 1 + $win create arc $extra $extra $w $w -outline $Option(TextColor) -fill $Option(TextColor) -start 90 -extent 180 -outline {} + balloon_add_help $win "First Quarter" + } + + foreach win {.moon_full .moon_full2 } { + canvas $win -background $Option(BackgroundColor) -width $wid -height $wid -borderwidth 0 -highlightthickness 0 + $win create oval $extra $extra $w $w -outline $Option(TextColor) -fill $Option(TextColor) -width 1 + balloon_add_help $win "Full Moon" + } + + foreach win {.moon_last .moon_last2 } { + canvas $win -background $Option(BackgroundColor) -width $wid -height $wid -borderwidth 0 -highlightthickness 0 + $win create oval $extra $extra $w $w -outline $Option(TextColor) -width 1 + $win create arc $extra $extra $w $w -outline $Option(TextColor) -fill $Option(TextColor) -start 270 -extent 180 -outline {} + balloon_add_help $win "Last Quarter" + } +} + +#*********************************************************************** +# %PROCEDURE: DisplayTimeContinuously +# %ARGUMENTS: +# None +# %RETURNS: +# Nothing +# %DESCRIPTION: +# Continuously displays current date and time in status window, +# updating once a minute +#*********************************************************************** +proc DisplayTimeContinuously {} { + DisplayTime + set secs [clock format [clock seconds] -format "%S"] + # Doh -- don't interpret as an octal number if leading zero + scan $secs "%d" decSecs + set decSecs [expr 60 - $decSecs] + after [expr $decSecs * 1000] DisplayTimeContinuously +} + + +#*********************************************************************** +# %PROCEDURE: ShowTodaysReminders +# %ARGUMENTS: +# None +# %RETURNS: +# Nothing +# %DESCRIPTION: +# Shows all of today's non-timed reminders in a window +#*********************************************************************** +proc ShowTodaysReminders {} { + global Option + global Remind + global ReminderFile + global TwentyFourHourMode + if {!$Option(ShowTodaysReminders)} { + return + } + + set w .today + catch { destroy $w } + toplevel $w + wm title $w "Today's Reminders" + wm iconname $w "Reminders" + text $w.text -width 80 -height 20 -wrap word -yscrollcommand "$w.sb set" + scrollbar $w.sb -orient vertical -command "$w.text yview" + button $w.ok -text "OK" -command "destroy $w" + + grid $w.text -row 0 -column 0 -sticky nsew + grid $w.sb -row 0 -column 1 -sticky ns + grid $w.ok -row 1 -column 0 -sticky w + + CenterWindow $w . + + # Grab the reminders + set stuff "" + set cmdline "|$Remind -itkremind=1 -g -q -r " + if {$TwentyFourHourMode} { + append cmdline "-b1 " + } + append cmdline $Option(ExtraRemindArgs); + append cmdline " $ReminderFile 2>/dev/null" + set f [open $cmdline r] + while {[gets $f line] >= 0} { + append stuff "$line\n" + } + close $f + $w.text insert end $stuff + $w.text configure -state disabled +} + +#*********************************************************************** +# %PROCEDURE: InteractiveDeleteReminder +# %ARGUMENTS: +# tag -- tag of reminder to delete +# %RETURNS: +# Nothing +# %DESCRIPTION: +# Prompts for confirmation; then deletes reminder +#*********************************************************************** +proc InteractiveDeleteReminder { tag } { + set ans [tk_dialog .error "Really Delete" "Really delete reminder?" warning 0 No Yes] + if {$ans == 1} { + DeleteTaggedReminder $tag + ScheduleUpdateForChanges + } +} + +proc SendMail { recipient subject body } { + global Option + + if {"$Option(MailAddr)" == ""} { + return + } + if {[catch {set token [mime::initialize -canonical text/plain -string $body] + mime::setheader $token Subject $subject + mime::setheader $token From "Reminder Service <>" + mime::setheader $token To "<$recipient>" + mime::setheader $token Auto-Submitted "auto-generated" + smtp::sendmessage $token -originator "" -servers $Option(SMTPServer) -recipients $Option(MailAddr)} err]} { + puts stderr "ERROR sending mail: $err" + } +} + +proc ClosePopup { w after_token mail_addr close_win ignore_or_kill tag reminder rem_time } { + global Ignore + if {"$after_token" != ""} { + catch { after cancel $after_token } + } + + if {$close_win} { + catch { destroy $w } + } + + if {"$mail_addr" != ""} { + SendMail $mail_addr "Reminder for $rem_time" "Hello,\n\nThe following reminder is scheduled for $rem_time:\n\n$reminder\nRegards,\n\nTkRemind\n" + } + if {"$ignore_or_kill" == "ignore"} { + set Ignore($tag) 1 + } + if {"$ignore_or_kill" == "kill"} { + InteractiveDeleteReminder $tag + } +} + +# Adjust font defaults for screen size +proc SetFonts {} { + global SetFontsWorked + set h [winfo screenheight .] + if {$h <= 480} { + # Small screen (maybe eeepc?) + font configure TkDefaultFont -size 6 + font configure TkFixedFont -size 6 + font configure TkTextFont -size 6 + } + if {$h >= 1080} { + # HIDPI screen + font configure TkDefaultFont -size 12 + font configure TkFixedFont -size 12 + font configure TkTextFont -size 12 + } + set SetFontsWorked 1 +} + +# Set up inotify to watch for changes to reminder file/directory +proc SetupInotify {} { + global InotifyFP + global ReminderFile + set failed [catch {set InotifyFP [open "|inotifywait -r -q -m -e close_write -e move -e create -e delete $ReminderFile < /dev/null 2>/dev/null" "r"] } ] + if {$failed} { + # inotifywait probably not available... meh. + return + } + fileevent $InotifyFP readable [list InotifyReadable $InotifyFP] +} + +# Called when inotifywait reports an event. Schedule a calendar update +# and daemon reload. +proc InotifyReadable { fp } { + catch { set num [gets $fp line] } + if {$num < 0} { + catch { exec kill [pid $fp] } + close $fp + return + } + ScheduleUpdateForChanges +} + +### Balloon help +set Balloon(HelpTime) 400 +set Balloon(StayTime) 3500 +set Balloon(Font) fixed +set Balloon(MustLeave) 0 + +proc balloon_reset_timer { w } { + balloon_destroy_help_window + balloon_cancel_timer + balloon_schedule_help $w +} + +proc balloon_destroy_help_window {} { + catch { destroy .balloonhelp } +} + +proc balloon_cancel_timer {} { + global Balloon + catch { after cancel $Balloon(HelpId) } +} + +proc balloon_schedule_help { w } { + global Balloon + if { $Balloon(MustLeave) } { + return + } + set Balloon(HelpId) [ after $Balloon(HelpTime) "balloon_popup_help $w" ] +} + +proc balloon_popup_help { w } { + global Balloon + if {![info exists Balloon(helptext$w)]} { + return + } + + if {[string compare [winfo containing [winfo pointerx .] [winfo pointery .]] $w]} { + return + } + set h .balloonhelp + toplevel $h -bg #000000 + label $h.l -text $Balloon(helptext$w) -wraplength 200 -justify left -bg #FFFFC0 -bd 0 + pack $h.l -padx 1 -pady 1 -ipadx 2 -ipady 1 + wm overrideredirect $h 1 + set geom [balloon_calculate_geometry $h] + wm geometry $h $geom + set Balloon(HelpId) [after $Balloon(StayTime) "catch { destroy $h }"] + set Balloon(MustLeave) 1 +} + +bind Balloon { + set Balloon(MustLeave) 0 + balloon_destroy_help_window + balloon_cancel_timer +} + +bind Balloon { + set Balloon(MustLeave) 0 + balloon_reset_timer %W +} + +bind Balloon "balloon_reset_timer %W" +bind Balloon { + set Balloon(MustLeave) 1 + balloon_reset_timer %W +} + +bind Balloon { + balloon_destroy_help_window + balloon_cancel_timer + catch { unset Balloon(helptext%W) } +} + +proc balloon_add_help { w txt } { + global Balloon + if {"$txt" == ""} { + catch { unset Balloon(helptext$w) } + return + } + set Balloon(helptext$w) $txt + bindtags $w "Balloon [bindtags $w]" +} + +proc balloon_calculate_geometry { w } { + set x [winfo pointerx $w] + set y [winfo pointery $w] + set mx [winfo screenwidth $w] + set my [winfo screenheight $w] + # Adjust for padding + set wid [expr [winfo reqwidth $w.l] + 6] + set h [expr [winfo reqheight $w.l] + 4] + + # Try above-right of pointer + set tx [expr $x+3] + set ty [expr $y-3-$h] + if {$ty >= 0 && ($tx+$wid) <= $mx} { + return "+$tx+$ty" + } + + # Try above-left of pointer + set tx [expr $x-3-$wid] + set ty [expr $y-3-$h] + if {$ty >= 0 && $tx >= 0} { + return "+$tx+$ty" + } + + # Try below-right of pointer + set tx [expr $x+3] + set ty [expr $y+3] + if {$ty+$h <= $my && ($tx+$wid) <= $mx} { + return "+$tx+$ty" + } + + # Darn... must be below-left + set tx [expr $x-3-$wid] + set ty [expr $y+3] + return "+$tx+$ty" +} + +proc ChooseCalboxFont {} { + tk fontchooser show + tk fontchooser configure -font [font actual CalboxFont] + tk fontchooser configure -command SetCalboxFont +} + +proc SetCalboxFont {font} { + global tmpOpt + font configure CalboxFont {*}[font actual $font] + set tmpOpt(CalboxFont) [font actual $font] + raise .opt +} + +proc ChooseHeadingFont {} { + tk fontchooser show + tk fontchooser configure -font [font actual HeadingFont] + tk fontchooser configure -command SetHeadingFont +} + +proc SetHeadingFont {font} { + global tmpOpt + font configure HeadingFont {*}[font actual $font] + set tmpOpt(HeadingFont) [font actual $font] + raise .opt +} + +proc PickColor {index button} { + global tmpOpt + set x [tk_chooseColor -initialcolor $tmpOpt($index)] + if {"$x" != ""} { + set tmpOpt($index) $x + $button configure -background $x + } + raise .opt +} + +proc FindConfigFile {} { + global ConfigFile + + # If it was set on the command line, use that + if {"$ConfigFile" != ""} { + return + } + + set confighome "" + if {[info exists env(XDG_CONFIG_HOME)]} { + set confighome $env(XDG_CONFIG_HOME) + } + if {"$confighome" == ""} { + set confighome "~/.config" + } + + # If $confighome does not exist, attempt to + # create it + if {![file exists $confighome]} { + catch { file mkdir $confighome } + } + + if {[file isdirectory $confighome]} { + # Migrate .tkremindrc to $confighome/tkremindrc + if {[file exists "~/.tkremindrc"]} { + if {![file exists "$confighome/tkreminderc"]} { + puts "Migrating ~/.tkremindrc to $confighome/tkremindrc" + if {[catch { file copy "~/.tkremindrc" "$confighome/tkremindrc"}]} { + puts "FAILED!\n" + set ConfigFile "~/.tkremindrc" + return + } + catch { file delete "~/.tkremindrc" } + } + set ConfigFile "$confighome/tkremindrc" + return + } + set ConfigFile "$confighome/tkremindrc" + return + } + set ConfigFile "~/.tkremindrc" +} + +proc set_default_colors { w } { + global tmpOpt + set tmpOpt(BackgroundColor) "#d9d9d9" + set tmpOpt(LabelColor) "#000000" + set tmpOpt(LineColor) "#000000" + set tmpOpt(TextColor) "#000000" + set tmpOpt(TodayColor) "#00C0C0" + set tmpOpt(WinBackground) "#d9d9d9" + update_color_buttons $w +} + +proc set_dark_colors { w } { + global tmpOpt + set tmpOpt(BackgroundColor) "#000000" + set tmpOpt(LabelColor) "#00ffff" + set tmpOpt(LineColor) "#0080fc" + set tmpOpt(TextColor) "#ffffff" + set tmpOpt(TodayColor) "#b000b6" + set tmpOpt(WinBackground) "#000000" + update_color_buttons $w +} + +proc update_color_buttons { w } { + global tmpOpt + $w.bbgcolor configure -background $tmpOpt(BackgroundColor) + $w.bheadcolor configure -background $tmpOpt(LabelColor) + $w.gridbcolor configure -background $tmpOpt(LineColor) + $w.btextcolor configure -background $tmpOpt(TextColor) + $w.tbbgcolor configure -background $tmpOpt(TodayColor) + $w.bwincolor configure -background $tmpOpt(WinBackground) +} + +proc set_button_to_queue {} { + .b.queue configure -text {Queue...} -command {DoQueue} +} +proc set_button_to_errors {} { + .b.queue configure -text {Errors...} -command {ShowErrors} +} + +proc ShowErrors {} { + global RemindErrors + set w ".errors" + catch { destroy $w } + toplevel $w + text $w.t -width 80 -height 30 -wrap word -yscrollcommand "$w.sb set" + scrollbar $w.sb -orient vertical -command "$w.t yview" + button $w.ok -text OK -command DoneShowingErrors + grid $w.t -row 0 -column 0 -sticky nsew + grid $w.sb -row 0 -column 1 -sticky ns + grid $w.ok -row 1 -column 0 -stick w + grid columnconfigure $w 0 -weight 1 + grid columnconfigure $w 1 -weight 0 + grid rowconfigure $w 0 -weight 1 + grid rowconfigure $w 1 -weight 0 + $w.t insert end $RemindErrors + $w.t configure -state disabled + CenterWindow $w . +} + +proc DoneShowingErrors {} { + global RemindErrors + set RemindErrors {} + set_button_to_queue + destroy .errors +} + +# Rem2PS program to execute -- supply full path if you want + +main diff --git a/.bin/OLD/tmpchrome b/.bin/OLD/tmpchrome new file mode 100755 index 0000000..a7fcf6a --- /dev/null +++ b/.bin/OLD/tmpchrome @@ -0,0 +1,4 @@ +#!/bin/sh +mkdir -p /tmp/chromecache +export XDG_CACHE_HOME=/tmp/chromecache +chrome diff --git a/.bin/OLD/tmpv b/.bin/OLD/tmpv new file mode 100755 index 0000000..e919849 --- /dev/null +++ b/.bin/OLD/tmpv @@ -0,0 +1,2 @@ +#!/bin/sh +mpv --x11-name=tmpv "$@" diff --git a/.bin/toot-wrapper b/.bin/OLD/toot-wrapper similarity index 100% rename from .bin/toot-wrapper rename to .bin/OLD/toot-wrapper diff --git a/.bin/OLD/trans b/.bin/OLD/trans new file mode 100755 index 0000000..1d66db2 --- /dev/null +++ b/.bin/OLD/trans @@ -0,0 +1,5713 @@ +#!/usr/bin/env bash +export TRANS_ENTRY="$0" +if [[ ! $LANG =~ (UTF|utf)-?8$ ]]; then export LANG=en_US.UTF-8; fi +read -r -d '' TRANS_PROGRAM << 'EOF' +BEGIN { +Name = "Translate Shell" +Description = "Command-line translator using Google Translate, Bing Translator, Yandex.Translate, etc." +Version = "0.9.6.12" +ReleaseDate = "2020-05-11" +Command = "trans" +EntryPoint = "translate.awk" +EntryScript = "translate" +} +function initConst() { +NULLSTR = "" +NONE = "\0" +TRUE = 1 +STDIN = "/dev/stdin" +STDOUT = "/dev/stdout" +STDERR = "/dev/stderr" +SUPOUT = " > /dev/null " +SUPERR = " 2> /dev/null " +PIPE = " | " +} +function anything(array, +i) { +for (i in array) +if (array[i]) return 1 +return 0 +} +function exists(value) { +if (isarray(value)) +return anything(value) +else +return value ? 1 : 0 +} +function belongsTo(element, array, +i) { +for (i in array) +if (element == array[i]) return element +return NULLSTR +} +function identical(x, y, +i) { +if (!isarray(x) && !isarray(y)) +return x == y +else if (isarray(x) && isarray(y)) { +if (length(x) != length(y)) return 0 +for (i in x) +if (!identical(x[i], y[i])) return 0 +return 1 +} else +return 0 +} +function append(array, element) { +array[anything(array) ? length(array) : 0] = element +} +function compareByIndexFields(i1, v1, i2, v2, +t1, t2, tl, j) { +split(i1, t1, SUBSEP) +split(i2, t2, SUBSEP) +tl = length(t1) < length(t2) ? length(t1) : length(t2) +for (j = 1; j <= tl; j++) { +if (t1[j] < t2[j]) +return -1 +else if (t1[j] > t2[j]) +return 1 +} +return 0 +} +function isnum(string) { +return string == string + 0 +} +function startsWithAny(string, substrings, +i) { +for (i in substrings) +if (index(string, substrings[i]) == 1) return substrings[i] +return NULLSTR +} +function matchesAny(string, patterns, +i) { +for (i in patterns) +if (string ~ "^" patterns[i]) return patterns[i] +return NULLSTR +} +function replicate(string, len, +i, temp) { +temp = NULLSTR +for (i = 0; i < len; i++) +temp = temp string +return temp +} +function reverse(string, +i, temp) { +temp = NULLSTR +for (i = length(string); i > 0; i--) +temp = temp substr(string, i, 1); +return temp +} +function join(array, separator, sortedIn, preserveNull, +i, j, saveSortedIn, temp) { +if (!sortedIn) +sortedIn = "compareByIndexFields" +temp = NULLSTR +j = 0 +if (isarray(array)) { +saveSortedIn = PROCINFO["sorted_in"] +PROCINFO["sorted_in"] = sortedIn +for (i in array) +if (preserveNull || array[i] != NULLSTR) +temp = j++ ? temp separator array[i] : array[i] +PROCINFO["sorted_in"] = saveSortedIn +} else +temp = array +return temp +} +function explode(string, array) { +split(string, array, NULLSTR) +} +function escapeChar(char) { +switch (char) { +case "b": +return "\b" +case "f": +return "\f" +case "n": +return "\n" +case "r": +return "\r" +case "t": +return "\t" +case "v": +return "\v" +case "u0026": +return "&" +case "u003c": +return "<" +case "u003e": +return ">" +case "u200b": +return "" +default: +return char +} +} +function literal(string, +c, cc, escaping, i, s) { +if (string !~ /^".*"$/) +return string +explode(string, s) +string = NULLSTR +escaping = 0 +for (i = 2; i < length(s); i++) { +c = s[i] +if (escaping) { +if (cc) { +cc = cc c +if (length(cc) == 5) { +string = string escapeChar(cc) +escaping = 0 +cc = NULLSTR +} +} else if (c == "u") { +cc = c +} else { +string = string escapeChar(c) +escaping = 0 +} +} else { +if (c == "\\") +escaping = 1 +else +string = string c +} +} +return string +} +function escape(string) { +gsub(/\\/, "\\\\", string) +gsub(/"/, "\\\"", string) +return string +} +function unescape(string) { +gsub(/\\"/, "\"", string) +gsub(/\\\\/, "\\", string) +return string +} +function parameterize(string, quotationMark) { +if (!quotationMark) +quotationMark = "'" +if (quotationMark == "'") { +gsub(/'/, "'\\''", string) +return "'" string "'" +} else { +return "\"" escape(string) "\"" +} +} +function unparameterize(string, temp) { +match(string, /^'(.*)'$/, temp) +if (temp[0]) { +string = temp[1] +gsub(/'\\''/, "'", string) +return string +} +match(string, /^"(.*)"$/, temp) +if (temp[0]) { +string = temp[1] +return unescape(string) +} +return string +} +function toString(value, inline, heredoc, valOnly, numSub, level, sortedIn, +i, items, j, k, p, saveSortedIn, temp, v) { +if (!level) level = 0 +if (!sortedIn) +sortedIn = "compareByIndexFields" +if (isarray(value)) { +saveSortedIn = PROCINFO["sorted_in"] +PROCINFO["sorted_in"] = sortedIn +p = 0 +for (i in value) { +split(i, j, SUBSEP); k = join(j, ",") +if (!numSub || !isnum(k)) k = parameterize(k, "\"") +v = toString(value[i], inline, heredoc, valOnly, numSub, level + 1, sortedIn) +if (!isarray(value[i])) v = parameterize(v, "\"") +if (valOnly) +items[p++] = inline ? v : (replicate("\t", level) v) +else +items[p++] = inline ? (k ": " v) : +(replicate("\t", level) k "\t" v) +} +PROCINFO["sorted_in"] = saveSortedIn +temp = inline ? join(items, ", ") : +("\n" join(items, "\n") "\n" replicate("\t", level)) +temp = valOnly ? ("[" temp "]") : ("{" temp "}") +return temp +} else { +if (heredoc) +return "'''\n" value "\n'''" +else +return value +} +} +function squeeze(line, preserveIndent) { +if (!preserveIndent) +gsub(/^[[:space:]]+/, NULLSTR, line) +gsub(/^[[:space:]]*#.*$/, NULLSTR, line) +gsub(/#[^"/]*$/, NULLSTR, line) +gsub(/[[:space:]]+$/, NULLSTR, line) +gsub(/[[:space:]]+\\$/, "\\", line) +return line +} +function yn(string) { +return (tolower(string) ~ /^([0fn]|off)/) ? 0 : 1 +} +function initAnsiCode() { +if (ENVIRON["TERM"] == "dumb") return +AnsiCode["reset"] = AnsiCode[0] = "\33[0m" +AnsiCode["bold"] = "\33[1m" +AnsiCode["underline"] = "\33[4m" +AnsiCode["negative"] = "\33[7m" +AnsiCode["no bold"] = "\33[22m" +AnsiCode["no underline"] = "\33[24m" +AnsiCode["positive"] = "\33[27m" +AnsiCode["black"] = "\33[30m" +AnsiCode["red"] = "\33[31m" +AnsiCode["green"] = "\33[32m" +AnsiCode["yellow"] = "\33[33m" +AnsiCode["blue"] = "\33[34m" +AnsiCode["magenta"] = "\33[35m" +AnsiCode["cyan"] = "\33[36m" +AnsiCode["gray"] = "\33[37m" +AnsiCode["default"] = "\33[39m" +AnsiCode["dark gray"] = "\33[90m" +AnsiCode["light red"] = "\33[91m" +AnsiCode["light green"] = "\33[92m" +AnsiCode["light yellow"] = "\33[93m" +AnsiCode["light blue"] = "\33[94m" +AnsiCode["light magenta"] = "\33[95m" +AnsiCode["light cyan"] = "\33[96m" +AnsiCode["white"] = "\33[97m" +} +function ansi(code, text) { +switch (code) { +case "bold": +return AnsiCode[code] text AnsiCode["no bold"] +case "underline": +return AnsiCode[code] text AnsiCode["no underline"] +case "negative": +return AnsiCode[code] text AnsiCode["positive"] +default: +return AnsiCode[code] text AnsiCode[0] +} +} +function w(text) { +print ansi("yellow", text) > STDERR +} +function e(text) { +print ansi("bold", ansi("yellow", text)) > STDERR +} +function wtf(text) { +print ansi("bold", ansi("red", text)) > STDERR +} +function d(text) { +print ansi("gray", text) > STDERR +} +function da(value, name, inline, heredoc, valOnly, numSub, sortedIn, +i, j, saveSortedIn) { +if (!name) +name = "_" +if (!sortedIn) +sortedIn = "compareByIndexFields" +d(name " = " toString(value, inline, heredoc, valOnly, numSub, 0, sortedIn)) +} +function assert(x, message) { +if (!message) +message = "[ERROR] Assertion failed." +if (x) +return x +else +e(message) +} +function initUrlEncoding() { +UrlEncoding["\t"] = "%09" +UrlEncoding["\n"] = "%0A" +UrlEncoding[" "] = "%20" +UrlEncoding["!"] = "%21" +UrlEncoding["\""] = "%22" +UrlEncoding["#"] = "%23" +UrlEncoding["$"] = "%24" +UrlEncoding["%"] = "%25" +UrlEncoding["&"] = "%26" +UrlEncoding["'"] = "%27" +UrlEncoding["("] = "%28" +UrlEncoding[")"] = "%29" +UrlEncoding["*"] = "%2A" +UrlEncoding["+"] = "%2B" +UrlEncoding[","] = "%2C" +UrlEncoding["-"] = "%2D" +UrlEncoding["."] = "%2E" +UrlEncoding["/"] = "%2F" +UrlEncoding[":"] = "%3A" +UrlEncoding[";"] = "%3B" +UrlEncoding["<"] = "%3C" +UrlEncoding["="] = "%3D" +UrlEncoding[">"] = "%3E" +UrlEncoding["?"] = "%3F" +UrlEncoding["@"] = "%40" +UrlEncoding["["] = "%5B" +UrlEncoding["\\"] = "%5C" +UrlEncoding["]"] = "%5D" +UrlEncoding["^"] = "%5E" +UrlEncoding["_"] = "%5F" +UrlEncoding["`"] = "%60" +UrlEncoding["{"] = "%7B" +UrlEncoding["|"] = "%7C" +UrlEncoding["}"] = "%7D" +UrlEncoding["~"] = "%7E" +} +function quote(string, i, r, s) { +r = NULLSTR +explode(string, s) +for (i = 1; i <= length(s); i++) +r = r (s[i] in UrlEncoding ? UrlEncoding[s[i]] : s[i]) +return r +} +function unquote(string, i, k, r, s, temp) { +r = NULLSTR +explode(string, s) +temp = NULLSTR +for (i = 1; i <= length(s); i++) +if (temp) { +temp = temp s[i] +if (length(temp) > 2) { +for (k in UrlEncoding) +if (temp == UrlEncoding[k]) { +r = r k +temp = NULLSTR +break +} +if (temp) { +r = r temp +temp = NULLSTR +} +} +} else { +if (s[i] != "%") +r = r s[i] +else +temp = s[i] +} +if (temp) +r = r temp +return r +} +function initUriSchemes() { +UriSchemes[0] = "file://" +UriSchemes[1] = "http://" +UriSchemes[2] = "https://" +} +function readFrom(file, line, text) { +if (!file) file = "/dev/stdin" +text = NULLSTR +while (getline line < file) +text = (text ? text "\n" : NULLSTR) line +return text +} +function writeTo(text, file) { +if (!file) file = "/dev/stdout" +print text > file +} +function getOutput(command, content, line) { +content = NULLSTR +while ((command |& getline line) > 0) +content = (content ? content "\n" : NULLSTR) line +close(command) +return content +} +function fileExists(file) { +return !system("test -f " parameterize(file)) +} +function dirExists(file) { +return !system("test -d " parameterize(file)) +} +function detectProgram(prog, arg, returnOutput, command, temp) { +command = prog " " arg SUPERR +command | getline temp +close(command) +if (returnOutput) +return temp +if (temp) +return prog +return NULLSTR +} +function getGitHead( line, group) { +if (fileExists(".git/HEAD")) { +getline line < ".git/HEAD" +match(line, /^ref: (.*)$/, group) +if (fileExists(".git/" group[1])) { +getline line < (".git/" group[1]) +return substr(line, 1, 7) +} else +return NULLSTR +} else +return NULLSTR +} +BEGIN { +initConst() +initAnsiCode() +initUrlEncoding() +initUriSchemes() +} +function initGawk( group) { +Gawk = "gawk" +GawkVersion = PROCINFO["version"] +split(PROCINFO["version"], group, ".") +if (group[1] < 4) { +e("[ERROR] Oops! Your gawk (version " GawkVersion ") "\ +"appears to be too old.\n"\ +" You need at least gawk 4.0.0 to run this program.") +exit 1 +} +} +function initBiDiTerm() { +if (ENVIRON["MLTERM"]) +BiDiTerm = "mlterm" +else if (ENVIRON["KONSOLE_VERSION"]) +BiDiTerm = "konsole" +} +function initBiDi() { +FriBidi = detectProgram("fribidi", "--version", 1) +BiDiNoPad = FriBidi ? "fribidi --nopad" : "rev" SUPERR +BiDi = FriBidi ? "fribidi --width %s" : +"rev" SUPERR "| sed \"s/'/\\\\\\'/\" | xargs -0 printf '%%%ss'" +} +function initRlwrap() { +Rlwrap = detectProgram("rlwrap", "--version") +} +function initEmacs() { +Emacs = detectProgram("emacs", "--version") +} +function initCurl() { +Curl = detectProgram("curl", "--version") +} +function l(value, name, inline, heredoc, valOnly, numSub, sortedIn) { +if (Option["debug"]) { +if (name) +da(value, name, inline, heredoc, valOnly, numSub, sortedIn) +else +d(value) +} +} +function m(string) { +if (Option["debug"]) +return ansi("cyan", string) RS +} +function newerVersion(ver1, ver2, i, group1, group2) { +split(ver1, group1, ".") +split(ver2, group2, ".") +for (i = 1; i <= 4; i++) { +if (group1[i] + 0 > group2[i] + 0) +return 1 +else if (group1[i] + 0 < group2[i] + 0) +return 0 +} +return 0 +} +function rlwrapMe( i, command) { +initRlwrap() +if (!Rlwrap) { +l(">> not found: rlwrap") +return 1 +} +if (ENVIRON["TRANS_ENTRY"]) { +command = Rlwrap " " ENVIRON["TRANS_ENTRY"] " "\ +parameterize("-no-rlwrap") +} else if (fileExists(ENVIRON["TRANS_DIR"] "/" EntryScript)) { +command = Rlwrap " sh "\ +parameterize(ENVIRON["TRANS_DIR"] "/" EntryScript)\ +" - " parameterize("-no-rlwrap") +} else { +l(">> not found: $TRANS_ENTRY or EntryPoint") +return 1 +} +for (i = 1; i < length(ARGV); i++) +if (ARGV[i]) +command = command " " parameterize(ARGV[i]) +l(">> forking: " command) +if (!system(command)) { +l(">> process exited with code 0") +exit ExitCode +} else { +l(">> process exited with non-zero return code") +return 1 +} +} +function emacsMe( i, params, el, command) { +initEmacs() +if (!Emacs) { +l(">> not found: emacs") +return 1 +} +params = "" +for (i = 1; i < length(ARGV); i++) +if (ARGV[i]) +params = params " " parameterize(ARGV[i], "\"") +if (ENVIRON["TRANS_ENTRY"]) { +el = "(progn (setq explicit-shell-file-name \"" ENVIRON["TRANS_ENTRY"] "\") "\ +"(setq explicit-" Command "-args '(\"-I\" \"-no-rlwrap\"" params ")) "\ +"(command-execute 'shell) (rename-buffer \"" Name "\"))" +} else if (fileExists(ENVIRON["TRANS_DIR"] "/" EntryScript)) { +el = "(progn (setq explicit-shell-file-name \"" "sh" "\") "\ +"(setq explicit-" "sh" "-args '(\"" ENVIRON["TRANS_DIR"] "/" EntryScript "\" \"-I\" \"-no-rlwrap\"" params ")) "\ +"(command-execute 'shell) (rename-buffer \"" Name "\"))" +} else { +l(">> not found: $TRANS_ENTRY or EntryPoint") +return 1 +} +command = Emacs " --eval " parameterize(el) +l(">> forking: " command) +if (!system(command)) { +l(">> process exited with code 0") +exit ExitCode +} else { +l(">> process exited with non-zero return code") +return 1 +} +} +function curl(url, output, command, content, line) { +initCurl() +if (!Curl) { +l(">> not found: curl") +w("[WARNING] curl is not found.") +return NULLSTR +} +command = Curl " --location --silent" +if (Option["proxy"]) +command = command " --proxy " parameterize(Option["proxy"]) +if (Option["user-agent"]) +command = command " --user-agent " parameterize(Option["user-agent"]) +command = command " " parameterize(url) +if (output) { +command = command " --output " parameterize(output) +system(command) +return NULLSTR +} +content = NULLSTR +while ((command |& getline line) > 0) +content = (content ? content "\n" : NULLSTR) line +close(command) +return content +} +function curlPost(url, data, output, command, content, line) { +initCurl() +if (!Curl) { +l(">> not found: curl") +w("[WARNING] curl is not found.") +return NULLSTR +} +command = Curl " --location --silent" +if (Option["proxy"]) +command = command " --proxy " parameterize(Option["proxy"]) +if (Option["user-agent"]) +command = command " --user-agent " parameterize(Option["user-agent"]) +command = command " --request POST --data " parameterize(data) +command = command " " parameterize(url) +if (output) { +command = command " --output " parameterize(output) +system(command) +return NULLSTR +} +content = NULLSTR +while ((command |& getline line) > 0) +content = (content ? content "\n" : NULLSTR) line +close(command) +return content +} +function dump(text, group, command, temp) { +command = "hexdump" " -v -e'1/1 \"%03u\" \" \"'" +command = "echo " parameterize(text) PIPE command +command | getline temp +split(temp, group, " ") +close(command) +return length(group) - 1 +} +function dumpX(text, group, command, temp) { +command = "hexdump" " -v -e'1/1 \"%02X\" \" \"'" +command = "echo " parameterize(text) PIPE command +command | getline temp +split(temp, group, " ") +close(command) +return length(group) - 1 +} +function base64(text, command, temp) { +if (detectProgram("uname", "-s", 1) == "Linux") +command = "echo -n " parameterize(text) PIPE "base64 -w0" +else +command = "echo -n " parameterize(text) PIPE "base64" +command = "bash -c " parameterize(command, "\"") +command | getline temp +close(command) +return temp +} +function uprintf(text, command, temp) { +command = "echo -en " parameterize(text) +command = "bash -c " parameterize(command, "\"") +command | getline temp +close(command) +return temp +} +function initLocale() { +Locale["af"]["name"] = "Afrikaans" +Locale["af"]["endonym"] = "Afrikaans" +Locale["af"]["translations-of"] = "Vertalings van %s" +Locale["af"]["definitions-of"] = "Definisies van %s" +Locale["af"]["synonyms"] = "Sinonieme" +Locale["af"]["examples"] = "Voorbeelde" +Locale["af"]["see-also"] = "Sien ook" +Locale["af"]["family"] = "Indo-European" +Locale["af"]["iso"] = "afr" +Locale["af"]["glotto"] = "afri1274" +Locale["af"]["script"] = "Latn" +Locale["sq"]["name"] = "Albanian" +Locale["sq"]["endonym"] = "Shqip" +Locale["sq"]["translations-of"] = "Përkthimet e %s" +Locale["sq"]["definitions-of"] = "Përkufizime të %s" +Locale["sq"]["synonyms"] = "Sinonime" +Locale["sq"]["examples"] = "Shembuj" +Locale["sq"]["see-also"] = "Shihni gjithashtu" +Locale["sq"]["family"] = "Indo-European" +Locale["sq"]["iso"] = "sqi" +Locale["sq"]["glotto"] = "alba1267" +Locale["sq"]["script"] = "Latn" +Locale["am"]["name"] = "Amharic" +Locale["am"]["endonym"] = "አማርኛ" +Locale["am"]["translations-of"] = "የ %s ትርጉሞች" +Locale["am"]["definitions-of"] = "የ %s ቃላት ፍችዎች" +Locale["am"]["synonyms"] = "ተመሳሳይ ቃላት" +Locale["am"]["examples"] = "ምሳሌዎች" +Locale["am"]["see-also"] = "የሚከተለውንም ይመልከቱ" +Locale["am"]["family"] = "Afro-Asiatic" +Locale["am"]["iso"] = "amh" +Locale["am"]["glotto"] = "amha1245" +Locale["am"]["script"] = "Ethi" +Locale["ar"]["name"] = "Arabic" +Locale["ar"]["endonym"] = "العربية" +Locale["ar"]["translations-of"] = "ترجمات %s" +Locale["ar"]["definitions-of"] = "تعريفات %s" +Locale["ar"]["synonyms"] = "مرادفات" +Locale["ar"]["examples"] = "أمثلة" +Locale["ar"]["see-also"] = "انظر أيضًا" +Locale["ar"]["family"] = "Afro-Asiatic" +Locale["ar"]["iso"] = "ara" +Locale["ar"]["glotto"] = "stan1318" +Locale["ar"]["script"] = "Arab" +Locale["ar"]["rtl"] = "true" +Locale["hy"]["name"] = "Armenian" +Locale["hy"]["endonym"] = "Հայերեն" +Locale["hy"]["translations-of"] = "%s-ի թարգմանությունները" +Locale["hy"]["definitions-of"] = "%s-ի սահմանումները" +Locale["hy"]["synonyms"] = "Հոմանիշներ" +Locale["hy"]["examples"] = "Օրինակներ" +Locale["hy"]["see-also"] = "Տես նաև" +Locale["hy"]["family"] = "Indo-European" +Locale["hy"]["iso"] = "hye" +Locale["hy"]["glotto"] = "nucl1235" +Locale["hy"]["script"] = "Armn" +Locale["az"]["name"] = "Azerbaijani" +Locale["az"]["endonym"] = "Azərbaycanca" +Locale["az"]["translations-of"] = "%s sözünün tərcüməsi" +Locale["az"]["definitions-of"] = "%s sözünün tərifləri" +Locale["az"]["synonyms"] = "Sinonimlər" +Locale["az"]["examples"] = "Nümunələr" +Locale["az"]["see-also"] = "Həmçinin, baxın:" +Locale["az"]["family"] = "Turkic" +Locale["az"]["iso"] = "aze" +Locale["az"]["glotto"] = "nort2697" +Locale["az"]["script"] = "Latn" +Locale["eu"]["name"] = "Basque" +Locale["eu"]["endonym"] = "Euskara" +Locale["eu"]["translations-of"] = "%s esapidearen itzulpena" +Locale["eu"]["definitions-of"] = "Honen definizioak: %s" +Locale["eu"]["synonyms"] = "Sinonimoak" +Locale["eu"]["examples"] = "Adibideak" +Locale["eu"]["see-also"] = "Ikusi hauek ere" +Locale["eu"]["family"] = "Language Isolate" +Locale["eu"]["iso"] = "eus" +Locale["eu"]["glotto"] = "basq1248" +Locale["eu"]["script"] = "Latn" +Locale["be"]["name"] = "Belarusian" +Locale["be"]["endonym"] = "беларуская" +Locale["be"]["translations-of"] = "Пераклады %s" +Locale["be"]["definitions-of"] = "Вызначэннi %s" +Locale["be"]["synonyms"] = "Сінонімы" +Locale["be"]["examples"] = "Прыклады" +Locale["be"]["see-also"] = "Гл. таксама" +Locale["be"]["family"] = "Indo-European" +Locale["be"]["iso"] = "bel" +Locale["be"]["glotto"] = "bela1254" +Locale["be"]["script"] = "Cyrl" +Locale["bn"]["name"] = "Bengali" +Locale["bn"]["endonym"] = "বাংলা" +Locale["bn"]["translations-of"] = "%s এর অনুবাদ" +Locale["bn"]["definitions-of"] = "%s এর সংজ্ঞা" +Locale["bn"]["synonyms"] = "প্রতিশব্দ" +Locale["bn"]["examples"] = "উদাহরণ" +Locale["bn"]["see-also"] = "আরো দেখুন" +Locale["bn"]["family"] = "Indo-European" +Locale["bn"]["iso"] = "ben" +Locale["bn"]["glotto"] = "beng1280" +Locale["bn"]["script"] = "Beng" +Locale["bs"]["name"] = "Bosnian" +Locale["bs"]["endonym"] = "Bosanski" +Locale["bs"]["translations-of"] = "Prijevod za: %s" +Locale["bs"]["definitions-of"] = "Definicije za %s" +Locale["bs"]["synonyms"] = "Sinonimi" +Locale["bs"]["examples"] = "Primjeri" +Locale["bs"]["see-also"] = "Pogledajte i" +Locale["bs"]["family"] = "Indo-European" +Locale["bs"]["iso"] = "bos" +Locale["bs"]["glotto"] = "bosn1245" +Locale["bs"]["script"] = "Latn" +Locale["bg"]["name"] = "Bulgarian" +Locale["bg"]["endonym"] = "български" +Locale["bg"]["translations-of"] = "Преводи на %s" +Locale["bg"]["definitions-of"] = "Дефиниции за %s" +Locale["bg"]["synonyms"] = "Синоними" +Locale["bg"]["examples"] = "Примери" +Locale["bg"]["see-also"] = "Вижте също" +Locale["bg"]["family"] = "Indo-European" +Locale["bg"]["iso"] = "bul" +Locale["bg"]["glotto"] = "bulg1262" +Locale["bg"]["script"] = "Cyrl" +Locale["ca"]["name"] = "Catalan" +Locale["ca"]["endonym"] = "Català" +Locale["ca"]["translations-of"] = "Traduccions per a %s" +Locale["ca"]["definitions-of"] = "Definicions de: %s" +Locale["ca"]["synonyms"] = "Sinònims" +Locale["ca"]["examples"] = "Exemples" +Locale["ca"]["see-also"] = "Vegeu també" +Locale["ca"]["family"] = "Indo-European" +Locale["ca"]["iso"] = "cat" +Locale["ca"]["glotto"] = "stan1289" +Locale["ca"]["script"] = "Latn" +Locale["ceb"]["name"] = "Cebuano" +Locale["ceb"]["endonym"] = "Cebuano" +Locale["ceb"]["translations-of"] = "%s Mga Paghubad sa PULONG_O_HUGPONG SA PAMULONG" +Locale["ceb"]["definitions-of"] = "Mga kahulugan sa %s" +Locale["ceb"]["synonyms"] = "Mga Kapulong" +Locale["ceb"]["examples"] = "Mga pananglitan:" +Locale["ceb"]["see-also"] = "Kitaa pag-usab" +Locale["ceb"]["family"] = "Austronesian" +Locale["ceb"]["iso"] = "ceb" +Locale["ceb"]["glotto"] = "cebu1242" +Locale["ceb"]["script"] = "Latn" +Locale["ny"]["name"] = "Chichewa" +Locale["ny"]["endonym"] = "Nyanja" +Locale["ny"]["translations-of"] = "Matanthauzidwe a %s" +Locale["ny"]["definitions-of"] = "Mamasulidwe a %s" +Locale["ny"]["synonyms"] = "Mau ofanana" +Locale["ny"]["examples"] = "Zitsanzo" +Locale["ny"]["see-also"] = "Onaninso" +Locale["ny"]["family"] = "Atlantic-Congo" +Locale["ny"]["iso"] = "nya" +Locale["ny"]["glotto"] = "nyan1308" +Locale["ny"]["script"] = "Latn" +Locale["zh-CN"]["name"] = "Chinese Simplified" +Locale["zh-CN"]["endonym"] = "简体中文" +Locale["zh-CN"]["translations-of"] = "%s 的翻译" +Locale["zh-CN"]["definitions-of"] = "%s的定义" +Locale["zh-CN"]["synonyms"] = "同义词" +Locale["zh-CN"]["examples"] = "示例" +Locale["zh-CN"]["see-also"] = "另请参阅" +Locale["zh-CN"]["family"] = "Sino-Tibetan" +Locale["zh-CN"]["iso"] = "zho-CN" +Locale["zh-CN"]["glotto"] = "mand1415" +Locale["zh-CN"]["script"] = "Hans" +Locale["zh-CN"]["dictionary"] = "true" +Locale["zh-TW"]["name"] = "Chinese Traditional" +Locale["zh-TW"]["endonym"] = "正體中文" +Locale["zh-TW"]["translations-of"] = "「%s」的翻譯" +Locale["zh-TW"]["definitions-of"] = "「%s」的定義" +Locale["zh-TW"]["synonyms"] = "同義詞" +Locale["zh-TW"]["examples"] = "例句" +Locale["zh-TW"]["see-also"] = "另請參閱" +Locale["zh-TW"]["family"] = "Sino-Tibetan" +Locale["zh-TW"]["iso"] = "zho-TW" +Locale["zh-TW"]["glotto"] = "mand1415" +Locale["zh-TW"]["script"] = "Hant" +Locale["zh-TW"]["dictionary"] = "true" +Locale["co"]["name"] = "Corsican" +Locale["co"]["endonym"] = "Corsu" +Locale["co"]["translations-of"] = "Traductions de %s" +Locale["co"]["definitions-of"] = "Définitions de %s" +Locale["co"]["synonyms"] = "Synonymes" +Locale["co"]["examples"] = "Exemples" +Locale["co"]["see-also"] = "Voir aussi" +Locale["co"]["family"] = "Indo-European" +Locale["co"]["iso"] = "cos" +Locale["co"]["glotto"] = "cors1242" +Locale["co"]["script"] = "Latn" +Locale["hr"]["name"] = "Croatian" +Locale["hr"]["endonym"] = "Hrvatski" +Locale["hr"]["translations-of"] = "Prijevodi riječi ili izraza %s" +Locale["hr"]["definitions-of"] = "Definicije riječi ili izraza %s" +Locale["hr"]["synonyms"] = "Sinonimi" +Locale["hr"]["examples"] = "Primjeri" +Locale["hr"]["see-also"] = "Također pogledajte" +Locale["hr"]["family"] = "Indo-European" +Locale["hr"]["iso"] = "hrv" +Locale["hr"]["glotto"] = "croa1245" +Locale["hr"]["script"] = "Latn" +Locale["cs"]["name"] = "Czech" +Locale["cs"]["endonym"] = "Čeština" +Locale["cs"]["translations-of"] = "Překlad výrazu %s" +Locale["cs"]["definitions-of"] = "Definice výrazu %s" +Locale["cs"]["synonyms"] = "Synonyma" +Locale["cs"]["examples"] = "Příklady" +Locale["cs"]["see-also"] = "Viz také" +Locale["cs"]["family"] = "Indo-European" +Locale["cs"]["iso"] = "ces" +Locale["cs"]["glotto"] = "czec1258" +Locale["cs"]["script"] = "Latn" +Locale["da"]["name"] = "Danish" +Locale["da"]["endonym"] = "Dansk" +Locale["da"]["translations-of"] = "Oversættelser af %s" +Locale["da"]["definitions-of"] = "Definitioner af %s" +Locale["da"]["synonyms"] = "Synonymer" +Locale["da"]["examples"] = "Eksempler" +Locale["da"]["see-also"] = "Se også" +Locale["da"]["family"] = "Indo-European" +Locale["da"]["iso"] = "dan" +Locale["da"]["glotto"] = "dani1285" +Locale["da"]["script"] = "Latn" +Locale["nl"]["name"] = "Dutch" +Locale["nl"]["endonym"] = "Nederlands" +Locale["nl"]["translations-of"] = "Vertalingen van %s" +Locale["nl"]["definitions-of"] = "Definities van %s" +Locale["nl"]["synonyms"] = "Synoniemen" +Locale["nl"]["examples"] = "Voorbeelden" +Locale["nl"]["see-also"] = "Zie ook" +Locale["nl"]["family"] = "Indo-European" +Locale["nl"]["iso"] = "nld" +Locale["nl"]["glotto"] = "dutc1256" +Locale["nl"]["script"] = "Latn" +Locale["nl"]["dictionary"] = "true" +Locale["en"]["name"] = "English" +Locale["en"]["endonym"] = "English" +Locale["en"]["translations-of"] = "Translations of %s" +Locale["en"]["definitions-of"] = "Definitions of %s" +Locale["en"]["synonyms"] = "Synonyms" +Locale["en"]["examples"] = "Examples" +Locale["en"]["see-also"] = "See also" +Locale["en"]["family"] = "Indo-European" +Locale["en"]["iso"] = "eng" +Locale["en"]["glotto"] = "stan1293" +Locale["en"]["script"] = "Latn" +Locale["en"]["dictionary"] = "true" +Locale["eo"]["name"] = "Esperanto" +Locale["eo"]["endonym"] = "Esperanto" +Locale["eo"]["translations-of"] = "Tradukoj de %s" +Locale["eo"]["definitions-of"] = "Difinoj de %s" +Locale["eo"]["synonyms"] = "Sinonimoj" +Locale["eo"]["examples"] = "Ekzemploj" +Locale["eo"]["see-also"] = "Vidu ankaŭ" +Locale["eo"]["family"] = "Artificial Language" +Locale["eo"]["iso"] = "epo" +Locale["eo"]["glotto"] = "espe1235" +Locale["eo"]["script"] = "Latn" +Locale["et"]["name"] = "Estonian" +Locale["et"]["endonym"] = "Eesti" +Locale["et"]["translations-of"] = "Sõna(de) %s tõlked" +Locale["et"]["definitions-of"] = "Sõna(de) %s definitsioonid" +Locale["et"]["synonyms"] = "Sünonüümid" +Locale["et"]["examples"] = "Näited" +Locale["et"]["see-also"] = "Vt ka" +Locale["et"]["family"] = "Uralic" +Locale["et"]["iso"] = "est" +Locale["et"]["glotto"] = "esto1258" +Locale["et"]["script"] = "Latn" +Locale["tl"]["name"] = "Filipino" +Locale["tl"]["endonym"] = "Tagalog" +Locale["tl"]["translations-of"] = "Mga pagsasalin ng %s" +Locale["tl"]["definitions-of"] = "Mga kahulugan ng %s" +Locale["tl"]["synonyms"] = "Mga Kasingkahulugan" +Locale["tl"]["examples"] = "Mga Halimbawa" +Locale["tl"]["see-also"] = "Tingnan rin ang" +Locale["tl"]["family"] = "Austronesian" +Locale["tl"]["iso"] = "tgl" +Locale["tl"]["glotto"] = "taga1270" +Locale["tl"]["script"] = "Latn" +Locale["fi"]["name"] = "Finnish" +Locale["fi"]["endonym"] = "Suomi" +Locale["fi"]["translations-of"] = "Käännökset tekstille %s" +Locale["fi"]["definitions-of"] = "Määritelmät kohteelle %s" +Locale["fi"]["synonyms"] = "Synonyymit" +Locale["fi"]["examples"] = "Esimerkkejä" +Locale["fi"]["see-also"] = "Katso myös" +Locale["fi"]["family"] = "Uralic" +Locale["fi"]["iso"] = "fin" +Locale["fi"]["glotto"] = "finn1318" +Locale["fi"]["script"] = "Latn" +Locale["fr"]["name"] = "French" +Locale["fr"]["endonym"] = "Français" +Locale["fr"]["translations-of"] = "Traductions de %s" +Locale["fr"]["definitions-of"] = "Définitions de %s" +Locale["fr"]["synonyms"] = "Synonymes" +Locale["fr"]["examples"] = "Exemples" +Locale["fr"]["see-also"] = "Voir aussi" +Locale["fr"]["family"] = "Indo-European" +Locale["fr"]["iso"] = "fra" +Locale["fr"]["glotto"] = "stan1290" +Locale["fr"]["script"] = "Latn" +Locale["fr"]["dictionary"] = "true" +Locale["gl"]["name"] = "Galician" +Locale["gl"]["endonym"] = "Galego" +Locale["gl"]["translations-of"] = "Traducións de %s" +Locale["gl"]["definitions-of"] = "Definicións de %s" +Locale["gl"]["synonyms"] = "Sinónimos" +Locale["gl"]["examples"] = "Exemplos" +Locale["gl"]["see-also"] = "Ver tamén" +Locale["gl"]["family"] = "Indo-European" +Locale["gl"]["iso"] = "glg" +Locale["gl"]["glotto"] = "gali1258" +Locale["gl"]["script"] = "Latn" +Locale["ka"]["name"] = "Georgian" +Locale["ka"]["endonym"] = "ქართული" +Locale["ka"]["translations-of"] = "%s-ის თარგმანები" +Locale["ka"]["definitions-of"] = "%s-ის განსაზღვრებები" +Locale["ka"]["synonyms"] = "სინონიმები" +Locale["ka"]["examples"] = "მაგალითები" +Locale["ka"]["see-also"] = "ასევე იხილეთ" +Locale["ka"]["family"] = "Kartvelian" +Locale["ka"]["iso"] = "kat" +Locale["ka"]["glotto"] = "nucl1302" +Locale["ka"]["script"] = "Geor" +Locale["de"]["name"] = "German" +Locale["de"]["endonym"] = "Deutsch" +Locale["de"]["translations-of"] = "Übersetzungen für %s" +Locale["de"]["definitions-of"] = "Definitionen von %s" +Locale["de"]["synonyms"] = "Synonyme" +Locale["de"]["examples"] = "Beispiele" +Locale["de"]["see-also"] = "Siehe auch" +Locale["de"]["family"] = "Indo-European" +Locale["de"]["iso"] = "deu" +Locale["de"]["glotto"] = "stan1295" +Locale["de"]["script"] = "Latn" +Locale["de"]["dictionary"] = "true" +Locale["el"]["name"] = "Greek" +Locale["el"]["endonym"] = "Ελληνικά" +Locale["el"]["translations-of"] = "Μεταφράσεις του %s" +Locale["el"]["definitions-of"] = "Όρισμοί %s" +Locale["el"]["synonyms"] = "Συνώνυμα" +Locale["el"]["examples"] = "Παραδείγματα" +Locale["el"]["see-also"] = "Δείτε επίσης" +Locale["el"]["family"] = "Indo-European" +Locale["el"]["iso"] = "ell" +Locale["el"]["glotto"] = "mode1248" +Locale["el"]["script"] = "Grek" +Locale["gu"]["name"] = "Gujarati" +Locale["gu"]["endonym"] = "ગુજરાતી" +Locale["gu"]["translations-of"] = "%s ના અનુવાદ" +Locale["gu"]["definitions-of"] = "%s ની વ્યાખ્યાઓ" +Locale["gu"]["synonyms"] = "સમાનાર્થી" +Locale["gu"]["examples"] = "ઉદાહરણો" +Locale["gu"]["see-also"] = "આ પણ જુઓ" +Locale["gu"]["family"] = "Indo-European" +Locale["gu"]["iso"] = "guj" +Locale["gu"]["glotto"] = "guja1252" +Locale["gu"]["script"] = "Gujr" +Locale["ht"]["name"] = "Haitian Creole" +Locale["ht"]["endonym"] = "Kreyòl Ayisyen" +Locale["ht"]["translations-of"] = "Tradiksyon %s" +Locale["ht"]["definitions-of"] = "Definisyon nan %s" +Locale["ht"]["synonyms"] = "Sinonim" +Locale["ht"]["examples"] = "Egzanp:" +Locale["ht"]["see-also"] = "Wè tou" +Locale["ht"]["family"] = "Indo-European" +Locale["ht"]["iso"] = "hat" +Locale["ht"]["glotto"] = "hait1244" +Locale["ht"]["script"] = "Latn" +Locale["haw"]["name"] = "Hawaiian" +Locale["haw"]["endonym"] = "ʻŌlelo Hawaiʻi" +Locale["haw"]["family"] = "Austronesian" +Locale["haw"]["iso"] = "haw" +Locale["haw"]["glotto"] = "hawa1245" +Locale["haw"]["script"] = "Latn" +Locale["ha"]["name"] = "Hausa" +Locale["ha"]["endonym"] = "Hausa" +Locale["ha"]["translations-of"] = "Fassarar %s" +Locale["ha"]["definitions-of"] = "Ma'anoni na %s" +Locale["ha"]["synonyms"] = "Masu kamancin ma'ana" +Locale["ha"]["examples"] = "Misalai" +Locale["ha"]["see-also"] = "Duba kuma" +Locale["ha"]["family"] = "Afro-Asiatic" +Locale["ha"]["iso"] = "hau" +Locale["ha"]["glotto"] = "haus1257" +Locale["ha"]["script"] = "Latn" +Locale["he"]["name"] = "Hebrew" +Locale["he"]["endonym"] = "עִבְרִית" +Locale["he"]["translations-of"] = "תרגומים של %s" +Locale["he"]["definitions-of"] = "הגדרות של %s" +Locale["he"]["synonyms"] = "מילים נרדפות" +Locale["he"]["examples"] = "דוגמאות" +Locale["he"]["see-also"] = "ראה גם" +Locale["he"]["family"] = "Afro-Asiatic" +Locale["he"]["iso"] = "heb" +Locale["he"]["glotto"] = "hebr1245" +Locale["he"]["script"] = "Hebr" +Locale["he"]["rtl"] = "true" +Locale["hi"]["name"] = "Hindi" +Locale["hi"]["endonym"] = "हिन्दी" +Locale["hi"]["translations-of"] = "%s के अनुवाद" +Locale["hi"]["definitions-of"] = "%s की परिभाषाएं" +Locale["hi"]["synonyms"] = "समानार्थी" +Locale["hi"]["examples"] = "उदाहरण" +Locale["hi"]["see-also"] = "यह भी देखें" +Locale["hi"]["family"] = "Indo-European" +Locale["hi"]["iso"] = "hin" +Locale["hi"]["glotto"] = "hind1269" +Locale["hi"]["script"] = "Deva" +Locale["hmn"]["name"] = "Hmong" +Locale["hmn"]["endonym"] = "Hmoob" +Locale["hmn"]["translations-of"] = "Lus txhais: %s" +Locale["hmn"]["family"] = "Hmong-Mien" +Locale["hmn"]["iso"] = "hmn" +Locale["hmn"]["glotto"] = "firs1234" +Locale["hmn"]["script"] = "Latn" +Locale["hu"]["name"] = "Hungarian" +Locale["hu"]["endonym"] = "Magyar" +Locale["hu"]["translations-of"] = "%s fordításai" +Locale["hu"]["definitions-of"] = "%s jelentései" +Locale["hu"]["synonyms"] = "Szinonimák" +Locale["hu"]["examples"] = "Példák" +Locale["hu"]["see-also"] = "Lásd még" +Locale["hu"]["family"] = "Uralic" +Locale["hu"]["iso"] = "hun" +Locale["hu"]["glotto"] = "hung1274" +Locale["hu"]["script"] = "Latn" +Locale["is"]["name"] = "Icelandic" +Locale["is"]["endonym"] = "Íslenska" +Locale["is"]["translations-of"] = "Þýðingar á %s" +Locale["is"]["definitions-of"] = "Skilgreiningar á" +Locale["is"]["synonyms"] = "Samheiti" +Locale["is"]["examples"] = "Dæmi" +Locale["is"]["see-also"] = "Sjá einnig" +Locale["is"]["family"] = "Indo-European" +Locale["is"]["iso"] = "isl" +Locale["is"]["glotto"] = "icel1247" +Locale["is"]["script"] = "Latn" +Locale["ig"]["name"] = "Igbo" +Locale["ig"]["endonym"] = "Igbo" +Locale["ig"]["translations-of"] = "Ntụgharị asụsụ nke %s" +Locale["ig"]["definitions-of"] = "Nkọwapụta nke %s" +Locale["ig"]["synonyms"] = "Okwu oyiri" +Locale["ig"]["examples"] = "Ọmụmaatụ" +Locale["ig"]["see-also"] = "Hụkwuo" +Locale["ig"]["family"] = "Atlantic-Congo" +Locale["ig"]["iso"] = "ibo" +Locale["ig"]["glotto"] = "nucl1417" +Locale["ig"]["script"] = "Latn" +Locale["id"]["name"] = "Indonesian" +Locale["id"]["endonym"] = "Bahasa Indonesia" +Locale["id"]["translations-of"] = "Terjemahan dari %s" +Locale["id"]["definitions-of"] = "Definisi %s" +Locale["id"]["synonyms"] = "Sinonim" +Locale["id"]["examples"] = "Contoh" +Locale["id"]["see-also"] = "Lihat juga" +Locale["id"]["family"] = "Austronesian" +Locale["id"]["iso"] = "ind" +Locale["id"]["glotto"] = "indo1316" +Locale["id"]["script"] = "Latn" +Locale["ga"]["name"] = "Irish" +Locale["ga"]["endonym"] = "Gaeilge" +Locale["ga"]["translations-of"] = "Aistriúcháin ar %s" +Locale["ga"]["definitions-of"] = "Sainmhínithe ar %s" +Locale["ga"]["synonyms"] = "Comhchiallaigh" +Locale["ga"]["examples"] = "Samplaí" +Locale["ga"]["see-also"] = "féach freisin" +Locale["ga"]["family"] = "Indo-European" +Locale["ga"]["iso"] = "gle" +Locale["ga"]["glotto"] = "iris1253" +Locale["ga"]["script"] = "Latn" +Locale["it"]["name"] = "Italian" +Locale["it"]["endonym"] = "Italiano" +Locale["it"]["translations-of"] = "Traduzioni di %s" +Locale["it"]["definitions-of"] = "Definizioni di %s" +Locale["it"]["synonyms"] = "Sinonimi" +Locale["it"]["examples"] = "Esempi" +Locale["it"]["see-also"] = "Vedi anche" +Locale["it"]["family"] = "Indo-European" +Locale["it"]["iso"] = "ita" +Locale["it"]["glotto"] = "ital1282" +Locale["it"]["script"] = "Latn" +Locale["it"]["dictionary"] = "true" +Locale["ja"]["name"] = "Japanese" +Locale["ja"]["endonym"] = "日本語" +Locale["ja"]["translations-of"] = "「%s」の翻訳" +Locale["ja"]["definitions-of"] = "%s の定義" +Locale["ja"]["synonyms"] = "同義語" +Locale["ja"]["examples"] = "例" +Locale["ja"]["see-also"] = "関連項目" +Locale["ja"]["family"] = "Japonic" +Locale["ja"]["iso"] = "jpn" +Locale["ja"]["glotto"] = "nucl1643" +Locale["ja"]["script"] = "Jpan" +Locale["ja"]["dictionary"] = "true" +Locale["jv"]["name"] = "Javanese" +Locale["jv"]["endonym"] = "Basa Jawa" +Locale["jv"]["translations-of"] = "Terjemahan %s" +Locale["jv"]["definitions-of"] = "Arti %s" +Locale["jv"]["synonyms"] = "Sinonim" +Locale["jv"]["examples"] = "Conto" +Locale["jv"]["see-also"] = "Deleng uga" +Locale["jv"]["family"] = "Austronesian" +Locale["jv"]["iso"] = "jav" +Locale["jv"]["glotto"] = "java1254" +Locale["jv"]["script"] = "Latn" +Locale["kn"]["name"] = "Kannada" +Locale["kn"]["endonym"] = "ಕನ್ನಡ" +Locale["kn"]["translations-of"] = "%s ನ ಅನುವಾದಗಳು" +Locale["kn"]["definitions-of"] = "%s ನ ವ್ಯಾಖ್ಯಾನಗಳು" +Locale["kn"]["synonyms"] = "ಸಮಾನಾರ್ಥಕಗಳು" +Locale["kn"]["examples"] = "ಉದಾಹರಣೆಗಳು" +Locale["kn"]["see-also"] = "ಇದನ್ನೂ ಗಮನಿಸಿ" +Locale["kn"]["family"] = "Dravidian" +Locale["kn"]["iso"] = "kan" +Locale["kn"]["glotto"] = "nucl1305" +Locale["kn"]["script"] = "Knda" +Locale["kk"]["name"] = "Kazakh" +Locale["kk"]["endonym"] = "Қазақ тілі" +Locale["kk"]["translations-of"] = "%s аудармалары" +Locale["kk"]["definitions-of"] = "%s анықтамалары" +Locale["kk"]["synonyms"] = "Синонимдер" +Locale["kk"]["examples"] = "Мысалдар" +Locale["kk"]["see-also"] = "Келесі тізімді де көріңіз:" +Locale["kk"]["family"] = "Turkic" +Locale["kk"]["iso"] = "kaz" +Locale["kk"]["glotto"] = "kaza1248" +Locale["kk"]["script"] = "Cyrl" +Locale["km"]["name"] = "Khmer" +Locale["km"]["endonym"] = "ភាសាខ្មែរ" +Locale["km"]["translations-of"] = "ការ​បក​ប្រែ​នៃ %s" +Locale["km"]["definitions-of"] = "និយមន័យ​នៃ​ %s" +Locale["km"]["synonyms"] = "សទិសន័យ" +Locale["km"]["examples"] = "ឧទាហរណ៍" +Locale["km"]["see-also"] = "មើល​ផង​ដែរ" +Locale["km"]["family"] = "Austroasiatic" +Locale["km"]["iso"] = "khm" +Locale["km"]["glotto"] = "cent1989" +Locale["km"]["script"] = "Khmr" +Locale["ko"]["name"] = "Korean" +Locale["ko"]["endonym"] = "한국어" +Locale["ko"]["translations-of"] = "%s의 번역" +Locale["ko"]["definitions-of"] = "%s의 정의" +Locale["ko"]["synonyms"] = "동의어" +Locale["ko"]["examples"] = "예문" +Locale["ko"]["see-also"] = "참조" +Locale["ko"]["family"] = "Koreanic" +Locale["ko"]["iso"] = "kor" +Locale["ko"]["glotto"] = "kore1280" +Locale["ko"]["script"] = "Kore" +Locale["ko"]["dictionary"] = "true" +Locale["ku"]["name"] = "Kurdish" +Locale["ku"]["endonym"] = "Kurdî" +Locale["ku"]["family"] = "Indo-European" +Locale["ku"]["iso"] = "kur" +Locale["ku"]["glotto"] = "kurd1259" +Locale["ku"]["script"] = "Latn" +Locale["ky"]["name"] = "Kyrgyz" +Locale["ky"]["endonym"] = "Кыргызча" +Locale["ky"]["translations-of"] = "%s котормосу" +Locale["ky"]["definitions-of"] = "%s аныктамасы" +Locale["ky"]["synonyms"] = "Синонимдер" +Locale["ky"]["examples"] = "Мисалдар" +Locale["ky"]["see-also"] = "Дагы караңыз" +Locale["ky"]["family"] = "Turkic" +Locale["ky"]["iso"] = "kir" +Locale["ky"]["glotto"] = "kirg1245" +Locale["ky"]["script"] = "Cyrl" +Locale["lo"]["name"] = "Lao" +Locale["lo"]["endonym"] = "ລາວ" +Locale["lo"]["translations-of"] = "ຄຳ​ແປ​ສຳລັບ %s" +Locale["lo"]["definitions-of"] = "ຄວາມໝາຍຂອງ %s" +Locale["lo"]["synonyms"] = "ຄຳທີ່ຄ້າຍກັນ %s" +Locale["lo"]["examples"] = "ຕົວຢ່າງ" +Locale["lo"]["see-also"] = "ເບິ່ງ​ເພີ່ມ​ເຕີມ" +Locale["lo"]["family"] = "Tai-Kadai" +Locale["lo"]["iso"] = "lao" +Locale["lo"]["glotto"] = "laoo1244" +Locale["lo"]["script"] = "Laoo" +Locale["la"]["name"] = "Latin" +Locale["la"]["endonym"] = "Latina" +Locale["la"]["translations-of"] = "Versio de %s" +Locale["la"]["family"] = "Indo-European" +Locale["la"]["iso"] = "lat" +Locale["la"]["glotto"] = "lati1261" +Locale["la"]["script"] = "Latn" +Locale["lv"]["name"] = "Latvian" +Locale["lv"]["endonym"] = "Latviešu" +Locale["lv"]["translations-of"] = "%s tulkojumi" +Locale["lv"]["definitions-of"] = "%s definīcijas" +Locale["lv"]["synonyms"] = "Sinonīmi" +Locale["lv"]["examples"] = "Piemēri" +Locale["lv"]["see-also"] = "Skatiet arī" +Locale["lv"]["family"] = "Indo-European" +Locale["lv"]["iso"] = "lav" +Locale["lv"]["glotto"] = "latv1249" +Locale["lv"]["script"] = "Latn" +Locale["lt"]["name"] = "Lithuanian" +Locale["lt"]["endonym"] = "Lietuvių" +Locale["lt"]["translations-of"] = "„%s“ vertimai" +Locale["lt"]["definitions-of"] = "„%s“ apibrėžimai" +Locale["lt"]["synonyms"] = "Sinonimai" +Locale["lt"]["examples"] = "Pavyzdžiai" +Locale["lt"]["see-also"] = "Taip pat žiūrėkite" +Locale["lt"]["family"] = "Indo-European" +Locale["lt"]["iso"] = "lit" +Locale["lt"]["glotto"] = "lith1251" +Locale["lt"]["script"] = "Latn" +Locale["lb"]["name"] = "Luxembourgish" +Locale["lb"]["endonym"] = "Lëtzebuergesch" +Locale["lb"]["family"] = "Indo-European" +Locale["lb"]["iso"] = "ltz" +Locale["lb"]["glotto"] = "luxe1241" +Locale["lb"]["script"] = "Latn" +Locale["mk"]["name"] = "Macedonian" +Locale["mk"]["endonym"] = "Македонски" +Locale["mk"]["translations-of"] = "Преводи на %s" +Locale["mk"]["definitions-of"] = "Дефиниции на %s" +Locale["mk"]["synonyms"] = "Синоними" +Locale["mk"]["examples"] = "Примери" +Locale["mk"]["see-also"] = "Види и" +Locale["mk"]["family"] = "Indo-European" +Locale["mk"]["iso"] = "mkd" +Locale["mk"]["glotto"] = "mace1250" +Locale["mk"]["script"] = "Cyrl" +Locale["mg"]["name"] = "Malagasy" +Locale["mg"]["endonym"] = "Malagasy" +Locale["mg"]["translations-of"] = "Dikan'ny %s" +Locale["mg"]["definitions-of"] = "Famaritana ny %s" +Locale["mg"]["synonyms"] = "Mitovy hevitra" +Locale["mg"]["examples"] = "Ohatra" +Locale["mg"]["see-also"] = "Jereo ihany koa" +Locale["mg"]["family"] = "Austronesian" +Locale["mg"]["iso"] = "mlg" +Locale["mg"]["glotto"] = "plat1254" +Locale["mg"]["script"] = "Latn" +Locale["ms"]["name"] = "Malay" +Locale["ms"]["endonym"] = "Bahasa Melayu" +Locale["ms"]["translations-of"] = "Terjemahan %s" +Locale["ms"]["definitions-of"] = "Takrif %s" +Locale["ms"]["synonyms"] = "Sinonim" +Locale["ms"]["examples"] = "Contoh" +Locale["ms"]["see-also"] = "Lihat juga" +Locale["ms"]["family"] = "Austronesian" +Locale["ms"]["iso"] = "msa" +Locale["ms"]["glotto"] = "stan1306" +Locale["ms"]["script"] = "Latn" +Locale["ml"]["name"] = "Malayalam" +Locale["ml"]["endonym"] = "മലയാളം" +Locale["ml"]["translations-of"] = "%s എന്നതിന്റെ വിവർത്തനങ്ങൾ" +Locale["ml"]["definitions-of"] = "%s എന്നതിന്റെ നിർവ്വചനങ്ങൾ" +Locale["ml"]["synonyms"] = "പര്യായങ്ങള്‍" +Locale["ml"]["examples"] = "ഉദാഹരണങ്ങള്‍" +Locale["ml"]["see-also"] = "ഇതും കാണുക" +Locale["ml"]["family"] = "Dravidian" +Locale["ml"]["iso"] = "mal" +Locale["ml"]["glotto"] = "mala1464" +Locale["ml"]["script"] = "Mlym" +Locale["mt"]["name"] = "Maltese" +Locale["mt"]["endonym"] = "Malti" +Locale["mt"]["translations-of"] = "Traduzzjonijiet ta' %s" +Locale["mt"]["definitions-of"] = "Definizzjonijiet ta' %s" +Locale["mt"]["synonyms"] = "Sinonimi" +Locale["mt"]["examples"] = "Eżempji" +Locale["mt"]["see-also"] = "Ara wkoll" +Locale["mt"]["family"] = "Afro-Asiatic" +Locale["mt"]["iso"] = "mlt" +Locale["mt"]["glotto"] = "malt1254" +Locale["mt"]["script"] = "Latn" +Locale["mi"]["name"] = "Maori" +Locale["mi"]["endonym"] = "Māori" +Locale["mi"]["translations-of"] = "Ngā whakamāoritanga o %s" +Locale["mi"]["definitions-of"] = "Ngā whakamārama o %s" +Locale["mi"]["synonyms"] = "Ngā Kupu Taurite" +Locale["mi"]["examples"] = "Ngā Tauira:" +Locale["mi"]["see-also"] = "Tiro hoki:" +Locale["mi"]["family"] = "Austronesian" +Locale["mi"]["iso"] = "mri" +Locale["mi"]["glotto"] = "maor1246" +Locale["mi"]["script"] = "Latn" +Locale["mr"]["name"] = "Marathi" +Locale["mr"]["endonym"] = "मराठी" +Locale["mr"]["translations-of"] = "%s ची भाषांतरे" +Locale["mr"]["definitions-of"] = "%s च्या व्याख्या" +Locale["mr"]["synonyms"] = "समानार्थी शब्द" +Locale["mr"]["examples"] = "उदाहरणे" +Locale["mr"]["see-also"] = "हे देखील पहा" +Locale["mr"]["family"] = "Indo-European" +Locale["mr"]["iso"] = "mar" +Locale["mr"]["glotto"] = "mara1378" +Locale["mr"]["script"] = "Deva" +Locale["mn"]["name"] = "Mongolian" +Locale["mn"]["endonym"] = "Монгол" +Locale["mn"]["translations-of"] = "%s-н орчуулга" +Locale["mn"]["definitions-of"] = "%s үгийн тодорхойлолт" +Locale["mn"]["synonyms"] = "Ойролцоо утгатай" +Locale["mn"]["examples"] = "Жишээнүүд" +Locale["mn"]["see-also"] = "Мөн харах" +Locale["mn"]["family"] = "Mongolic" +Locale["mn"]["iso"] = "mon" +Locale["mn"]["glotto"] = "mong1331" +Locale["mn"]["script"] = "Cyrl" +Locale["my"]["name"] = "Myanmar" +Locale["my"]["endonym"] = "မြန်မာစာ" +Locale["my"]["translations-of"] = "%s၏ ဘာသာပြန်ဆိုချက်များ" +Locale["my"]["definitions-of"] = "%s၏ အနက်ဖွင့်ဆိုချက်များ" +Locale["my"]["synonyms"] = "ကြောင်းတူသံကွဲများ" +Locale["my"]["examples"] = "ဥပမာ" +Locale["my"]["see-also"] = "ဖော်ပြပါများကိုလဲ ကြည့်ပါ" +Locale["my"]["family"] = "Sino-Tibetan" +Locale["my"]["iso"] = "mya" +Locale["my"]["glotto"] = "nucl1310" +Locale["my"]["script"] = "Mymr" +Locale["ne"]["name"] = "Nepali" +Locale["ne"]["endonym"] = "नेपाली" +Locale["ne"]["translations-of"] = "%sका अनुवाद" +Locale["ne"]["definitions-of"] = "%sको परिभाषा" +Locale["ne"]["synonyms"] = "समानार्थीहरू" +Locale["ne"]["examples"] = "उदाहरणहरु" +Locale["ne"]["see-also"] = "यो पनि हेर्नुहोस्" +Locale["ne"]["family"] = "Indo-European" +Locale["ne"]["iso"] = "nep" +Locale["ne"]["glotto"] = "nepa1254" +Locale["ne"]["script"] = "Deva" +Locale["no"]["name"] = "Norwegian" +Locale["no"]["endonym"] = "Norsk" +Locale["no"]["translations-of"] = "Oversettelser av %s" +Locale["no"]["definitions-of"] = "Definisjoner av %s" +Locale["no"]["synonyms"] = "Synonymer" +Locale["no"]["examples"] = "Eksempler" +Locale["no"]["see-also"] = "Se også" +Locale["no"]["family"] = "Indo-European" +Locale["no"]["iso"] = "nor" +Locale["no"]["glotto"] = "norw1258" +Locale["no"]["script"] = "Latn" +Locale["ps"]["name"] = "Pashto" +Locale["ps"]["endonym"] = "پښتو" +Locale["ps"]["translations-of"] = "د %sژباړې" +Locale["ps"]["definitions-of"] = "د%s تعریفونه" +Locale["ps"]["synonyms"] = "مترادف لغتونه" +Locale["ps"]["examples"] = "بېلګې" +Locale["ps"]["see-also"] = "دا هم ووینئ" +Locale["ps"]["family"] = "Indo-European" +Locale["ps"]["iso"] = "pus" +Locale["ps"]["glotto"] = "pash1269" +Locale["ps"]["script"] = "Arab" +Locale["ps"]["rtl"] = "true" +Locale["fa"]["name"] = "Persian" +Locale["fa"]["endonym"] = "فارسی" +Locale["fa"]["translations-of"] = "ترجمه‌های %s" +Locale["fa"]["definitions-of"] = "تعریف‌های %s" +Locale["fa"]["synonyms"] = "مترادف‌ها" +Locale["fa"]["examples"] = "مثال‌ها" +Locale["fa"]["see-also"] = "همچنین مراجعه کنید به" +Locale["fa"]["family"] = "Indo-European" +Locale["fa"]["iso"] = "fas" +Locale["fa"]["glotto"] = "west2369" +Locale["fa"]["script"] = "Arab" +Locale["fa"]["rtl"] = "true" +Locale["pl"]["name"] = "Polish" +Locale["pl"]["endonym"] = "Polski" +Locale["pl"]["translations-of"] = "Tłumaczenia %s" +Locale["pl"]["definitions-of"] = "%s – definicje" +Locale["pl"]["synonyms"] = "Synonimy" +Locale["pl"]["examples"] = "Przykłady" +Locale["pl"]["see-also"] = "Zobacz też" +Locale["pl"]["family"] = "Indo-European" +Locale["pl"]["iso"] = "pol" +Locale["pl"]["glotto"] = "poli1260" +Locale["pl"]["script"] = "Latn" +Locale["pt"]["name"] = "Portuguese" +Locale["pt"]["endonym"] = "Português" +Locale["pt"]["translations-of"] = "Traduções de %s" +Locale["pt"]["definitions-of"] = "Definições de %s" +Locale["pt"]["synonyms"] = "Sinônimos" +Locale["pt"]["examples"] = "Exemplos" +Locale["pt"]["see-also"] = "Veja também" +Locale["pt"]["family"] = "Indo-European" +Locale["pt"]["iso"] = "por" +Locale["pt"]["glotto"] = "port1283" +Locale["pt"]["script"] = "Latn" +Locale["pt"]["dictionary"] = "true" +Locale["pa"]["name"] = "Punjabi" +Locale["pa"]["endonym"] = "ਪੰਜਾਬੀ" +Locale["pa"]["translations-of"] = "ਦੇ ਅਨੁਵਾਦ%s" +Locale["pa"]["definitions-of"] = "ਦੀਆਂ ਪਰਿਭਾਸ਼ਾ %s" +Locale["pa"]["synonyms"] = "ਸਮਾਨਾਰਥਕ ਸ਼ਬਦ" +Locale["pa"]["examples"] = "ਉਦਾਹਰਣਾਂ" +Locale["pa"]["see-also"] = "ਇਹ ਵੀ ਵੇਖੋ" +Locale["pa"]["family"] = "Indo-European" +Locale["pa"]["iso"] = "pan" +Locale["pa"]["glotto"] = "panj1256" +Locale["pa"]["script"] = "Guru" +Locale["ro"]["name"] = "Romanian" +Locale["ro"]["endonym"] = "Română" +Locale["ro"]["translations-of"] = "Traduceri pentru %s" +Locale["ro"]["definitions-of"] = "Definiții pentru %s" +Locale["ro"]["synonyms"] = "Sinonime" +Locale["ro"]["examples"] = "Exemple" +Locale["ro"]["see-also"] = "Vedeți și" +Locale["ro"]["family"] = "Indo-European" +Locale["ro"]["iso"] = "ron" +Locale["ro"]["glotto"] = "roma1327" +Locale["ro"]["script"] = "Latn" +Locale["ru"]["name"] = "Russian" +Locale["ru"]["endonym"] = "Русский" +Locale["ru"]["translations-of"] = "%s: варианты перевода" +Locale["ru"]["definitions-of"] = "%s – определения" +Locale["ru"]["synonyms"] = "Синонимы" +Locale["ru"]["examples"] = "Примеры" +Locale["ru"]["see-also"] = "Похожие слова" +Locale["ru"]["family"] = "Indo-European" +Locale["ru"]["iso"] = "rus" +Locale["ru"]["glotto"] = "russ1263" +Locale["ru"]["script"] = "Cyrl" +Locale["ru"]["dictionary"] = "true" +Locale["sm"]["name"] = "Samoan" +Locale["sm"]["endonym"] = "Gagana Sāmoa" +Locale["sm"]["family"] = "Austronesian" +Locale["sm"]["iso"] = "smo" +Locale["sm"]["glotto"] = "samo1305" +Locale["sm"]["script"] = "Latn" +Locale["gd"]["name"] = "Scots Gaelic" +Locale["gd"]["endonym"] = "Gàidhlig" +Locale["gd"]["translations-of"] = "Eadar-theangachadh airson %s" +Locale["gd"]["definitions-of"] = "Deifiniseanan airson %s" +Locale["gd"]["synonyms"] = "Co-fhaclan" +Locale["gd"]["examples"] = "Buill-eisimpleir" +Locale["gd"]["see-also"] = "Faic na leanas cuideachd" +Locale["gd"]["family"] = "Indo-European" +Locale["gd"]["iso"] = "gla" +Locale["gd"]["glotto"] = "scot1245" +Locale["gd"]["script"] = "Latn" +Locale["sr-Cyrl"]["name"] = "Serbian (Cyrillic)" +Locale["sr-Cyrl"]["endonym"] = "српски" +Locale["sr-Cyrl"]["translations-of"] = "Преводи за „%s“" +Locale["sr-Cyrl"]["definitions-of"] = "Дефиниције за %s" +Locale["sr-Cyrl"]["synonyms"] = "Синоними" +Locale["sr-Cyrl"]["examples"] = "Примери" +Locale["sr-Cyrl"]["see-also"] = "Погледајте такође" +Locale["sr-Cyrl"]["family"] = "Indo-European" +Locale["sr-Cyrl"]["iso"] = "srp-Cyrl" +Locale["sr-Cyrl"]["glotto"] = "serb1264" +Locale["sr-Cyrl"]["script"] = "Cyrl" +Locale["sr-Latn"]["name"] = "Serbian (Latin)" +Locale["sr-Latn"]["endonym"] = "srpski" +Locale["sr-Latn"]["translations-of"] = "Prevodi za „%s“" +Locale["sr-Latn"]["definitions-of"] = "Definicije za %s" +Locale["sr-Latn"]["synonyms"] = "Sinonimi" +Locale["sr-Latn"]["examples"] = "Primeri" +Locale["sr-Latn"]["see-also"] = "Pogledajte takođe" +Locale["sr-Latn"]["family"] = "Indo-European" +Locale["sr-Latn"]["iso"] = "srp-Latn" +Locale["sr-Latn"]["glotto"] = "serb1264" +Locale["sr-Latn"]["script"] = "Latn" +Locale["st"]["name"] = "Sesotho" +Locale["st"]["endonym"] = "Sesotho" +Locale["st"]["translations-of"] = "Liphetolelo tsa %s" +Locale["st"]["definitions-of"] = "Meelelo ea %s" +Locale["st"]["synonyms"] = "Mantsoe a tšoanang ka moelelo" +Locale["st"]["examples"] = "Mehlala" +Locale["st"]["see-also"] = "Bona hape" +Locale["st"]["family"] = "Atlantic-Congo" +Locale["st"]["iso"] = "sot" +Locale["st"]["glotto"] = "sout2807" +Locale["st"]["script"] = "Latn" +Locale["sn"]["name"] = "Shona" +Locale["sn"]["endonym"] = "chiShona" +Locale["sn"]["translations-of"] = "Shanduro dze %s" +Locale["sn"]["definitions-of"] = "Zvinoreva %s" +Locale["sn"]["synonyms"] = "Mashoko anoreva zvakafana nemamwe" +Locale["sn"]["examples"] = "Mienzaniso" +Locale["sn"]["see-also"] = "Onawo" +Locale["sn"]["family"] = "Atlantic-Congo" +Locale["sn"]["iso"] = "sna" +Locale["sn"]["glotto"] = "core1255" +Locale["sn"]["script"] = "Latn" +Locale["sd"]["name"] = "Sindhi" +Locale["sd"]["endonym"] = "سنڌي" +Locale["sd"]["translations-of"] = "%s جو ترجمو" +Locale["sd"]["definitions-of"] = "%s جون وصفون" +Locale["sd"]["synonyms"] = "هم معني" +Locale["sd"]["examples"] = "مثالون" +Locale["sd"]["see-also"] = "به ڏسو" +Locale["sd"]["family"] = "Indo-European" +Locale["sd"]["iso"] = "snd" +Locale["sd"]["glotto"] = "sind1272" +Locale["sd"]["script"] = "Arab" +Locale["sd"]["rtl"] = "true" +Locale["si"]["name"] = "Sinhala" +Locale["si"]["endonym"] = "සිංහල" +Locale["si"]["translations-of"] = "%s හි පරිවර්තන" +Locale["si"]["definitions-of"] = "%s හි නිර්වචන" +Locale["si"]["synonyms"] = "සමානාර්ථ පද" +Locale["si"]["examples"] = "උදාහරණ" +Locale["si"]["see-also"] = "මෙයත් බලන්න" +Locale["si"]["family"] = "Indo-European" +Locale["si"]["iso"] = "sin" +Locale["si"]["glotto"] = "sinh1246" +Locale["si"]["script"] = "Sinh" +Locale["sk"]["name"] = "Slovak" +Locale["sk"]["endonym"] = "Slovenčina" +Locale["sk"]["translations-of"] = "Preklady výrazu: %s" +Locale["sk"]["definitions-of"] = "Definície výrazu %s" +Locale["sk"]["synonyms"] = "Synonymá" +Locale["sk"]["examples"] = "Príklady" +Locale["sk"]["see-also"] = "Pozrite tiež" +Locale["sk"]["family"] = "Indo-European" +Locale["sk"]["iso"] = "slk" +Locale["sk"]["glotto"] = "slov1269" +Locale["sk"]["script"] = "Latn" +Locale["sl"]["name"] = "Slovenian" +Locale["sl"]["endonym"] = "Slovenščina" +Locale["sl"]["translations-of"] = "Prevodi za %s" +Locale["sl"]["definitions-of"] = "Razlage za %s" +Locale["sl"]["synonyms"] = "Sopomenke" +Locale["sl"]["examples"] = "Primeri" +Locale["sl"]["see-also"] = "Glejte tudi" +Locale["sl"]["family"] = "Indo-European" +Locale["sl"]["iso"] = "slv" +Locale["sl"]["glotto"] = "slov1268" +Locale["sl"]["script"] = "Latn" +Locale["so"]["name"] = "Somali" +Locale["so"]["endonym"] = "Soomaali" +Locale["so"]["translations-of"] = "Turjumaada %s" +Locale["so"]["definitions-of"] = "Qeexitaannada %s" +Locale["so"]["synonyms"] = "La micne ah" +Locale["so"]["examples"] = "Tusaalooyin" +Locale["so"]["see-also"] = "Sidoo kale eeg" +Locale["so"]["family"] = "Afro-Asiatic" +Locale["so"]["iso"] = "som" +Locale["so"]["glotto"] = "soma1255" +Locale["so"]["script"] = "Latn" +Locale["es"]["name"] = "Spanish" +Locale["es"]["endonym"] = "Español" +Locale["es"]["translations-of"] = "Traducciones de %s" +Locale["es"]["definitions-of"] = "Definiciones de %s" +Locale["es"]["synonyms"] = "Sinónimos" +Locale["es"]["examples"] = "Ejemplos" +Locale["es"]["see-also"] = "Ver también" +Locale["es"]["family"] = "Indo-European" +Locale["es"]["iso"] = "spa" +Locale["es"]["glotto"] = "stan1288" +Locale["es"]["script"] = "Latn" +Locale["es"]["dictionary"] = "true" +Locale["su"]["name"] = "Sundanese" +Locale["su"]["endonym"] = "Basa Sunda" +Locale["su"]["translations-of"] = "Tarjamahan tina %s" +Locale["su"]["definitions-of"] = "Panjelasan tina %s" +Locale["su"]["synonyms"] = "Sinonim" +Locale["su"]["examples"] = "Conto" +Locale["su"]["see-also"] = "Tingali ogé" +Locale["su"]["family"] = "Austronesian" +Locale["su"]["iso"] = "sun" +Locale["su"]["glotto"] = "sund1252" +Locale["su"]["script"] = "Latn" +Locale["sw"]["name"] = "Swahili" +Locale["sw"]["endonym"] = "Kiswahili" +Locale["sw"]["translations-of"] = "Tafsiri ya %s" +Locale["sw"]["definitions-of"] = "Ufafanuzi wa %s" +Locale["sw"]["synonyms"] = "Visawe" +Locale["sw"]["examples"] = "Mifano" +Locale["sw"]["see-also"] = "Angalia pia" +Locale["sw"]["family"] = "Atlantic-Congo" +Locale["sw"]["iso"] = "swa" +Locale["sw"]["glotto"] = "swah1253" +Locale["sw"]["script"] = "Latn" +Locale["sv"]["name"] = "Swedish" +Locale["sv"]["endonym"] = "Svenska" +Locale["sv"]["translations-of"] = "Översättningar av %s" +Locale["sv"]["definitions-of"] = "Definitioner av %s" +Locale["sv"]["synonyms"] = "Synonymer" +Locale["sv"]["examples"] = "Exempel" +Locale["sv"]["see-also"] = "Se även" +Locale["sv"]["family"] = "Indo-European" +Locale["sv"]["iso"] = "swe" +Locale["sv"]["glotto"] = "swed1254" +Locale["sv"]["script"] = "Latn" +Locale["tg"]["name"] = "Tajik" +Locale["tg"]["endonym"] = "Тоҷикӣ" +Locale["tg"]["translations-of"] = "Тарҷумаҳои %s" +Locale["tg"]["definitions-of"] = "Таърифҳои %s" +Locale["tg"]["synonyms"] = "Муродифҳо" +Locale["tg"]["examples"] = "Намунаҳо:" +Locale["tg"]["see-also"] = "Ҳамчунин Бинед" +Locale["tg"]["family"] = "Indo-European" +Locale["tg"]["iso"] = "tgk" +Locale["tg"]["glotto"] = "taji1245" +Locale["tg"]["script"] = "Cyrl" +Locale["ta"]["name"] = "Tamil" +Locale["ta"]["endonym"] = "தமிழ்" +Locale["ta"]["translations-of"] = "%s இன் மொழிபெயர்ப்புகள்" +Locale["ta"]["definitions-of"] = "%s இன் வரையறைகள்" +Locale["ta"]["synonyms"] = "இணைச்சொற்கள்" +Locale["ta"]["examples"] = "எடுத்துக்காட்டுகள்" +Locale["ta"]["see-also"] = "இதையும் காண்க" +Locale["ta"]["family"] = "Dravidian" +Locale["ta"]["iso"] = "tam" +Locale["ta"]["glotto"] = "tami1289" +Locale["ta"]["script"] = "Taml" +Locale["te"]["name"] = "Telugu" +Locale["te"]["endonym"] = "తెలుగు" +Locale["te"]["translations-of"] = "%s యొక్క అనువాదాలు" +Locale["te"]["definitions-of"] = "%s యొక్క నిర్వచనాలు" +Locale["te"]["synonyms"] = "పర్యాయపదాలు" +Locale["te"]["examples"] = "ఉదాహరణలు" +Locale["te"]["see-also"] = "వీటిని కూడా చూడండి" +Locale["te"]["family"] = "Dravidian" +Locale["te"]["iso"] = "tel" +Locale["te"]["glotto"] = "telu1262" +Locale["te"]["script"] = "Telu" +Locale["th"]["name"] = "Thai" +Locale["th"]["endonym"] = "ไทย" +Locale["th"]["translations-of"] = "คำแปลของ %s" +Locale["th"]["definitions-of"] = "คำจำกัดความของ %s" +Locale["th"]["synonyms"] = "คำพ้องความหมาย" +Locale["th"]["examples"] = "ตัวอย่าง" +Locale["th"]["see-also"] = "ดูเพิ่มเติม" +Locale["th"]["family"] = "Tai-Kadai" +Locale["th"]["iso"] = "tha" +Locale["th"]["glotto"] = "thai1261" +Locale["th"]["script"] = "Thai" +Locale["tr"]["name"] = "Turkish" +Locale["tr"]["endonym"] = "Türkçe" +Locale["tr"]["translations-of"] = "%s çevirileri" +Locale["tr"]["definitions-of"] = "%s için tanımlar" +Locale["tr"]["synonyms"] = "Eş anlamlılar" +Locale["tr"]["examples"] = "Örnekler" +Locale["tr"]["see-also"] = "Ayrıca bkz." +Locale["tr"]["family"] = "Turkic" +Locale["tr"]["iso"] = "tur" +Locale["tr"]["glotto"] = "nucl1301" +Locale["tr"]["script"] = "Latn" +Locale["uk"]["name"] = "Ukrainian" +Locale["uk"]["endonym"] = "Українська" +Locale["uk"]["translations-of"] = "Переклади слова або виразу \"%s\"" +Locale["uk"]["definitions-of"] = "\"%s\" – визначення" +Locale["uk"]["synonyms"] = "Синоніми" +Locale["uk"]["examples"] = "Приклади" +Locale["uk"]["see-also"] = "Дивіться також" +Locale["uk"]["family"] = "Indo-European" +Locale["uk"]["iso"] = "ukr" +Locale["uk"]["glotto"] = "ukra1253" +Locale["uk"]["script"] = "Cyrl" +Locale["ur"]["name"] = "Urdu" +Locale["ur"]["endonym"] = "اُردُو" +Locale["ur"]["translations-of"] = "کے ترجمے %s" +Locale["ur"]["definitions-of"] = "کی تعریفات %s" +Locale["ur"]["synonyms"] = "مترادفات" +Locale["ur"]["examples"] = "مثالیں" +Locale["ur"]["see-also"] = "نیز دیکھیں" +Locale["ur"]["family"] = "Indo-European" +Locale["ur"]["iso"] = "urd" +Locale["ur"]["glotto"] = "urdu1245" +Locale["ur"]["script"] = "Arab" +Locale["ur"]["rtl"] = "true" +Locale["uz"]["name"] = "Uzbek" +Locale["uz"]["endonym"] = "Oʻzbek tili" +Locale["uz"]["translations-of"] = "%s: tarjima variantlari" +Locale["uz"]["definitions-of"] = "%s – ta’riflar" +Locale["uz"]["synonyms"] = "Sinonimlar" +Locale["uz"]["examples"] = "Namunalar" +Locale["uz"]["see-also"] = "O‘xshash so‘zlar" +Locale["uz"]["family"] = "Turkic" +Locale["uz"]["iso"] = "uzb" +Locale["uz"]["glotto"] = "uzbe1247" +Locale["uz"]["script"] = "Latn" +Locale["vi"]["name"] = "Vietnamese" +Locale["vi"]["endonym"] = "Tiếng Việt" +Locale["vi"]["translations-of"] = "Bản dịch của %s" +Locale["vi"]["definitions-of"] = "Nghĩa của %s" +Locale["vi"]["synonyms"] = "Từ đồng nghĩa" +Locale["vi"]["examples"] = "Ví dụ" +Locale["vi"]["see-also"] = "Xem thêm" +Locale["vi"]["family"] = "Austroasiatic" +Locale["vi"]["iso"] = "vie" +Locale["vi"]["glotto"] = "viet1252" +Locale["vi"]["script"] = "Latn" +Locale["cy"]["name"] = "Welsh" +Locale["cy"]["endonym"] = "Cymraeg" +Locale["cy"]["translations-of"] = "Cyfieithiadau %s" +Locale["cy"]["definitions-of"] = "Diffiniadau %s" +Locale["cy"]["synonyms"] = "Cyfystyron" +Locale["cy"]["examples"] = "Enghreifftiau" +Locale["cy"]["see-also"] = "Gweler hefyd" +Locale["cy"]["family"] = "Indo-European" +Locale["cy"]["iso"] = "cym" +Locale["cy"]["glotto"] = "wels1247" +Locale["cy"]["script"] = "Latn" +Locale["fy"]["name"] = "Frisian" +Locale["fy"]["endonym"] = "Frysk" +Locale["fy"]["translations-of"] = "Oersettings fan %s" +Locale["fy"]["definitions-of"] = "Definysjes fan %s" +Locale["fy"]["synonyms"] = "Synonimen" +Locale["fy"]["examples"] = "Foarbylden" +Locale["fy"]["see-also"] = "Sjoch ek" +Locale["fy"]["family"] = "Indo-European" +Locale["fy"]["iso"] = "fry" +Locale["fy"]["glotto"] = "west2354" +Locale["fy"]["script"] = "Latn" +Locale["xh"]["name"] = "Xhosa" +Locale["xh"]["endonym"] = "isiXhosa" +Locale["xh"]["translations-of"] = "Iinguqulelo zika-%s" +Locale["xh"]["definitions-of"] = "Iingcaciso zika-%s" +Locale["xh"]["synonyms"] = "Izithethantonye" +Locale["xh"]["examples"] = "Imizekelo" +Locale["xh"]["see-also"] = "Kwakhona bona" +Locale["xh"]["family"] = "Atlantic-Congo" +Locale["xh"]["iso"] = "xho" +Locale["xh"]["glotto"] = "xhos1239" +Locale["xh"]["script"] = "Latn" +Locale["yi"]["name"] = "Yiddish" +Locale["yi"]["endonym"] = "ייִדיש" +Locale["yi"]["translations-of"] = "איבערזעצונגען פון %s" +Locale["yi"]["definitions-of"] = "דפיניציונען %s" +Locale["yi"]["synonyms"] = "סינאָנימען" +Locale["yi"]["examples"] = "ביישפילע" +Locale["yi"]["see-also"] = "זייען אויך" +Locale["yi"]["family"] = "Indo-European" +Locale["yi"]["iso"] = "yid" +Locale["yi"]["glotto"] = "yidd1255" +Locale["yi"]["script"] = "Hebr" +Locale["yi"]["rtl"] = "true" +Locale["yo"]["name"] = "Yoruba" +Locale["yo"]["endonym"] = "Yorùbá" +Locale["yo"]["translations-of"] = "Awọn itumọ ti %s" +Locale["yo"]["definitions-of"] = "Awọn itumọ ti %s" +Locale["yo"]["synonyms"] = "Awọn ọrọ onitumọ" +Locale["yo"]["examples"] = "Awọn apẹrẹ" +Locale["yo"]["see-also"] = "Tun wo" +Locale["yo"]["family"] = "Atlantic-Congo" +Locale["yo"]["iso"] = "yor" +Locale["yo"]["glotto"] = "yoru1245" +Locale["yo"]["script"] = "Latn" +Locale["zu"]["name"] = "Zulu" +Locale["zu"]["endonym"] = "isiZulu" +Locale["zu"]["translations-of"] = "Ukuhumusha i-%s" +Locale["zu"]["definitions-of"] = "Izincazelo ze-%s" +Locale["zu"]["synonyms"] = "Amagama afanayo" +Locale["zu"]["examples"] = "Izibonelo" +Locale["zu"]["see-also"] = "Bheka futhi" +Locale["zu"]["family"] = "Atlantic-Congo" +Locale["zu"]["iso"] = "zul" +Locale["zu"]["glotto"] = "zulu1248" +Locale["zu"]["script"] = "Latn" +Locale["yue"]["support"] = "bing-only" +Locale["yue"]["name"] = "Cantonese" +Locale["yue"]["endonym"] = "粵語" +Locale["yue"]["family"] = "Sino-Tibetan" +Locale["yue"]["iso"] = "yue" +Locale["yue"]["glotto"] = "cant1236" +Locale["yue"]["script"] = "Hant" +Locale["fj"]["support"] = "bing-only" +Locale["fj"]["name"] = "Fijian" +Locale["fj"]["endonym"] = "Vosa Vakaviti" +Locale["fj"]["family"] = "Austronesian" +Locale["fj"]["iso"] = "fij" +Locale["fj"]["glotto"] = "fiji1243" +Locale["fj"]["script"] = "Latn" +Locale["mww"]["support"] = "bing-only" +Locale["mww"]["name"] = "Hmong Daw" +Locale["mww"]["endonym"] = "Hmoob Daw" +Locale["mww"]["family"] = "Hmong-Mien" +Locale["mww"]["iso"] = "mww" +Locale["mww"]["glotto"] = "hmon1333" +Locale["mww"]["script"] = "Latn" +Locale["otq"]["support"] = "bing-only" +Locale["otq"]["name"] = "Querétaro Otomi" +Locale["otq"]["endonym"] = "Hñąñho" +Locale["otq"]["family"] = "Oto-Manguean" +Locale["otq"]["iso"] = "otq" +Locale["otq"]["glotto"] = "quer1236" +Locale["otq"]["script"] = "Latn" +Locale["ty"]["support"] = "bing-only" +Locale["ty"]["name"] = "Tahitian" +Locale["ty"]["endonym"] = "Reo Tahiti" +Locale["ty"]["family"] = "Austronesian" +Locale["ty"]["iso"] = "tah" +Locale["ty"]["glotto"] = "tahi1242" +Locale["ty"]["script"] = "Latn" +Locale["to"]["support"] = "bing-only" +Locale["to"]["name"] = "Tongan" +Locale["to"]["endonym"] = "Lea faka-Tonga" +Locale["to"]["family"] = "Austronesian" +Locale["to"]["iso"] = "ton" +Locale["to"]["glotto"] = "tong1325" +Locale["to"]["script"] = "Latn" +Locale["yua"]["support"] = "bing-only" +Locale["yua"]["name"] = "Yucatec Maya" +Locale["yua"]["endonym"] = "Màaya T'àan" +Locale["yua"]["family"] = "Mayan" +Locale["yua"]["iso"] = "yua" +Locale["yua"]["glotto"] = "yuca1254" +Locale["yua"]["script"] = "Latn" +Locale["tlh"]["support"] = "bing-only" +Locale["tlh"]["name"] = "Klingon" +Locale["tlh"]["endonym"] = "tlhIngan Hol" +Locale["tlh"]["family"] = "Artificial Language" +Locale["tlh"]["iso"] = "tlh" +Locale["tlh"]["script"] = "Latn" +Locale["tlh-Qaak"]["support"] = "bing-only" +Locale["tlh-Qaak"]["name"] = "Klingon (pIqaD)" +Locale["tlh-Qaak"]["endonym"] = " " +Locale["tlh-Qaak"]["family"] = "Artificial Language" +Locale["tlh-Qaak"]["iso"] = "tlh" +Locale["tlh-Qaak"]["script"] = "Piqd" +Locale["as"]["support"] = "unstable" +Locale["as"]["name"] = "Assamese" +Locale["as"]["endonym"] = "অসমীয়া" +Locale["as"]["family"] = "Indo-European" +Locale["as"]["iso"] = "asm" +Locale["as"]["glotto"] = "assa1263" +Locale["as"]["script"] = "Beng" +Locale["ba"]["support"] = "yandex-only" +Locale["ba"]["name"] = "Bashkir" +Locale["ba"]["endonym"] = "башҡорт теле" +Locale["ba"]["family"] = "Turkic" +Locale["ba"]["iso"] = "bak" +Locale["ba"]["glotto"] = "bash1264" +Locale["ba"]["script"] = "Cyrl" +Locale["br"]["support"] = "unstable" +Locale["br"]["name"] = "Breton" +Locale["br"]["endonym"] = "Brezhoneg" +Locale["br"]["family"] = "Indo-European" +Locale["br"]["iso"] = "bre" +Locale["br"]["glotto"] = "bret1244" +Locale["br"]["script"] = "Latn" +Locale["dz"]["support"] = "unstable" +Locale["dz"]["name"] = "Dzongkha" +Locale["dz"]["endonym"] = "རྫོང་ཁ" +Locale["dz"]["family"] = "Sino-Tibetan" +Locale["dz"]["iso"] = "dzo" +Locale["dz"]["glotto"] = "nucl1307" +Locale["dz"]["script"] = "Tibt" +Locale["mhr"]["support"] = "yandex-only" +Locale["mhr"]["name"] = "Eastern Mari" +Locale["mhr"]["endonym"] = "Олык марий" +Locale["mhr"]["family"] = "Uralic" +Locale["mhr"]["iso"] = "mhr" +Locale["mhr"]["glotto"] = "east2328" +Locale["mhr"]["script"] = "Cyrl" +Locale["fo"]["support"] = "unstable" +Locale["fo"]["name"] = "Faroese" +Locale["fo"]["endonym"] = "Føroyskt" +Locale["fo"]["family"] = "Indo-European" +Locale["fo"]["iso"] = "fao" +Locale["fo"]["glotto"] = "faro1244" +Locale["fo"]["script"] = "Latn" +Locale["gn"]["support"] = "unstable" +Locale["gn"]["name"] = "Guarani" +Locale["gn"]["endonym"] = "Avañe'ẽ" +Locale["gn"]["family"] = "Tupian" +Locale["gn"]["iso"] = "grn" +Locale["gn"]["glotto"] = "para1311" +Locale["gn"]["script"] = "Latn" +Locale["mrj"]["support"] = "yandex-only" +Locale["mrj"]["name"] = "Hill Mari" +Locale["mrj"]["endonym"] = "Кырык мары" +Locale["mrj"]["family"] = "Uralic" +Locale["mrj"]["iso"] = "mrj" +Locale["mrj"]["glotto"] = "west2392" +Locale["mrj"]["script"] = "Cyrl" +Locale["ie"]["support"] = "unstable" +Locale["ie"]["name"] = "Interlingue" +Locale["ie"]["endonym"] = "Interlingue" +Locale["ie"]["family"] = "Artificial Language" +Locale["ie"]["iso"] = "ile" +Locale["ie"]["glotto"] = "occi1241" +Locale["ie"]["script"] = "Latn" +Locale["rw"]["support"] = "unstable" +Locale["rw"]["name"] = "Kinyarwanda" +Locale["rw"]["endonym"] = "Ikinyarwanda" +Locale["rw"]["family"] = "Atlantic-Congo" +Locale["rw"]["iso"] = "kin" +Locale["rw"]["glotto"] = "kiny1244" +Locale["rw"]["script"] = "Latn" +Locale["oc"]["support"] = "unstable" +Locale["oc"]["name"] = "Occitan" +Locale["oc"]["endonym"] = "Occitan" +Locale["oc"]["family"] = "Indo-European" +Locale["oc"]["iso"] = "oci" +Locale["oc"]["glotto"] = "occi1239" +Locale["oc"]["script"] = "Latn" +Locale["om"]["support"] = "unstable" +Locale["om"]["name"] = "Oromo" +Locale["om"]["endonym"] = "Afaan Oromoo" +Locale["om"]["family"] = "Afro-Asiatic" +Locale["om"]["iso"] = "orm" +Locale["om"]["glotto"] = "nucl1736" +Locale["om"]["script"] = "Latn" +Locale["or"]["support"] = "unstable" +Locale["or"]["name"] = "Oriya" +Locale["or"]["endonym"] = "ଓଡ଼ିଆ" +Locale["or"]["family"] = "Indo-European" +Locale["or"]["iso"] = "ori" +Locale["or"]["glotto"] = "macr1269" +Locale["or"]["script"] = "Orya" +Locale["pap"]["support"] = "yandex-only" +Locale["pap"]["name"] = "Papiamento" +Locale["pap"]["endonym"] = "Papiamentu" +Locale["pap"]["family"] = "Indo-European" +Locale["pap"]["iso"] = "pap" +Locale["pap"]["glotto"] = "papi1253" +Locale["pap"]["script"] = "Latn" +Locale["rm"]["support"] = "unstable" +Locale["rm"]["name"] = "Romansh" +Locale["rm"]["endonym"] = "Rumantsch" +Locale["rm"]["family"] = "Indo-European" +Locale["rm"]["iso"] = "roh" +Locale["rm"]["glotto"] = "roma1326" +Locale["rm"]["script"] = "Latn" +Locale["ti"]["support"] = "unstable" +Locale["ti"]["name"] = "Tigrinya" +Locale["ti"]["endonym"] = "ትግርኛ" +Locale["ti"]["family"] = "Afro-Asiatic" +Locale["ti"]["iso"] = "tir" +Locale["ti"]["glotto"] = "tigr1271" +Locale["ti"]["script"] = "Ethi" +Locale["bo"]["support"] = "unstable" +Locale["bo"]["name"] = "Tibetan" +Locale["bo"]["endonym"] = "བོད་ཡིག" +Locale["bo"]["family"] = "Sino-Tibetan" +Locale["bo"]["iso"] = "bod" +Locale["bo"]["glotto"] = "tibe1272" +Locale["bo"]["script"] = "Tibt" +Locale["tk"]["support"] = "unstable" +Locale["tk"]["name"] = "Turkmen" +Locale["tk"]["endonym"] = "Türkmen" +Locale["tk"]["family"] = "Turkic" +Locale["tk"]["iso"] = "tuk" +Locale["tk"]["glotto"] = "turk1304" +Locale["tk"]["script"] = "Latn" +Locale["tt"]["support"] = "yandex-only" +Locale["tt"]["name"] = "Tatar" +Locale["tt"]["endonym"] = "татарча" +Locale["tt"]["family"] = "Turkic" +Locale["tt"]["iso"] = "tat" +Locale["tt"]["glotto"] = "tata1255" +Locale["tt"]["script"] = "Cyrl" +Locale["udm"]["support"] = "yandex-only" +Locale["udm"]["name"] = "Udmurt" +Locale["udm"]["endonym"] = "удмурт" +Locale["udm"]["family"] = "Uralic" +Locale["udm"]["iso"] = "udm" +Locale["udm"]["glotto"] = "udmu1245" +Locale["udm"]["script"] = "Cyrl" +Locale["ug"]["support"] = "unstable" +Locale["ug"]["name"] = "Uyghur" +Locale["ug"]["endonym"] = "ئۇيغۇر تىلى" +Locale["ug"]["family"] = "Turkic" +Locale["ug"]["iso"] = "uig" +Locale["ug"]["glotto"] = "uigh1240" +Locale["ug"]["script"] = "Arab" +Locale["ug"]["rtl"] = "true" +Locale["vo"]["support"] = "unstable" +Locale["vo"]["name"] = "Volapük" +Locale["vo"]["endonym"] = "Volapük" +Locale["vo"]["family"] = "Artificial Language" +Locale["vo"]["iso"] = "vol" +Locale["vo"]["script"] = "Latn" +Locale["wo"]["support"] = "unstable" +Locale["wo"]["name"] = "Wolof" +Locale["wo"]["endonym"] = "Wollof" +Locale["wo"]["family"] = "Atlantic-Congo" +Locale["wo"]["iso"] = "wol" +Locale["wo"]["glotto"] = "wolo1247" +Locale["wo"]["script"] = "Latn" +Locale["chr"]["support"] = "unstable" +Locale["chr"]["name"] = "Cherokee" +Locale["chr"]["endonym"] = "ᏣᎳᎩ" +Locale["chr"]["family"] = "Iroquoian" +Locale["chr"]["iso"] = "chr" +Locale["chr"]["glotto"] = "cher1273" +Locale["chr"]["script"] = "Cher" +Locale["emj"]["support"] = "yandex-only" +Locale["emj"]["name"] = "Emoji" +Locale["emj"]["endonym"] = "Emoji" +} +function initLocaleAlias( i) { +for (i in Locale) { +LocaleAlias[Locale[i]["iso"]] = i +LocaleAlias[tolower(Locale[i]["name"])] = i +LocaleAlias[tolower(Locale[i]["endonym"])] = i +} +LocaleAlias["in"] = "id" +LocaleAlias["iw"] = "he" +LocaleAlias["ji"] = "yi" +LocaleAlias["jw"] = "jv" +LocaleAlias["mo"] = "ro" +LocaleAlias["nb"] = "no" +LocaleAlias["nn"] = "no" +LocaleAlias["sh"] = "sr-Cyrl" +LocaleAlias["sr"] = "sr-Cyrl" +LocaleAlias["srp"] = "sr-Cyrl" +LocaleAlias["serbian"] = "sr-Cyrl" +LocaleAlias["zh"] = "zh-CN" +LocaleAlias["zh-CHS"] = "zh-CN" +LocaleAlias["zh-CHT"] = "zh-TW" +LocaleAlias["zh-Hans"] = "zh-CN" +LocaleAlias["zh-Hant"] = "zh-TW" +LocaleAlias["zho"] = "zh-CN" +LocaleAlias["chinese"] = "zh-CN" +LocaleAlias["tlh-Latn"] = "tlh" +LocaleAlias["tlh-Piqd"] = "tlh-Qaak" +} +function initLocaleDisplay( i) { +for (i in Locale) { +Locale[i]["display"] = show(Locale[i]["endonym"], i) +} +} +function getCode(code, group) { +if (code == "auto" || code in Locale) +return code +else if (code in LocaleAlias) +return LocaleAlias[code] +else if (tolower(code) in LocaleAlias) +return LocaleAlias[tolower(code)] +match(code, /^([[:alpha:]][[:alpha:]][[:alpha:]]?)-(.*)$/, group) +if (group[1]) +return group[1] +return +} +function getName(code) { +return Locale[getCode(code)]["name"] +} +function getEndonym(code) { +return Locale[getCode(code)]["endonym"] +} +function getDisplay(code) { +return Locale[getCode(code)]["display"] +} +function showTranslationsOf(code, text, fmt) { +fmt = Locale[getCode(code)]["translations-of"] +if (!fmt) fmt = Locale["en"]["translations-of"] +return sprintf(fmt, text) +} +function showDefinitionsOf(code, text, fmt) { +fmt = Locale[getCode(code)]["definitions-of"] +if (!fmt) fmt = Locale["en"]["definitions-of"] +return sprintf(fmt, text) +} +function showSynonyms(code, tmp) { +tmp = Locale[getCode(code)]["synonyms"] +if (!tmp) tmp = Locale["en"]["synonyms"] +return tmp +} +function showExamples(code, tmp) { +tmp = Locale[getCode(code)]["examples"] +if (!tmp) tmp = Locale["en"]["examples"] +return tmp +} +function showSeeAlso(code, tmp) { +tmp = Locale[getCode(code)]["see-also"] +if (!tmp) tmp = Locale["en"]["see-also"] +return tmp +} +function getFamily(code) { +return Locale[getCode(code)]["family"] +} +function getISO(code) { +return Locale[getCode(code)]["iso"] +} +function getGlotto(code) { +return Locale[getCode(code)]["glotto"] +} +function getScript(code) { +return Locale[getCode(code)]["script"] +} +function isRTL(code) { +return Locale[getCode(code)]["rtl"] ? 1 : 0 +} +function hasDictionary(code) { +return Locale[getCode(code)]["dictionary"] ? 1 : 0 +} +function compName(i1, v1, i2, v2) { +if (getName(i1) < getName(i2)) +return -1 +else +return (getName(i1) != getName(i2)) +} +function scriptName(code) { +switch (code) { +case "Arab": return "Arabic" +case "Armn": return "Armenian" +case "Beng": return "Bengali" +case "Cher": return "Cherokee" +case "Cyrl": return "Cyrillic" +case "Deva": return "Devanagari" +case "Ethi": return "Ethiopic (Geʻez)" +case "Geor": return "Georgian (Mkhedruli)" +case "Grek": return "Greek" +case "Gujr": return "Gujarati" +case "Guru": return "Gurmukhi" +case "Hani": return "Han" +case "Hans": return "Han (Simplified)" +case "Hant": return "Han (Traditional)" +case "Hebr": return "Hebrew" +case "Jpan": return "Japanese (Han + Hiragana + Katakana)" +case "Khmr": return "Khmer" +case "Knda": return "Kannada" +case "Kore": return "Korean (Hangul + Han)" +case "Laoo": return "Lao" +case "Latn": return "Latin" +case "Mlym": return "Malayalam" +case "Mymr": return "Myanmar" +case "Orya": return "Oriya" +case "Piqd": return "Klingon (pIqaD)" +case "Sinh": return "Sinhala" +case "Taml": return "Tamil" +case "Telu": return "Telugu" +case "Thai": return "Thai" +case "Tibt": return "Tibetan" +default: return "Unknown" +} +} +function getDetails(code, group, iso, language, script) { +if (code == "auto" || !getCode(code)) { +e("[ERROR] Language not found: " code "\n"\ +" Run '-reference / -R' to see a list of available languages.") +exit 1 +} +script = scriptName(getScript(code)) +if (isRTL(code)) script = script " (R-to-L)" +split(getISO(code), group, "-") +iso = group[1] +split(getName(code), group, " ") +language = length(group) == 1 ? group[1] "_language" : +group[2] ~ /^\(.*\)$/ ? group[1] "_language" : join(group, "_") +return ansi("bold", sprintf("%s\n", getDisplay(code)))\ +sprintf("%-22s%s\n", "Name", ansi("bold", getName(code)))\ +sprintf("%-22s%s\n", "Family", ansi("bold", getFamily(code)))\ +sprintf("%-22s%s\n", "Writing system", ansi("bold", script))\ +sprintf("%-22s%s\n", "Code", ansi("bold", getCode(code)))\ +sprintf("%-22s%s\n", "ISO 639-3", ansi("bold", iso))\ +sprintf("%-22s%s\n", "SIL", ansi("bold", "http://www-01.sil.org/iso639-3/documentation.asp?id=" iso))\ +sprintf("%-22s%s\n", "Glottolog", getGlotto(code) ? +ansi("bold", "http://glottolog.org/resource/languoid/id/" getGlotto(code)) : "")\ +sprintf("%-22s%s", "Wikipedia", ansi("bold", "http://en.wikipedia.org/wiki/" language)) +} +function showPhonetics(phonetics, code) { +if (code && getCode(code) == "en") +return "/" phonetics "/" +else +return "(" phonetics ")" +} +function show(text, code, command, temp) { +if (!code || isRTL(code)) { +if (Cache[text][0]) +return Cache[text][0] +else { +if ((FriBidi || (code && isRTL(code))) && BiDiNoPad) { +command = "echo " parameterize(text) PIPE BiDiNoPad +command | getline temp +close(command) +} else +temp = text +return Cache[text][0] = temp +} +} else +return text +} +function s(text, code, width, command, temp) { +if (!code || isRTL(code)) { +if (!width) width = Option["width"] +if (Cache[text][width]) +return Cache[text][width] +else { +if ((FriBidi || (code && isRTL(code))) && BiDi) { +command = "echo " parameterize(text) PIPE sprintf(BiDi, width) +command | getline temp +close(command) +} else +temp = text +return Cache[text][width] = temp +} +} else +return text +} +function ins(level, text, code, width, i, temp) { +if (code && isRTL(code)) { +if (!width) width = Option["width"] +return s(text, code, width - Option["indent"] * level) +} else +return replicate(" ", Option["indent"] * level) text +} +function parseLang(lang, code, group) { +match(lang, /^([a-z][a-z][a-z]?)(_|$)/, group) +code = getCode(group[1]) +if (lang ~ /^zh_(CN|SG)/) code = "zh-CN" +else if (lang ~ /^zh_(TW|HK)/) code = "zh-TW" +if (!code) code = "en" +return code +} +function initUserLang( lang, utf) { +if (lang = ENVIRON["LC_ALL"]) { +if (!UserLocale) UserLocale = lang +utf = utf || tolower(lang) ~ /utf-?8$/ +} +if (lang = ENVIRON["LANG"]) { +if (!UserLocale) UserLocale = lang +utf = utf || tolower(lang) ~ /utf-?8$/ +} +if (!UserLocale) { +UserLocale = "en_US.UTF-8" +utf = 1 +} +if (!utf) +w("[WARNING] Your locale codeset (" UserLocale ") is not UTF-8.") +UserLang = parseLang(UserLocale) +} +function getVersion( build, gitHead) { +initAudioPlayer() +initPager() +Platform = Platform ? Platform : detectProgram("uname", "-s", 1) +if (ENVIRON["TRANS_BUILD"]) +build = "-" ENVIRON["TRANS_BUILD"] +else { +gitHead = getGitHead() +build = gitHead ? "-git:" gitHead : "" +} +return ansi("bold", sprintf("%-22s%s%s\n\n", Name, Version, build))\ +sprintf("%-22s%s\n", "platform", Platform)\ +sprintf("%-22s%s\n", "terminal type", ENVIRON["TERM"])\ +sprintf("%-22s%s\n", "bi-di emulator", BiDiTerm ? BiDiTerm : +"[N/A]")\ +sprintf("%-22s%s\n", "gawk (GNU Awk)", PROCINFO["version"])\ +sprintf("%s\n", FriBidi ? FriBidi : +"fribidi (GNU FriBidi) [NOT INSTALLED]")\ +sprintf("%-22s%s\n", "audio player", AudioPlayer ? AudioPlayer : +"[NOT INSTALLED]")\ +sprintf("%-22s%s\n", "terminal pager", Pager ? Pager : +"[NOT INSTALLED]")\ +sprintf("%-22s%s\n", "web browser", Option["browser"] != NONE ? +Option["browser"] :"[NONE]")\ +sprintf("%-22s%s (%s)\n", "user locale", UserLocale, getName(UserLang))\ +sprintf("%-22s%s\n", "home language", Option["hl"])\ +sprintf("%-22s%s\n", "source language", join(Option["sls"], "+"))\ +sprintf("%-22s%s\n", "target language", join(Option["tl"], "+"))\ +sprintf("%-22s%s\n", "translation engine", Option["engine"])\ +sprintf("%-22s%s\n", "proxy", Option["proxy"] ? Option["proxy"] : +"[NONE]")\ +sprintf("%-22s%s\n", "user-agent", Option["user-agent"] ? Option["user-agent"] : +"[NONE]")\ +sprintf("%-22s%s\n", "ip version", Option["ip-version"] ? Option["ip-version"] : +"[DEFAULT]")\ +sprintf("%-22s%s\n", "theme", Option["theme"])\ +sprintf("%-22s%s\n", "init file", InitScript ? InitScript : "[NONE]")\ +sprintf("\n%-22s%s", "Report bugs to:", "https://github.com/soimort/translate-shell/issues") +} +function getHelp() { +return "Usage: " ansi("bold", Command)\ +" [" ansi("underline", "OPTIONS") "]"\ +" [" ansi("underline", "SOURCES") "]"\ +":[" ansi("underline", "TARGETS") "]"\ +" [" ansi("underline", "TEXT") "]..." RS\ +RS "Information options:" RS\ +ins(1, ansi("bold", "-V") ", " ansi("bold", "-version")) RS\ +ins(2, "Print version and exit.") RS\ +ins(1, ansi("bold", "-H") ", " ansi("bold", "-help")) RS\ +ins(2, "Print help message and exit.") RS\ +ins(1, ansi("bold", "-M") ", " ansi("bold", "-man")) RS\ +ins(2, "Show man page and exit.") RS\ +ins(1, ansi("bold", "-T") ", " ansi("bold", "-reference")) RS\ +ins(2, "Print reference table of languages and exit.") RS\ +ins(1, ansi("bold", "-R") ", " ansi("bold", "-reference-english")) RS\ +ins(2, "Print reference table of languages (in English names) and exit.") RS\ +ins(1, ansi("bold", "-L ") ansi("underline", "CODES")\ +", " ansi("bold", "-list ") ansi("underline", "CODES")) RS\ +ins(2, "Print details of languages and exit.") RS\ +ins(1, ansi("bold", "-S") ", " ansi("bold", "-list-engines")) RS\ +ins(2, "List available translation engines and exit.") RS\ +ins(1, ansi("bold", "-U") ", " ansi("bold", "-upgrade")) RS\ +ins(2, "Check for upgrade of this program.") RS\ +RS "Translator options:" RS\ +ins(1, ansi("bold", "-e ") ansi("underline", "ENGINE")\ +", " ansi("bold", "-engine ") ansi("underline", "ENGINE")) RS\ +ins(2, "Specify the translation engine to use.") RS\ +RS "Display options:" RS\ +ins(1, ansi("bold", "-verbose")) RS\ +ins(2, "Verbose mode. (default)") RS\ +ins(1, ansi("bold", "-b") ", " ansi("bold", "-brief")) RS\ +ins(2, "Brief mode.") RS\ +ins(1, ansi("bold", "-d") ", " ansi("bold", "-dictionary")) RS\ +ins(2, "Dictionary mode.") RS\ +ins(1, ansi("bold", "-identify")) RS\ +ins(2, "Language identification.") RS\ +ins(1, ansi("bold", "-show-original ") ansi("underline", "Y/n")) RS\ +ins(2, "Show original text or not.") RS\ +ins(1, ansi("bold", "-show-original-phonetics ") ansi("underline", "Y/n")) RS\ +ins(2, "Show phonetic notation of original text or not.") RS\ +ins(1, ansi("bold", "-show-translation ") ansi("underline", "Y/n")) RS\ +ins(2, "Show translation or not.") RS\ +ins(1, ansi("bold", "-show-translation-phonetics ") ansi("underline", "Y/n")) RS\ +ins(2, "Show phonetic notation of translation or not.") RS\ +ins(1, ansi("bold", "-show-prompt-message ") ansi("underline", "Y/n")) RS\ +ins(2, "Show prompt message or not.") RS\ +ins(1, ansi("bold", "-show-languages ") ansi("underline", "Y/n")) RS\ +ins(2, "Show source and target languages or not.") RS\ +ins(1, ansi("bold", "-show-original-dictionary ") ansi("underline", "y/N")) RS\ +ins(2, "Show dictionary entry of original text or not.") RS\ +ins(1, ansi("bold", "-show-dictionary ") ansi("underline", "Y/n")) RS\ +ins(2, "Show dictionary entry of translation or not.") RS\ +ins(1, ansi("bold", "-show-alternatives ") ansi("underline", "Y/n")) RS\ +ins(2, "Show alternative translations or not.") RS\ +ins(1, ansi("bold", "-w ") ansi("underline", "NUM")\ +", " ansi("bold", "-width ") ansi("underline", "NUM")) RS\ +ins(2, "Specify the screen width for padding.") RS\ +ins(1, ansi("bold", "-indent ") ansi("underline", "NUM")) RS\ +ins(2, "Specify the size of indent (number of spaces).") RS\ +ins(1, ansi("bold", "-theme ") ansi("underline", "FILENAME")) RS\ +ins(2, "Specify the theme to use.") RS\ +ins(1, ansi("bold", "-no-theme")) RS\ +ins(2, "Do not use any other theme than default.") RS\ +ins(1, ansi("bold", "-no-ansi")) RS\ +ins(2, "Do not use ANSI escape codes.") RS\ +ins(1, ansi("bold", "-no-autocorrect")) RS\ +ins(2, "Do not autocorrect. (if defaulted by the translation engine)") RS\ +ins(1, ansi("bold", "-no-bidi")) RS\ +ins(2, "Do not convert bidirectional texts.") RS\ +ins(1, ansi("bold", "-bidi")) RS\ +ins(2, "Always convert bidirectional texts.") RS\ +ins(1, ansi("bold", "-no-warn")) RS\ +ins(2, "Do not write warning messages to stderr.") RS\ +ins(1, ansi("bold", "-dump")) RS\ +ins(2, "Print raw API response instead.") RS\ +RS "Audio options:" RS\ +ins(1, ansi("bold", "-p, -play")) RS\ +ins(2, "Listen to the translation.") RS\ +ins(1, ansi("bold", "-speak")) RS\ +ins(2, "Listen to the original text.") RS\ +ins(1, ansi("bold", "-n ") ansi("underline", "VOICE")\ +", " ansi("bold", "-narrator ") ansi("underline", "VOICE")) RS\ +ins(2, "Specify the narrator, and listen to the translation.") RS\ +ins(1, ansi("bold", "-player ") ansi("underline", "PROGRAM")) RS\ +ins(2, "Specify the audio player to use, and listen to the translation.") RS\ +ins(1, ansi("bold", "-no-play")) RS\ +ins(2, "Do not listen to the translation.") RS\ +ins(1, ansi("bold", "-no-translate")) RS\ +ins(2, "Do not translate anything when using -speak.") RS\ +ins(1, ansi("bold", "-download-audio")) RS\ +ins(2, "Download the audio to the current directory.") RS\ +ins(1, ansi("bold", "-download-audio-as ") ansi("underline", "FILENAME")) RS\ +ins(2, "Download the audio to the specified file.") RS\ +RS "Terminal paging and browsing options:" RS\ +ins(1, ansi("bold", "-v") ", " ansi("bold", "-view")) RS\ +ins(2, "View the translation in a terminal pager.") RS\ +ins(1, ansi("bold", "-pager ") ansi("underline", "PROGRAM")) RS\ +ins(2, "Specify the terminal pager to use, and view the translation.") RS\ +ins(1, ansi("bold", "-no-view") ", " ansi("bold", "-no-pager")) RS\ +ins(2, "Do not view the translation in a terminal pager.") RS\ +ins(1, ansi("bold", "-browser ") ansi("underline", "PROGRAM")) RS\ +ins(2, "Specify the web browser to use.") RS\ +ins(1, ansi("bold", "-no-browser")) RS\ +ins(2, "Do not open the web browser.") RS\ +RS "Networking options:" RS\ +ins(1, ansi("bold", "-x ") ansi("underline", "HOST:PORT")\ +", " ansi("bold", "-proxy ") ansi("underline", "HOST:PORT")) RS\ +ins(2, "Use HTTP proxy on given port.") RS\ +ins(1, ansi("bold", "-u ") ansi("underline", "STRING")\ +", " ansi("bold", "-user-agent ") ansi("underline", "STRING")) RS\ +ins(2, "Specify the User-Agent to identify as.") RS\ +ins(1, ansi("bold", "-4") ", " ansi("bold", "-ipv4")\ +", " ansi("bold", "-inet4-only")) RS\ +ins(2, "Connect only to IPv4 addresses.") RS\ +ins(1, ansi("bold", "-6") ", " ansi("bold", "-ipv6")\ +", " ansi("bold", "-inet6-only")) RS\ +ins(2, "Connect only to IPv6 addresses.") RS\ +RS "Interactive shell options:" RS\ +ins(1, ansi("bold", "-I") ", " ansi("bold", "-interactive") ", " ansi("bold", "-shell")) RS\ +ins(2, "Start an interactive shell.") RS\ +ins(1, ansi("bold", "-E") ", " ansi("bold", "-emacs")) RS\ +ins(2, "Start the GNU Emacs front-end for an interactive shell.") RS\ +ins(1, ansi("bold", "-no-rlwrap")) RS\ +ins(2, "Do not invoke rlwrap when starting an interactive shell.") RS\ +RS "I/O options:" RS\ +ins(1, ansi("bold", "-i ") ansi("underline", "FILENAME")\ +", " ansi("bold", "-input ") ansi("underline", "FILENAME")) RS\ +ins(2, "Specify the input file.") RS\ +ins(1, ansi("bold", "-o ") ansi("underline", "FILENAME")\ +", " ansi("bold", "-output ") ansi("underline", "FILENAME")) RS\ +ins(2, "Specify the output file.") RS\ +RS "Language preference options:" RS\ +ins(1, ansi("bold", "-l ") ansi("underline", "CODE")\ +", " ansi("bold", "-hl ") ansi("underline", "CODE")\ +", " ansi("bold", "-lang ") ansi("underline", "CODE")) RS\ +ins(2, "Specify your home language.") RS\ +ins(1, ansi("bold", "-s ") ansi("underline", "CODES")\ +", " ansi("bold", "-sl ") ansi("underline", "CODES")\ +", " ansi("bold", "-source ") ansi("underline", "CODES")\ +", " ansi("bold", "-from ") ansi("underline", "CODES")) RS\ +ins(2, "Specify the source language(s), joined by '+'.") RS\ +ins(1, ansi("bold", "-t ") ansi("underline", "CODES")\ +", " ansi("bold", "-tl ") ansi("underline", "CODES")\ +", " ansi("bold", "-target ") ansi("underline", "CODES")\ +", " ansi("bold", "-to ") ansi("underline", "CODES")) RS\ +ins(2, "Specify the target language(s), joined by '+'.") RS\ +RS "Text preprocessing options:" RS\ +ins(1, ansi("bold", "-j") ", " ansi("bold", "-join-sentence")) RS\ +ins(2, "Treat all arguments as one single sentence.") RS\ +RS "Other options:" RS\ +ins(1, ansi("bold", "-no-init")) RS\ +ins(2, "Do not load any initialization script.") RS\ +RS "See the man page " Command "(1) for more information." +} +function showMan( temp) { +if (ENVIRON["TRANS_MANPAGE"]) { +initPager() +Groff = detectProgram("groff", "--version") +if (Pager && Groff) { +temp = "echo -E \"${TRANS_MANPAGE}\"" +temp = temp PIPE\ +Groff " -Wall -mtty-char -mandoc -Tutf8 "\ +"-rLL=" Option["width"] "n -rLT=" Option["width"] "n" +switch (Pager) { +case "less": +temp = temp PIPE\ +Pager " -s -P\"\\ \\Manual page " Command "(1) line %lt (press h for help or q to quit)\"" +break +case "most": +temp = temp PIPE Pager " -Cs" +break +default: +temp = temp PIPE Pager +} +system(temp) +return +} +} +if (fileExists(ENVIRON["TRANS_DIR"] "/man/" Command ".1")) +system("man " parameterize(ENVIRON["TRANS_DIR"] "/man/" Command ".1") SUPERR) +else if (system("man " Command SUPERR)) +print getHelp() +} +function getReference(displayName, +code, col, cols, i, j, name, num, r, rows, saveSortedIn, +t1, t2) { +num = 0 +for (code in Locale) +if (Locale[code]["support"] != "unstable") +num++ +rows = int(num / 3) + (num % 3 ? 1 : 0) +cols[0][0] = cols[1][0] = cols[2][0] = NULLSTR +i = 0 +saveSortedIn = PROCINFO["sorted_in"] +PROCINFO["sorted_in"] = displayName == "endonym" ? "@ind_num_asc" : +"compName" +for (code in Locale) { +if (Locale[code]["support"] != "unstable") { +col = int(i / rows) +append(cols[col], code) +i++ +} +} +PROCINFO["sorted_in"] = saveSortedIn +if (displayName == "endonym") { +r = "┌" replicate("─", 23) "┬" replicate("─", 23) "┬" replicate("─", 23) "┐" RS +for (i = 0; i < rows; i++) { +r = r "│" +for (j = 0; j < 3; j++) { +if (cols[j][i]) { +t1 = getDisplay(cols[j][i]) +switch (cols[j][i]) { +case "he": +t1 = sprintf(" %-18s", t1) +break +case "ur": +t1 = sprintf(" %-17s", t1) +break +case "hi": case "gu": case "km": case "kn": +case "my": case "ne": case "pa": case "si": +case "ta": case "te": case "yi": +t1 = sprintf(" %-16s", t1) +break +case "yue": +t1 = sprintf(" %-13s", t1) +break +case "ja": case "ko": +t1 = sprintf(" %-12s", t1) +break +case "zh-CN": case "zh-TW": +t1 = sprintf(" %-11s", t1) +break +default: +if (length(t1) <= 15) +t1 = sprintf(" %-15s", t1) +} +switch (length(cols[j][i])) { +case 1: case 2: case 3: case 4: +t2 = sprintf("- %s │", ansi("bold", sprintf("%4s", cols[j][i]))) +break +case 5: +t2 = sprintf("- %s│", ansi("bold", cols[j][i])) +break +case 6: +t2 = sprintf("-%s│", ansi("bold", cols[j][i])) +break +case 7: +t2 = sprintf("-%s", ansi("bold", cols[j][i])) +break +default: +t2 = ansi("bold", cols[j][i]) +} +r = r t1 t2 +} else +r = r sprintf("%23s│", NULLSTR) +} +r = r RS +} +r = r "└" replicate("─", 23) "┴" replicate("─", 23) "┴" replicate("─", 23) "┘" +} else { +r = "┌" replicate("─", 23) "┬" replicate("─", 23) "┬" replicate("─", 23) "┐" RS +for (i = 0; i < rows; i++) { +r = r "│" +for (j = 0; j < 3; j++) { +if (cols[j][i]) { +t1 = getName(cols[j][i]) +if (length(t1) > 15) +t1 = substr(t1, 1, 12) "..." +t1 = sprintf(" %-15s", t1) +switch (length(cols[j][i])) { +case 1: case 2: case 3: case 4: +t2 = sprintf("- %s │", ansi("bold", sprintf("%4s", cols[j][i]))) +break +case 5: +t2 = sprintf("- %s│", ansi("bold", cols[j][i])) +break +case 6: +t2 = sprintf("-%s│", ansi("bold", cols[j][i])) +break +case 7: +t2 = sprintf("-%s", ansi("bold", cols[j][i])) +break +default: +t2 = ansi("bold", cols[j][i]) +} +r = r t1 t2 +} else +r = r sprintf("%23s│", NULLSTR) +} +r = r RS +} +r = r "└" replicate("─", 23) "┴" replicate("─", 23) "┴" replicate("─", 23) "┘" +} +return r +} +function getList(codes, code, i, r, saveSortedIn) { +r = NULLSTR +if (!isarray(codes)) +r = getDetails(codes) +else if (anything(codes)) { +saveSortedIn = PROCINFO["sorted_in"] +PROCINFO["sorted_in"] = "@ind_num_asc" +for (i in codes) +r = (r ? r RS prettify("target-seperator", replicate(Option["chr-target-seperator"], Option["width"])) RS\ +: r) getDetails(codes[i]) +PROCINFO["sorted_in"] = saveSortedIn +} else +r = getDetails(Option["hl"]) +return r +} +function tokenize(returnTokens, string, +delimiters, +newlines, +quotes, +escapeChars, +leftBlockComments, +rightBlockComments, +lineComments, +reservedOperators, +reservedPatterns, +blockCommenting, +c, +currentToken, +escaping, +i, +lineCommenting, +p, +quoting, +r, +s, +tempGroup, +tempPattern, +tempString) { +if (!delimiters[0]) { +delimiters[0] = " " +delimiters[1] = "\t" +delimiters[2] = "\v" +} +if (!newlines[0]) { +newlines[0] = "\n" +newlines[1] = "\r" +} +if (!quotes[0]) { +quotes[0] = "\"" +} +if (!escapeChars[0]) { +escapeChars[0] = "\\" +} +if (!leftBlockComments[0]) { +leftBlockComments[0] = "#|" +leftBlockComments[1] = "/*" +leftBlockComments[2] = "(*" +} +if (!rightBlockComments[0]) { +rightBlockComments[0] = "|#" +rightBlockComments[1] = "*/" +rightBlockComments[2] = "*)" +} +if (!lineComments[0]) { +lineComments[0] = ";" +lineComments[1] = "//" +lineComments[2] = "#" +} +if (!reservedOperators[0]) { +reservedOperators[0] = "(" +reservedOperators[1] = ")" +reservedOperators[2] = "[" +reservedOperators[3] = "]" +reservedOperators[4] = "{" +reservedOperators[5] = "}" +reservedOperators[6] = "," +} +if (!reservedPatterns[0]) { +reservedPatterns[0] = "[+-]?((0|[1-9][0-9]*)|[.][0-9]*|(0|[1-9][0-9]*)[.][0-9]*)([Ee][+-]?[0-9]+)?" +reservedPatterns[1] = "[+-]?0[0-7]+([.][0-7]*)?" +reservedPatterns[2] = "[+-]?0[Xx][0-9A-Fa-f]+([.][0-9A-Fa-f]*)?" +} +split(string, s, "") +currentToken = "" +quoting = escaping = blockCommenting = lineCommenting = 0 +p = 0 +i = 1 +while (i <= length(s)) { +c = s[i] +r = substr(string, i) +if (blockCommenting) { +if (tempString = startsWithAny(r, rightBlockComments)) +blockCommenting = 0 +i++ +} else if (lineCommenting) { +if (belongsTo(c, newlines)) +lineCommenting = 0 +i++ +} else if (quoting) { +currentToken = currentToken c +if (escaping) { +escaping = 0 +} else { +if (belongsTo(c, quotes)) { +if (currentToken) { +returnTokens[p++] = currentToken +currentToken = "" +} +quoting = 0 +} else if (belongsTo(c, escapeChars)) { +escaping = 1 +} else { +} +} +i++ +} else { +if (belongsTo(c, delimiters) || belongsTo(c, newlines)) { +if (currentToken) { +returnTokens[p++] = currentToken +currentToken = "" +} +i++ +} else if (belongsTo(c, quotes)) { +if (currentToken) { +returnTokens[p++] = currentToken +} +currentToken = c +quoting = 1 +i++ +} else if (tempString = startsWithAny(r, leftBlockComments)) { +if (currentToken) { +returnTokens[p++] = currentToken +currentToken = "" +} +blockCommenting = 1 +i += length(tempString) +} else if (tempString = startsWithAny(r, lineComments)) { +if (currentToken) { +returnTokens[p++] = currentToken +currentToken = "" +} +lineCommenting = 1 +i += length(tempString) +} else if (tempString = startsWithAny(r, reservedOperators)) { +if (currentToken) { +returnTokens[p++] = currentToken +currentToken = "" +} +returnTokens[p++] = tempString +i += length(tempString) +} else if (tempPattern = matchesAny(r, reservedPatterns)) { +if (currentToken) { +returnTokens[p++] = currentToken +currentToken = "" +} +match(r, "^" tempPattern, tempGroup) +returnTokens[p++] = tempGroup[0] +i += length(tempGroup[0]) +} else { +currentToken = currentToken c +i++ +} +} +} +if (currentToken) +returnTokens[p++] = currentToken +} +function parseJsonArray(returnAST, tokens, +leftBrackets, +rightBrackets, +separators, +i, j, key, p, stack, token) { +if (!leftBrackets[0]) { +leftBrackets[0] = "(" +leftBrackets[1] = "[" +leftBrackets[2] = "{" +} +if (!rightBrackets[0]) { +rightBrackets[0] = ")" +rightBrackets[1] = "]" +rightBrackets[2] = "}" +} +if (!separators[0]) { +separators[0] = "," +} +stack[p = 0] = 0 +for (i = 0; i < length(tokens); i++) { +token = tokens[i] +if (belongsTo(token, leftBrackets)) +stack[++p] = 0 +else if (belongsTo(token, rightBrackets)) +--p +else if (belongsTo(token, separators)) +stack[p]++ +else { +key = stack[0] +for (j = 1; j <= p; j++) +key = key SUBSEP stack[j] +returnAST[key] = token +} +} +} +function parseJson(returnAST, tokens, +arrayStartTokens, arrayEndTokens, +objectStartTokens, objectEndTokens, +commas, colons, +flag, i, j, key, name, p, stack, token) { +if (!arrayStartTokens[0]) arrayStartTokens[0] = "[" +if (!arrayEndTokens[0]) arrayEndTokens[0] = "]" +if (!objectStartTokens[0]) objectStartTokens[0] = "{" +if (!objectEndTokens[0]) objectEndTokens[0] = "}" +if (!commas[0]) commas[0] = "," +if (!colons[0]) colons[0] = ":" +stack[p = 0] = 0 +flag = 0 +for (i = 0; i < length(tokens); i++) { +token = tokens[i] +if (belongsTo(token, arrayStartTokens)) { +stack[++p] = 0 +} else if (belongsTo(token, objectStartTokens)) { +stack[++p] = NULLSTR +flag = 0 +} else if (belongsTo(token, objectEndTokens) || +belongsTo(token, arrayEndTokens)) { +--p +} else if (belongsTo(token, commas)) { +if (isnum(stack[p])) +stack[p]++ +else +flag = 0 +} else if (belongsTo(token, colons)) { +flag = 1 +} else if (isnum(stack[p]) || flag) { +key = stack[0] +for (j = 1; j <= p; j++) +key = key SUBSEP stack[j] +returnAST[key] = token +flag = 0 +} else { +stack[p] = unparameterize(token) +} +} +} +function parseList(returnAST, tokens, +leftBrackets, +rightBrackets, +separators, +i, j, key, p, stack, token) { +if (!leftBrackets[0]) { +leftBrackets[0] = "(" +leftBrackets[1] = "[" +leftBrackets[2] = "{" +} +if (!rightBrackets[0]) { +rightBrackets[0] = ")" +rightBrackets[1] = "]" +rightBrackets[2] = "}" +} +if (!separators[0]) { +separators[0] = "," +} +stack[p = 0] = 0 +for (i = 0; i < length(tokens); i++) { +token = tokens[i] +if (belongsTo(token, leftBrackets)) { +stack[++p] = 0 +} else if (belongsTo(token, rightBrackets)) { +stack[--p]++ +} else if (belongsTo(token, separators)) { +} else { +key = NULLSTR +if (p > 0) { +for (j = 0; j < p - 1; j++) +key = key SUBSEP stack[j] +returnAST[key][stack[p - 1]] = NULLSTR +key = key SUBSEP stack[p - 1] +} +returnAST[key][stack[p]] = token +stack[p]++ +} +} +} +function prettify(name, string, i, temp) { +temp = string +if ("sgr-" name in Option) +if (isarray(Option["sgr-" name])) +for (i in Option["sgr-" name]) +temp = ansi(Option["sgr-" name][i], temp) +else +temp = ansi(Option["sgr-" name], temp) +return temp +} +function randomColor( i) { +i = int(5 * rand()) +switch (i) { +case 0: return "green" +case 1: return "yellow" +case 2: return "blue" +case 3: return "magenta" +case 4: return "cyan" +default: return "default" +} +} +function setRandomTheme( i, n, temp) { +srand(systime()) +for (i = 0; i < 3; i++) { +do temp = randomColor(); while (belongsTo(temp, n)) +n[i] = temp +} +Option["sgr-prompt-message"] = Option["sgr-languages"] = n[0] +Option["sgr-original-dictionary-detailed-word-class"][1] = n[0] +Option["sgr-original-dictionary-detailed-word-class"][2] = "bold" +Option["sgr-original-dictionary-synonyms"] = n[0] +Option["sgr-original-dictionary-synonyms-word-class"][1] = n[0] +Option["sgr-original-dictionary-synonyms-word-class"][2] = "bold" +Option["sgr-original-dictionary-examples"] = n[0] +Option["sgr-original-dictionary-see-also"] = n[0] +Option["sgr-dictionary-word-class"][1] = n[0] +Option["sgr-dictionary-word-class"][2] = "bold" +Option["sgr-original"][1] = Option["sgr-original-phonetics"][1] = n[1] +Option["sgr-original"][2] = Option["sgr-original-phonetics"][2] = "bold" +Option["sgr-prompt-message-original"][1] = n[1] +Option["sgr-prompt-message-original"][2] = "bold" +Option["sgr-languages-sl"] = n[1] +Option["sgr-original-dictionary-detailed-explanation"][1] = n[1] +Option["sgr-original-dictionary-detailed-explanation"][2] = "bold" +Option["sgr-original-dictionary-detailed-example"] = n[1] +Option["sgr-original-dictionary-detailed-synonyms"] = n[1] +Option["sgr-original-dictionary-detailed-synonyms-item"][1] = n[1] +Option["sgr-original-dictionary-detailed-synonyms-item"][2] = "bold" +Option["sgr-original-dictionary-synonyms-synonyms"] = n[1] +Option["sgr-original-dictionary-synonyms-synonyms-item"][1] = n[1] +Option["sgr-original-dictionary-synonyms-synonyms-item"][2] = "bold" +Option["sgr-original-dictionary-examples-example"] = n[1] +Option["sgr-original-dictionary-examples-original"][1] = n[1] +Option["sgr-original-dictionary-examples-original"][2] = "bold" +Option["sgr-original-dictionary-examples-original"][3] = "underline" +Option["sgr-original-dictionary-see-also-phrases"] = n[1] +Option["sgr-original-dictionary-see-also-phrases-item"][1] = n[1] +Option["sgr-original-dictionary-see-also-phrases-item"][2] = "bold" +Option["sgr-dictionary-explanation"] = n[1] +Option["sgr-dictionary-explanation-item"][1] = n[1] +Option["sgr-dictionary-explanation-item"][2] = "bold" +Option["sgr-alternatives-original"][1] = n[1] +Option["sgr-alternatives-original"][2] = "bold" +Option["sgr-translation"][1] = Option["sgr-translation-phonetics"][1] = n[2] +Option["sgr-translation"][2] = Option["sgr-translation-phonetics"][2] = "bold" +Option["sgr-languages-tl"] = n[2] +Option["sgr-dictionary-word"][1] = n[2] +Option["sgr-dictionary-word"][2] = "bold" +Option["sgr-alternatives-translations"] = n[2] +Option["sgr-alternatives-translations-item"][1] = n[2] +Option["sgr-alternatives-translations-item"][2] = "bold" +Option["sgr-brief-translation"][1] = Option["sgr-brief-translation-phonetics"][1] = n[2] +Option["sgr-brief-translation"][2] = Option["sgr-brief-translation-phonetics"][2] = "bold" +Option["fmt-welcome-message"] = Name +Option["sgr-welcome-message"][1] = n[0] +Option["sgr-welcome-message"][2] = "bold" +Option["fmt-welcome-submessage"] = "(:q to quit)" +Option["sgr-welcome-submessage"] = n[0] +Option["fmt-prompt"] = "%s> " +Option["sgr-prompt"][1] = n[1] +Option["sgr-prompt"][2] = "bold" +} +function setDefaultTheme() { +Option["sgr-translation"] = Option["sgr-translation-phonetics"] = "bold" +Option["sgr-prompt-message-original"] = "underline" +Option["sgr-languages-sl"] = "underline" +Option["sgr-languages-tl"] = "bold" +Option["sgr-original-dictionary-detailed-explanation"] = "bold" +Option["sgr-original-dictionary-detailed-synonyms-item"] = "bold" +Option["sgr-original-dictionary-synonyms-synonyms-item"] = "bold" +Option["sgr-original-dictionary-examples-original"][1] = "bold" +Option["sgr-original-dictionary-examples-original"][2] = "underline" +Option["sgr-original-dictionary-see-also-phrases-item"] = "bold" +Option["sgr-dictionary-word"] = "bold" +Option["sgr-alternatives-original"] = "underline" +Option["sgr-alternatives-translations-item"] = "bold" +Option["fmt-welcome-message"] = Name +Option["sgr-welcome-message"] = "bold" +Option["fmt-welcome-submessage"] = "(:q to quit)" +Option["fmt-prompt"] = "%s> " +Option["sgr-prompt"] = "bold" +} +function setTheme( file, line, script) { +if (Option["theme"] && Option["theme"] != "default"\ +&& Option["theme"] != "none" && Option["theme"] != "random") { +file = Option["theme"] +if (!fileExists(file)) { +file = ENVIRON["HOME"] "/.translate-shell/" Option["theme"] +if (!fileExists(file)) { +file = ENVIRON["HOME"] "/.config/translate-shell/" Option["theme"] +if (!fileExists(file)) return +} +} +} +if (file && fileExists(file)) { +script = NULLSTR +while (getline line < file) +script = script "\n" line +loadOptions(script) +} else if (Option["theme"] == "none") +; +else if (Option["theme"] == "random") +setRandomTheme() +else +setDefaultTheme() +} +function provides(engineName) { +Translator[tolower(engineName)] = TRUE +} +function engineMethod(methodName, engine, translator) { +if (!Translator[Option["engine"]]) { +engine = tolower(Option["engine"]) +if (!Translator[engine]) +for (translator in Translator) +if (Translator[translator] && +translator ~ "^"engine) { +engine = translator +break +} +if (!Translator[engine]) { +e("[ERROR] Translator not found: " Option["engine"] "\n"\ +" Run '-list-engines / -S' to see a list of available engines.") +exit 1 +} +Option["engine"] = engine +} +return Option["engine"] methodName +} +function initAudioPlayer() { +AudioPlayer = !system("mpv" SUPOUT SUPERR) ? +"mpv --no-config" : +(!system("mplayer" SUPOUT SUPERR) ? +"mplayer" : +(!system("mpg123 --version" SUPOUT SUPERR) ? +"mpg123" : +"")) +} +function initSpeechSynthesizer() { +SpeechSynthesizer = !system("say ''" SUPOUT SUPERR) ? +"say" : +(!system("espeak ''" SUPOUT SUPERR) ? +"espeak" : +"") +} +function initPager() { +Pager = !system("less -V" SUPOUT SUPERR) ? +"less" : +(!system("more -V" SUPOUT SUPERR) ? +"more" : +(!system("most" SUPOUT SUPERR) ? +"most" : +"")) +} +function initHttpService( inet) { +_Init() +inet = "inet" +if (Option["ip-version"]) +inet = inet Option["ip-version"] +if (Option["proxy"]) { +match(Option["proxy"], /^(http:\/*)?(([^:]+):([^@]+)@)?([^\/]*):([^\/:]*)/, HttpProxySpec) +HttpAuthUser = HttpProxySpec[3] +HttpAuthPass = HttpProxySpec[4] +HttpAuthCredentials = base64(unquote(HttpAuthUser) ":" HttpAuthPass) +HttpService = "/" inet "/tcp/0/" HttpProxySpec[5] "/" HttpProxySpec[6] +HttpPathPrefix = HttpProtocol HttpHost +} else { +HttpService = "/" inet "/tcp/0/" HttpHost "/" HttpPort +HttpPathPrefix = "" +} +PROCINFO[HttpService, "READ_TIMEOUT"] = 2000 +} +function preprocess(text) { +return quote(text) +} +function preprocessByDump(text, arr, len, temp) { +len = dumpX(text, arr) +temp = "" +for (i = 1; i <= len; i++) +temp = temp "%" arr[i] +return temp +} +function postprocess(text) { +text = gensub(/ ([.,;:?!"])/, "\\1", "g", text) +text = gensub(/(["]) /, "\\1", "g", text) +return text +} +function getResponse(text, sl, tl, hl, +content, header, isBody, url, group, status, location) { +url = _RequestUrl(text, sl, tl, hl) +header = "GET " url " HTTP/1.1\r\n"\ +"Host: " HttpHost "\r\n"\ +"Connection: close\r\n" +if (Option["user-agent"]) +header = header "User-Agent: " Option["user-agent"] "\r\n" +if (Cookie) +header = header "Cookie: " Cookie "\r\n" +if (HttpAuthUser && HttpAuthPass) +header = header "Proxy-Authorization: Basic " HttpAuthCredentials "\r\n" +content = NULLSTR; isBody = 0 +while (1) { +print header |& HttpService +while ((HttpService |& getline) > 0) { +if (isBody) +content = content ? content "\n" $0 : $0 +else if (length($0) <= 1) +isBody = 1 +else { +match($0, /^HTTP[^ ]* ([^ ]*)/, group) +if (RSTART) status = group[1] +match($0, /^Location: (.*)/, group) +if (RSTART) location = squeeze(group[1]) +} +l(sprintf("%4s bytes > %s", length($0), $0)) +} +close(HttpService) +if (ERRNO == "Connection timed out") { +w("[WARNING] " ERRNO ". Retrying IPv4 connection.") +Option["ip-version"] = 4 +initHttpService() +PROCINFO[HttpService, "READ_TIMEOUT"] = 0 +ERRNO = "" +} else +break +} +if ((status == "301" || status == "302") && location) +content = curl(location) +return assert(content, "[ERROR] Null response.") +} +function postResponse(text, sl, tl, hl, type, +content, contentLength, contentType, group, +header, isBody, reqBody, url, status, location, userAgent) { +url = _PostRequestUrl(text, sl, tl, hl, type) +contentType = _PostRequestContentType(text, sl, tl, hl, type) +userAgent = _PostRequestUserAgent(text, sl, tl, hl, type) +reqBody = _PostRequestBody(text, sl, tl, hl, type) +if (DumpContentengths[reqBody]) +contentLength = DumpContentengths[reqBody] +else +contentLength = DumpContentengths[reqBody] = dump(reqBody, group) +header = "POST " url " HTTP/1.1\r\n"\ +"Host: " HttpHost "\r\n"\ +"Connection: close\r\n"\ +"Content-Length: " contentLength "\r\n"\ +"Content-Type: " contentType "\r\n" +if (Option["user-agent"] && !userAgent) +header = header "User-Agent: " Option["user-agent"] "\r\n" +if (userAgent) +header = header "User-Agent: " userAgent "\r\n" +if (Cookie) +header = header "Cookie: " Cookie "\r\n" +if (HttpAuthUser && HttpAuthPass) +header = header "Proxy-Authorization: Basic " HttpAuthCredentials "\r\n" +content = NULLSTR; isBody = 0 +while (1) { +print (header "\r\n" reqBody) |& HttpService +while ((HttpService |& getline) > 0) { +if (isBody) +content = content ? content "\n" $0 : $0 +else if (length($0) <= 1) +isBody = 1 +else { +match($0, /^HTTP[^ ]* ([^ ]*)/, group) +if (RSTART) status = group[1] +match($0, /^Location: (.*)/, group) +if (RSTART) location = squeeze(group[1]) +} +l(sprintf("%4s bytes > %s", length($0), $0)) +} +close(HttpService) +if (ERRNO == "Connection timed out") { +w("[WARNING] " ERRNO ". Retrying IPv4 connection.") +Option["ip-version"] = 4 +initHttpService() +PROCINFO[HttpService, "READ_TIMEOUT"] = 0 +ERRNO = "" +} else +break +} +if (status == "404") { +e("[ERROR] 404 Not Found") +exit 1 +} +if ((status == "301" || status == "302") && location) { +url = "https" substr(url, 5) +content = curlPost(url, reqBody) +} +return content +} +function p(string) { +if (Option["view"]) { +print string | Option["pager"] +close(Option["pager"]) +} else +print string > Option["output"] +} +function play(text, tl, url, status) { +url = _TTSUrl(text, tl) +status = system(Option["player"] " " parameterize(url) SUPOUT SUPERR) +if (status) +w("Voice output isn't available for " getName(tl)) +return status +} +function download_audio(text, tl, url, output) { +url = _TTSUrl(text, tl) +if (Option["download-audio-as"]) +output = Option["download-audio-as"] +else +output = text " [" Option["engine"] "] (" Option["narrator"] ").ts" +if (url ~ /^\//) +system("mv -- " parameterize(url) " " parameterize(output)) +else +curl(url, output) +} +function getTranslation(text, sl, tl, hl, +isVerbose, toSpeech, returnPlaylist, returnIl) { +return _Translate(text, sl, tl, hl, +isVerbose, toSpeech, returnPlaylist, returnIl) +} +function fileTranslation(uri, group, temp1, temp2) { +temp1 = Option["input"] +temp2 = Option["verbose"] +match(uri, /^file:\/\/(.*)/, group) +Option["input"] = group[1] +Option["verbose"] = 0 +translateMain() +Option["input"] = temp1 +Option["verbose"] = temp2 +} +function webTranslation(uri, sl, tl, hl, temp) { +temp = _WebTranslateUrl(uri, sl, tl, hl) +if (temp) { +p(temp) +if (Option["browser"] != NONE) +system(Option["browser"] " " parameterize(temp) SUPOUT SUPERR) +} +} +function translate(text, inline, +i, j, playlist, il, saveSortedIn) { +if (!getCode(Option["hl"])) { +w("[WARNING] Unknown language code: " Option["hl"] ", fallback to English: en") +Option["hl"] = "en" +} else if (isRTL(Option["hl"])) { +if (!FriBidi) +w("[WARNING] " getName(Option["hl"]) " is a right-to-left language, but FriBidi is not found.") +} +if (!getCode(Option["sl"])) { +w("[WARNING] Unknown source language code: " Option["sl"]) +} else if (isRTL(Option["sl"])) { +if (!FriBidi) +w("[WARNING] " getName(Option["sl"]) " is a right-to-left language, but FriBidi is not found.") +} +saveSortedIn = PROCINFO["sorted_in"] +PROCINFO["sorted_in"] = "@ind_num_asc" +for (i in Option["tl"]) { +if (!Option["interactive"]) +if (Option["verbose"] && i > 1) +p(prettify("target-seperator", replicate(Option["chr-target-seperator"], Option["width"]))) +if (inline && +startsWithAny(text, UriSchemes) == "file://") { +fileTranslation(text) +} else if (inline && +startsWithAny(text, UriSchemes) == "http://" || +startsWithAny(text, UriSchemes) == "https://") { +webTranslation(text, Option["sl"], Option["tl"][i], Option["hl"]) +} else { +if (!Option["no-translate"]) +p(getTranslation(text, Option["sl"], Option["tl"][i], Option["hl"], Option["verbose"], Option["play"] || Option["download-audio"], playlist, il)) +else +il[0] = Option["sl"] == "auto" ? "en" : Option["sl"] +if (Option["play"] == 1) { +if (Option["player"]) +for (j in playlist) +play(playlist[j]["text"], playlist[j]["tl"]) +else if (SpeechSynthesizer) +for (j in playlist) +print playlist[j]["text"] | SpeechSynthesizer +} else if (Option["play"] == 2) { +if (Option["player"]) +play(text, il[0]) +else if (SpeechSynthesizer) +print text | SpeechSynthesizer +} +if (Option["download-audio"] == 1) { +if (Option["play"] != 2 && !Option["no-translate"]) +download_audio(playlist[length(playlist) - 1]["text"],\ +playlist[length(playlist) - 1]["tl"]) +else +download_audio(text, il[0]) +} +} +} +PROCINFO["sorted_in"] = saveSortedIn +} +function translates(text, inline, +i) { +saveSortedIn = PROCINFO["sorted_in"] +PROCINFO["sorted_in"] = "@ind_num_asc" +for (i in Option["sls"]) { +if (!Option["interactive"]) +if (Option["verbose"] && i > 1) +p(prettify("target-seperator", replicate(Option["chr-target-seperator"], Option["width"]))) +Option["sl"] = Option["sls"][i] +translate(text, inline) +} +PROCINFO["sorted_in"] = saveSortedIn +} +function translateMain( i, line) { +if (Option["interactive"]) +prompt() +if (Option["input"] == STDIN || fileExists(Option["input"])) { +i = 0 +while (getline line < Option["input"]) +if (line) { +if (!Option["interactive"]) +if (Option["verbose"] && i++ > 0) +p(prettify("source-seperator", +replicate(Option["chr-source-seperator"], +Option["width"]))) +if (Option["interactive"]) +repl(line) +else +translates(line) +} else { +if (!Option["interactive"]) +if (!Option["verbose"]) +p(line) +} +} else +e("[ERROR] File not found: " Option["input"]) +} +function _Init( vm) { +vm = engineMethod("Init") +return @vm() +} +function _RequestUrl(text, sl, tl, hl, vm) { +vm = engineMethod("RequestUrl") +return @vm(text, sl, tl, hl) +} +function _PostRequestUrl(text, sl, tl, hl, type, vm) { +vm = engineMethod("PostRequestUrl") +return @vm(text, sl, tl, hl, type) +} +function _PostRequestContentType(text, sl, tl, hl, type, vm) { +vm = engineMethod("PostRequestContentType") +return @vm(text, sl, tl, hl, type) +} +function _PostRequestUserAgent(text, sl, tl, hl, type, vm) { +vm = engineMethod("PostRequestUserAgent") +return @vm(text, sl, tl, hl, type) +} +function _PostRequestBody(text, sl, tl, hl, type, vm) { +vm = engineMethod("PostRequestBody") +return @vm(text, sl, tl, hl, type) +} +function _TTSUrl(text, tl, vm) { +vm = engineMethod("TTSUrl") +return @vm(text, tl) +} +function _WebTranslateUrl(uri, sl, tl, hl, vm) { +vm = engineMethod("WebTranslateUrl") +return @vm(uri, sl, tl, hl) +} +function _Translate(text, sl, tl, hl, +isVerbose, toSpeech, returnPlaylist, returnIl, +vm) { +vm = engineMethod("Translate") +return @vm(text, sl, tl, hl, +isVerbose, toSpeech, returnPlaylist, returnIl) +} +BEGIN { provides("google") } +function genRL(a, x, +b, c, d, i, y) { +tokenize(y, x) +parseList(b, y) +i = SUBSEP 0 +for (c = 0; c < length(b[i]) - 2; c += 3) { +d = b[i][c + 2] +d = d >= 97 ? d - 87 : +d - 48 +d = b[i][c + 1] == 43 ? rshift(a, d) : lshift(a, d) +a = b[i][c] == 43 ? and(a + d, 4294967295) : xor(a, d) +} +return a +} +function genTK(text, +a, d, dLen, e, tkk, ub, vb) { +if (TK[text]) return TK[text] +tkk = systime() / 3600 +ub = "[43,45,51,94,43,98,43,45,102]" +vb = "[43,45,97,94,43,54]" +dLen = dump(text, d) +a = tkk +for (e = 1; e <= dLen; e++) +a = genRL(a + d[e], vb) +a = genRL(a, ub) +0 > a && (a = and(a, 2147483647) + 2147483648) +a %= 1e6 +TK[text] = a "." xor(a, tkk) +l(text, "text") +l(tkk, "tkk") +l(TK[text], "tk") +return TK[text] +} +function googleInit() { +HttpProtocol = "http://" +HttpHost = "translate.googleapis.com" +HttpPort = 80 +} +function googleRequestUrl(text, sl, tl, hl, qc) { +qc = Option["no-autocorrect"] ? "qc" : "qca"; +return HttpPathPrefix "/translate_a/single?client=gtx"\ +"&ie=UTF-8&oe=UTF-8"\ +"&dt=bd&dt=ex&dt=ld&dt=md&dt=rw&dt=rm&dt=ss&dt=t&dt=at&dt=gt"\ +"&dt=" qc "&sl=" sl "&tl=" tl "&hl=" hl\ +"&q=" preprocessByDump(text) +} +function googleTTSUrl(text, tl) { +return HttpProtocol HttpHost "/translate_tts?ie=UTF-8&client=gtx"\ +"&tl=" tl "&q=" preprocessByDump(text) +} +function googleWebTranslateUrl(uri, sl, tl, hl) { +return "https://translate.google.com/translate?"\ +"hl=" hl "&sl=" sl "&tl=" tl "&u=" uri +} +function googleTranslate(text, sl, tl, hl, +isVerbose, toSpeech, returnPlaylist, returnIl, +r, +content, tokens, ast, +_sl, _tl, _hl, il, ils, isPhonetic, +article, example, explanation, ref, word, +translation, translations, phonetics, +wordClasses, words, segments, altTranslations, +original, oPhonetics, oWordClasses, oWords, +oRefs, oSynonymClasses, oSynonyms, +oExamples, oSeeAlso, +wShowOriginal, wShowOriginalPhonetics, +wShowTranslation, wShowTranslationPhonetics, +wShowPromptMessage, wShowLanguages, +wShowOriginalDictionary, wShowDictionary, +wShowAlternatives, +genderedTrans, hasWordClasses, hasAltTranslations, +i, j, k, group, temp, saveSortedIn) { +isPhonetic = match(tl, /^@/) +tl = substr(tl, 1 + isPhonetic) +if (!getCode(tl)) { +w("[WARNING] Unknown target language code: " tl) +} else if (isRTL(tl)) { +if (!FriBidi) +w("[WARNING] " getName(tl) " is a right-to-left language, but FriBidi is not found.") +} +_sl = getCode(sl); if (!_sl) _sl = sl +_tl = getCode(tl); if (!_tl) _tl = tl +_hl = getCode(hl); if (!_hl) _hl = hl +content = getResponse(text, _sl, _tl, _hl) +if (Option["dump"]) +return content +tokenize(tokens, content) +parseJsonArray(ast, tokens) +l(content, "content", 1, 1) +l(tokens, "tokens", 1, 0, 1) +l(ast, "ast") +if (!isarray(ast) || !anything(ast)) { +e("[ERROR] Oops! Something went wrong and I can't translate it for you :(") +ExitCode = 1 +return +} +saveSortedIn = PROCINFO["sorted_in"] +PROCINFO["sorted_in"] = "compareByIndexFields" +for (i in ast) { +if (ast[i] == "null") continue +if (i ~ "^0" SUBSEP "0" SUBSEP "[[:digit:]]+" SUBSEP "0$") +append(translations, literal(ast[i])) +if (i ~ "^0" SUBSEP "0" SUBSEP "[[:digit:]]+" SUBSEP "1$") +append(original, literal(ast[i])) +if (i ~ "^0" SUBSEP "0" SUBSEP "[[:digit:]]+" SUBSEP "2$") +append(phonetics, literal(ast[i])) +if (i ~ "^0" SUBSEP "0" SUBSEP "[[:digit:]]+" SUBSEP "3$") +append(oPhonetics, literal(ast[i])) +if (match(i, "^0" SUBSEP "1" SUBSEP "([[:digit:]]+)" SUBSEP "0$", group)) +wordClasses[group[1]] = literal(ast[i]) +if (match(i, "^0" SUBSEP "1" SUBSEP "([[:digit:]]+)" SUBSEP "2" SUBSEP "([[:digit:]]+)" SUBSEP "([[:digit:]]+)$", group)) +words[group[1]][group[2]][group[3]] = literal(ast[i]) +if (match(i, "^0" SUBSEP "1" SUBSEP "([[:digit:]]+)" SUBSEP "2" SUBSEP "([[:digit:]]+)" SUBSEP "1" SUBSEP "([[:digit:]]+)$", group)) +words[group[1]][group[2]]["1"][group[3]] = literal(ast[i]) +if (match(i, "^0" SUBSEP "5" SUBSEP "([[:digit:]]+)" SUBSEP "0$", group)) { +segments[group[1]] = literal(ast[i]) +altTranslations[group[1]][0] = "" +} +if (match(i, "^0" SUBSEP "5" SUBSEP "([[:digit:]]+)" SUBSEP "2" SUBSEP "([[:digit:]]+)" SUBSEP "0$", group)) +altTranslations[group[1]][group[2]] = literal(ast[i]) +if (i ~ "^0" SUBSEP "7" SUBSEP "5$") { +if (ast[i] == "true") +w("Showing translation for: (use -no-auto to disable autocorrect)") +else +w("Did you mean: "\ +ansi("bold", unparameterize(ast["0" SUBSEP "7" SUBSEP "1"]))) +} +if (i ~ "^0" SUBSEP "8" SUBSEP "0" SUBSEP "[[:digit:]]+$" || +i ~ "^0" SUBSEP "2$") +append(ils, literal(ast[i])) +if (match(i, "^0" SUBSEP "11" SUBSEP "([[:digit:]]+)" SUBSEP "0$", group)) +oSynonymClasses[group[1]] = literal(ast[i]) +if (match(i, "^0" SUBSEP "11" SUBSEP "([[:digit:]]+)" SUBSEP "1" SUBSEP "([[:digit:]]+)" SUBSEP "1$", group)) +if (ast[i]) { +oRefs[literal(ast[i])][1] = group[1] +oRefs[literal(ast[i])][2] = group[2] +} +if (match(i, "^0" SUBSEP "11" SUBSEP "([[:digit:]]+)" SUBSEP "1" SUBSEP "([[:digit:]]+)" SUBSEP "0" SUBSEP "([[:digit:]]+)$", group)) +oSynonyms[group[1]][group[2]][group[3]] = literal(ast[i]) +if (match(i, "^0" SUBSEP "12" SUBSEP "([[:digit:]]+)" SUBSEP "0$", group)) +oWordClasses[group[1]] = literal(ast[i]) +if (match(i, "^0" SUBSEP "12" SUBSEP "([[:digit:]]+)" SUBSEP "1" SUBSEP "([[:digit:]]+)" SUBSEP "0$", group)) +oWords[group[1]][group[2]][0] = literal(ast[i]) +if (match(i, "^0" SUBSEP "12" SUBSEP "([[:digit:]]+)" SUBSEP "1" SUBSEP "([[:digit:]]+)" SUBSEP "1$", group)) +oWords[group[1]][group[2]][1] = literal(ast[i]) +if (match(i, "^0" SUBSEP "12" SUBSEP "([[:digit:]]+)" SUBSEP "1" SUBSEP "([[:digit:]]+)" SUBSEP "2$", group)) +oWords[group[1]][group[2]][2] = literal(ast[i]) +if (match(i, "^0" SUBSEP "13" SUBSEP "0" SUBSEP "([[:digit:]]+)" SUBSEP "0$", group)) +oExamples[group[1]] = literal(ast[i]) +if (match(i, "^0" SUBSEP "14" SUBSEP "0" SUBSEP "([[:digit:]]+)$", group)) +oSeeAlso[group[1]] = literal(ast[i]) +if (match(i, "^0" SUBSEP "18" SUBSEP "0" SUBSEP "([[:digit:]]+)" SUBSEP "1$", group)) +genderedTrans[group[1]] = literal(ast[i]) +} +PROCINFO["sorted_in"] = saveSortedIn +translation = join(translations) +returnIl[0] = il = !anything(ils) || belongsTo(sl, ils) ? sl : ils[0] +if (Option["verbose"] < -1) +return il +else if (Option["verbose"] < 0) +return getList(il) +if (!isVerbose) { +r = isPhonetic && anything(phonetics) ? +prettify("brief-translation-phonetics", join(phonetics, " ")) : +prettify("brief-translation", s(translation, tl)) +if (toSpeech) { +returnPlaylist[0]["text"] = translation +returnPlaylist[0]["tl"] = _tl +} +} else { +wShowOriginal = Option["show-original"] +wShowOriginalPhonetics = Option["show-original-phonetics"] +wShowTranslation = Option["show-translation"] +wShowTranslationPhonetics = Option["show-translation-phonetics"] +wShowPromptMessage = Option["show-prompt-message"] +wShowLanguages = Option["show-languages"] +wShowOriginalDictionary = Option["show-original-dictionary"] +wShowDictionary = Option["show-dictionary"] +wShowAlternatives = Option["show-alternatives"] +if (!anything(oPhonetics)) wShowOriginalPhonetics = 0 +if (!anything(phonetics)) wShowTranslationPhonetics = 0 +if (getCode(il) == getCode(tl) &&\ +(isarray(oWordClasses) || isarray(oSynonymClasses) ||\ +isarray(oExamples) || isarray(oSeeAlso))) { +wShowOriginalDictionary = 1 +wShowTranslation = 0 +} +hasWordClasses = exists(wordClasses) +hasAltTranslations = exists(altTranslations[0]) +if (!hasWordClasses && !hasAltTranslations) +wShowPromptMessage = wShowLanguages = 0 +if (!hasWordClasses) wShowDictionary = 0 +if (!hasAltTranslations) wShowAlternatives = 0 +if (wShowOriginal) { +if (r) r = r RS RS +r = r m("-- display original text & phonetics") +r = r prettify("original", s(join(original, " "), il)) +if (wShowOriginalPhonetics) +r = r RS prettify("original-phonetics", showPhonetics(join(oPhonetics, " "), il)) +} +if (wShowTranslation) { +if (r) r = r RS RS +r = r m("-- display major translation & phonetics") +if (!exists(genderedTrans)) +r = r prettify("translation", s(translation, tl)) +else { +r = r prettify("prompt-message", s("(♂) ", hl)) +r = r prettify("translation", s(genderedTrans[0], tl)) RS +r = r prettify("prompt-message", s("(♀) ", hl)) +r = r prettify("translation", s(genderedTrans[1], tl)) +} +if (wShowTranslationPhonetics) +r = r RS prettify("translation-phonetics", showPhonetics(join(phonetics, " "), tl)) +} +if (wShowPromptMessage || wShowLanguages) +if (r) r = r RS +if (wShowPromptMessage) { +if (hasWordClasses) { +if (r) r = r RS +r = r m("-- display prompt message (Definitions of ...)") +if (isRTL(hl)) +r = r prettify("prompt-message", s(showDefinitionsOf(hl, join(original, " ")))) +else { +split(showDefinitionsOf(hl, "\0%s\0"), group, "\0") +for (i = 1; i <= length(group); i++) { +if (group[i] == "%s") +r = r prettify("prompt-message-original", show(join(original, " "), il)) +else +r = r prettify("prompt-message", group[i]) +} +} +} else if (hasAltTranslations) { +if (r) r = r RS +r = r m("-- display prompt message (Translations of ...)") +if (isRTL(hl)) +r = r prettify("prompt-message", s(showTranslationsOf(hl, join(original, " ")))) +else { +split(showTranslationsOf(hl, "\0%s\0"), group, "\0") +for (i = 1; i <= length(group); i++) { +if (group[i] == "%s") +r = r prettify("prompt-message-original", show(join(original, " "), il)) +else +r = r prettify("prompt-message", group[i]) +} +} +} +} +if (wShowLanguages) { +if (r) r = r RS +r = r m("-- display source language -> target language") +temp = Option["fmt-languages"] +if (!temp) temp = "[ %s -> %t ]" +split(temp, group, /(%s|%S|%t|%T)/) +r = r prettify("languages", group[1]) +if (temp ~ /%s/) +r = r prettify("languages-sl", getDisplay(il)) +if (temp ~ /%S/) +r = r prettify("languages-sl", getName(il)) +r = r prettify("languages", group[2]) +if (temp ~ /%t/) +r = r prettify("languages-tl", getDisplay(tl)) +if (temp ~ /%T/) +r = r prettify("languages-tl", getName(tl)) +r = r prettify("languages", group[3]) +} +if (wShowOriginalDictionary) { +if (exists(oWordClasses)) { +if (r) r = r RS +r = r m("-- display original dictionary (detailed explanations)") +for (i = 0; i < length(oWordClasses); i++) { +r = (i > 0 ? r RS : r) RS prettify("original-dictionary-detailed-word-class", s(oWordClasses[i], hl)) +for (j = 0; j < length(oWords[i]); j++) { +explanation = oWords[i][j][0] +ref = oWords[i][j][1] +example = oWords[i][j][2] +r = (j > 0 ? r RS : r) RS prettify("original-dictionary-detailed-explanation", ins(1, explanation, il)) +if (example) +r = r RS prettify("original-dictionary-detailed-example", ins(2, "- \"" example "\"", il)) +if (ref && isarray(oRefs[ref])) { +temp = prettify("original-dictionary-detailed-synonyms", ins(1, show(showSynonyms(hl), hl) ": ")) +temp = temp prettify("original-dictionary-detailed-synonyms-item", show(oSynonyms[oRefs[ref][1]][oRefs[ref][2]][0], il)) +for (k = 1; k < length(oSynonyms[oRefs[ref][1]][oRefs[ref][2]]); k++) +temp = temp prettify("original-dictionary-detailed-synonyms", ", ")\ +prettify("original-dictionary-detailed-synonyms-item", show(oSynonyms[oRefs[ref][1]][oRefs[ref][2]][k], il)) +r = r RS temp +} +} +} +} +if (exists(oSynonymClasses)) { +r = r RS RS +r = r m("-- display original dictionary (synonyms)") +r = r prettify("original-dictionary-synonyms", s(showSynonyms(hl), hl)) +for (i = 0; i < length(oSynonymClasses); i++) { +r = (i > 0 ? r RS : r) RS prettify("original-dictionary-synonyms-word-class", ins(1, oSynonymClasses[i], hl)) +for (j = 0; j < length(oSynonyms[i]); j++) { +temp = prettify("original-dictionary-synonyms-synonyms", ins(2, "- ")) +temp = temp prettify("original-dictionary-synonyms-synonyms-item", show(oSynonyms[i][j][0], il)) +for (k = 1; k < length(oSynonyms[i][j]); k++) +temp = temp prettify("original-dictionary-synonyms-synonyms", ", ")\ +prettify("original-dictionary-synonyms-synonyms-item", show(oSynonyms[i][j][k], il)) +r = r RS temp +} +} +} +if (exists(oExamples)) { +r = r RS RS +r = r m("-- display original dictionary (examples)") +r = r prettify("original-dictionary-examples", s(showExamples(hl), hl)) +for (i = 0; i < length(oExamples); i++) { +example = oExamples[i] +temp = prettify("original-dictionary-examples-example", ins(1, "- ")) +split(example, group, /(|<\/b>)/) +if (group[3] ~ / [[:punct:].]/) +group[3] = substr(group[3], 2) +if (isRTL(il)) +temp = temp show(group[1] group[2] group[3], il) +else +temp = temp prettify("original-dictionary-examples-example", group[1])\ +prettify("original-dictionary-examples-original", group[2])\ +prettify("original-dictionary-examples-example", group[3]) +r = (i > 0 ? r RS : r) RS temp +} +} +if (exists(oSeeAlso)) { +r = r RS RS +r = r m("-- display original dictionary (see also)") +r = r prettify("original-dictionary-see-also", s(showSeeAlso(hl), hl)) +temp = ins(1, prettify("original-dictionary-see-also-phrases-item", show(oSeeAlso[0], il))) +for (k = 1; k < length(oSeeAlso); k++) +temp = temp prettify("original-dictionary-see-also-phrases", ", ")\ +prettify("original-dictionary-see-also-phrases-item", show(oSeeAlso[k], il)) +r = r RS temp +} +} +if (wShowDictionary) { +if (r) r = r RS +r = r m("-- display dictionary entries") +for (i = 0; i < length(wordClasses); i++) { +r = (i > 0 ? r RS : r) RS prettify("dictionary-word-class", s(wordClasses[i], hl)) +for (j = 0; j < length(words[i]); j++) { +word = words[i][j][0] +article = words[i][j][4] +if (isRTL(il)) +explanation = join(words[i][j][1], ", ") +else { +explanation = prettify("dictionary-explanation-item", words[i][j][1][0]) +for (k = 1; k < length(words[i][j][1]); k++) +explanation = explanation prettify("dictionary-explanation", ", ")\ +prettify("dictionary-explanation-item", words[i][j][1][k]) +} +r = r RS prettify("dictionary-word", ins(1, (article ? "(" article ") " : "") word, tl)) +if (isRTL(il)) +r = r RS prettify("dictionary-explanation-item", ins(2, explanation, il)) +else +r = r RS ins(2, explanation) +} +} +} +if (wShowAlternatives) { +if (r) r = r RS RS +r = r m("-- display alternative translations") +for (i = 0; i < length(altTranslations); i++) { +r = (i > 0 ? r RS : r) prettify("alternatives-original", show(segments[i], il)) +if (isRTL(tl)) { +temp = join(altTranslations[i], ", ") +r = r RS prettify("alternatives-translations-item", ins(1, temp, tl)) +} else { +temp = prettify("alternatives-translations-item", altTranslations[i][0]) +for (j = 1; j < length(altTranslations[i]); j++) +temp = temp prettify("alternatives-translations", ", ")\ +prettify("alternatives-translations-item", altTranslations[i][j]) +r = r RS ins(1, temp) +} +} +} +if (toSpeech) { +if (index(showTranslationsOf(hl, "%s"), "%s") > 2) { +returnPlaylist[0]["text"] = showTranslationsOf(hl) +returnPlaylist[0]["tl"] = _hl +returnPlaylist[1]["text"] = join(original) +returnPlaylist[1]["tl"] = il +} else { +returnPlaylist[0]["text"] = join(original) +returnPlaylist[0]["tl"] = il +returnPlaylist[1]["text"] = showTranslationsOf(hl) +returnPlaylist[1]["tl"] = _hl +} +returnPlaylist[2]["text"] = translation +returnPlaylist[2]["tl"] = _tl +} +} +return r +} +BEGIN { provides("bing") } +function bingInit() { +HttpProtocol = "http://" +HttpHost = "www.bing.com" +HttpPort = 80 +} +function bingSetIG( content, cookie, group, header, isBody, +url, status, location) { +url = HttpPathPrefix "/translator" +header = "GET " url " HTTP/1.1\r\n"\ +"Host: " HttpHost "\r\n"\ +"Connection: close\r\n" +if (Option["user-agent"]) +header = header "User-Agent: " Option["user-agent"] "\r\n" +cookie = NULLSTR +print header |& HttpService +while ((HttpService |& getline) > 0) { +match($0, /Set-Cookie: ([^;]*);/, group) +if (group[1]) { +cookie = cookie (cookie ? "; " : NULLSTR) group[1] +} +if (isBody) +content = content ? content "\n" $0 : $0 +else if (length($0) <= 1) +isBody = 1 +else { +match($0, /^HTTP[^ ]* ([^ ]*)/, group) +if (RSTART) status = group[1] +match($0, /^Location: (.*)/, group) +if (RSTART) location = squeeze(group[1]) +} +l(sprintf("%4s bytes > %s", length($0), length($0) < 1024 ? $0 : "...")) +} +close(HttpService) +if ((status == "301" || status == "302") && location) +content = curl(location) +Cookie = cookie +match(content, /IG:"([^"]+)"/, group) +if (group[1]) { +IG = group[1] +} else { +e("[ERROR] Oops! Something went wrong and I can't translate it for you :(") +exit 1 +} +} +function bingTTSUrl(text, tl, +country, gender, i, group, +header, content, isBody) { +gender = "female" +country = NULLSTR +split(Option["narrator"], group, ",") +for (i in group) { +if (group[i] ~ /^(f(emale)?|w(oman)?)$/) +gender = "female" +else if (group[i] ~ /^m(ale|an)?$/) +gender = "male" +else +country = group[i] +} +if (country) tl = tl "-" country +else if (tl == "ar") tl = tl "-EG" +else if (tl == "da") tl = tl "-DK" +else if (tl == "de") tl = tl "-DE" +else if (tl == "en") tl = tl "-US" +else if (tl == "es") tl = tl "-ES" +else if (tl == "fi") tl = tl "-FI" +else if (tl == "fr") tl = tl "-FR" +else if (tl == "it") tl = tl "-IT" +else if (tl == "ja") tl = tl "-JP" +else if (tl == "ko") tl = tl "-KR" +else if (tl == "nl") tl = tl "-NL" +else if (tl == "nb") tl = tl "-NO" +else if (tl == "pl") tl = tl "-PL" +else if (tl == "pt") tl = tl "-PT" +else if (tl == "ru") tl = tl "-RU" +else if (tl == "sv") tl = tl "-SE" +else if (tl == "yue") ; +else if (tl == "zh") tl = tl "-CN" +header = "GET " "/tspeak?"\ +"&language=" tl "&text=" preprocess(text)\ +"&options=" gender "&format=audio%2Fmp3" " HTTP/1.1\r\n"\ +"Host: " HttpHost "\r\n"\ +"Connection: close\r\n" +if (Option["user-agent"]) +header = header "User-Agent: " Option["user-agent"] "\r\n" +if (Cookie) +header = header "Cookie: " Cookie "\r\n" +content = NULLSTR; isBody = 0 +print header |& HttpService +while ((HttpService |& getline) > 0) { +if (isBody) +content = content ? content "\n" $0 : $0 +else if (length($0) <= 1) +isBody = 1 +} +close(HttpService) +if (!TempFile) +TempFile = getOutput("mktemp") +printf("%s", content) > TempFile +close(TempFile) +return TempFile +} +function bingWebTranslateUrl(uri, sl, tl, hl, _sl, _tl) { +_sl = sl; _tl = tl +if (_sl == "bs") _sl = "bs-Latn" +if (_sl == "zh") _sl = "zh-CHS" +if (_sl == "zh-CN") _sl = "zh-CHS" +if (_sl == "zh-TW") _sl = "zh-CHT" +if (_tl == "bs") _tl = "bs-Latn" +if (_tl == "zh") _tl = "zh-CHS" +if (_tl == "zh-CN") _tl = "zh-CHS" +if (_tl == "zh-TW") _tl = "zh-CHT" +return "https://www.translatetheweb.com/?" "from=" _sl "&to=" _tl "&a=" uri +} +function bingRequestUrl(text, sl, tl, hl) { +return HttpPathPrefix "/translator/api/Dictionary/Lookup?"\ +"from=" sl "&to=" tl "&text=" preprocess(text) +} +function bingPostRequestUrl(text, sl, tl, hl, type) { +if (type == "lookup") +return HttpPathPrefix "/tlookupv3" +else # type == "translate" +return HttpPathPrefix "/ttranslatev3" +} +function bingPostRequestContentType(text, sl, tl, hl, type) { +return "application/x-www-form-urlencoded" +} +function bingPostRequestUserAgent(text, sl, tl, hl, type) { +return "" +} +function bingPostRequestBody(text, sl, tl, hl, type) { +if (type == "lookup") +return "&text=" quote(text) "&from=" sl "&to=" tl +else # type == "translate" +return "&text=" quote(text) "&fromLang=" sl "&to=" tl +} +function bingTranslate(text, sl, tl, hl, +isVerbose, toSpeech, returnPlaylist, returnIl, +r, +content, tokens, ast, dicContent, dicTokens, dicAst, +_sl, _tl, _hl, il, isPhonetic, +translation, phonetics, oPhonetics, +wordClasses, words, wordBackTranslations, +wShowOriginal, wShowOriginalPhonetics, +wShowTranslation, wShowTranslationPhonetics, +wShowLanguages, wShowDictionary, +i, j, k, group, temp, saveSortedIn) { +isPhonetic = match(tl, /^@/) +tl = substr(tl, 1 + isPhonetic) +if (!getCode(tl)) { +w("[WARNING] Unknown target language code: " tl) +} else if (isRTL(tl)) { +if (!FriBidi) +w("[WARNING] " getName(tl) " is a right-to-left language, but FriBidi is not found.") +} +_sl = getCode(sl); if (!_sl) _sl = sl +_tl = getCode(tl); if (!_tl) _tl = tl +_hl = getCode(hl); if (!_hl) _hl = hl +if (_sl == "auto") _sl = "auto-detect" +if (_sl == "bs") _sl = "bs-Latn" +if (_sl == "no") _sl = "nb" +if (_sl == "pt") _sl = "pt-pt" +if (_sl == "zh-CN") _sl = "zh-Hans" +if (_sl == "zh-TW") _sl = "zh-Hant" +if (_tl == "bs") _tl = "bs-Latn" +if (_tl == "no") _tl = "nb" +if (_tl == "pt") _tl = "pt-pt" +if (_tl == "zh-CN") _tl = "zh-Hans" +if (_tl == "zh-TW") _tl = "zh-Hant" +content = postResponse(text, _sl, _tl, _hl, "translate") +if (content == "") { +HttpHost = "cn.bing.com" +if (Option["proxy"]) { +HttpPathPrefix = HttpProtocol HttpHost +} else { +HttpService = "/" "inet" "/tcp/0/" HttpHost "/" HttpPort +} +content = postResponse(text, _sl, _tl, _hl, "translate") +} +if (Option["dump"]) +return content +tokenize(tokens, content) +parseJson(ast, tokens) +l(content, "content", 1, 1) +l(tokens, "tokens", 1, 0, 1) +l(ast, "ast") +if (!isarray(ast) || !anything(ast)) { +e("[ERROR] Oops! Something went wrong and I can't translate it for you :(") +ExitCode = 1 +return +} +translation = unparameterize(ast[0 SUBSEP 0 SUBSEP "translations" SUBSEP 0 SUBSEP "text"]) +returnIl[0] = il = _sl == "auto-detect" ? +unparameterize(ast[0 SUBSEP 0 SUBSEP "detectedLanguage" SUBSEP "language"]) : _sl +if (Option["verbose"] < -1) +return il +if (Option["verbose"] < 0) +return getList(il) +wShowTranslationPhonetics = Option["show-translation-phonetics"] +if (wShowTranslationPhonetics) { +split(_tl, group, "-") +phonetics = unparameterize(ast[0 SUBSEP 0 SUBSEP "translations" SUBSEP 0 SUBSEP "transliteration"\ +SUBSEP "text"]) +if (phonetics == translation) phonetics = "" +} +if (!isVerbose) { +r = isPhonetic && phonetics ? +prettify("brief-translation-phonetics", join(phonetics, " ")) : +prettify("brief-translation", s(translation, tl)) +} else { +wShowOriginal = Option["show-original"] +wShowTranslation = Option["show-translation"] +wShowLanguages = Option["show-languages"] +wShowDictionary = Option["show-dictionary"] +wShowOriginalPhonetics = Option["show-original-phonetics"] +if (wShowOriginalPhonetics) { +split(_sl, group, "-") +delete ast +content = postResponse(text, il, il, _hl, "translate") +tokenize(tokens, content) +parseJson(ast, tokens) +oPhonetics = unparameterize(ast[0 SUBSEP 0 SUBSEP "translations" SUBSEP 0\ +SUBSEP "transliteration" SUBSEP "text"]) +if (oPhonetics == text) oPhonetics = "" +} +if (!oPhonetics) wShowOriginalPhonetics = 0 +if (!phonetics) wShowTranslationPhonetics = 0 +if (wShowOriginal) { +if (r) r = r RS RS +r = r m("-- display original text") +r = r prettify("original", s(text, _sl)) +if (wShowOriginalPhonetics) +r = r RS prettify("original-phonetics", showPhonetics(join(oPhonetics, " "), _sl)) +} +if (wShowTranslation) { +if (r) r = r RS RS +r = r m("-- display major translation") +r = r prettify("translation", s(translation, tl)) +if (wShowTranslationPhonetics) +r = r RS prettify("translation-phonetics", showPhonetics(join(phonetics, " "), tl)) +} +if (wShowLanguages) { +if (r) r = r RS RS +r = r m("-- display source language -> target language") +temp = Option["fmt-languages"] +if (!temp) temp = "[ %s -> %t ]" +split(temp, group, /(%s|%S|%t|%T)/) +r = r prettify("languages", group[1]) +if (temp ~ /%s/) +r = r prettify("languages-sl", getDisplay(il)) +if (temp ~ /%S/) +r = r prettify("languages-sl", getName(il)) +r = r prettify("languages", group[2]) +if (temp ~ /%t/) +r = r prettify("languages-tl", getDisplay(tl)) +if (temp ~ /%T/) +r = r prettify("languages-tl", getName(tl)) +r = r prettify("languages", group[3]) +} +if (wShowDictionary) { +dicContent = postResponse(text, il, _tl, _hl, "lookup") +if (dicContent != "") { +tokenize(dicTokens, dicContent) +parseJson(dicAst, dicTokens) +l(dicContent, "dicContent", 1, 1) +l(dicTokens, "dicTokens", 1, 0, 1) +l(dicAst, "dicAst") +saveSortedIn = PROCINFO["sorted_in"] +PROCINFO["sorted_in"] = "compareByIndexFields" +for (i in dicAst) { +if (match(i, "^0" SUBSEP "0" SUBSEP "translations" SUBSEP "([[:digit:]]+)" SUBSEP\ +"posTag$", group)) +wordClasses[group[1]] = tolower(literal(dicAst[i])) +} +for (i in dicAst) { +if (match(i, "^0" SUBSEP "0" SUBSEP "translations" SUBSEP "([[:digit:]]+)" SUBSEP\ +"displayTarget$", group)) +words[wordClasses[group[1]]][group[1]] = literal(dicAst[i]) +if (match(i, "^0" SUBSEP "0" SUBSEP "translations" SUBSEP "([[:digit:]]+)" SUBSEP\ +"backTranslations" SUBSEP "([[:digit:]]+)" SUBSEP "displayText$", group)) +wordBackTranslations[wordClasses[group[1]]][group[1]][group[2]] = literal(dicAst[i]) +} +PROCINFO["sorted_in"] = saveSortedIn +if (r) r = r RS +r = r m("-- display dictionary entries") +for (i = 0; i < length(words); i++) { +r = (i > 0 ? r RS : r) RS prettify("dictionary-word-class", s(wordClasses[i], hl)) +for (j in words[wordClasses[i]]) { +r = r RS prettify("dictionary-word", ins(1, words[wordClasses[i]][j], tl)) +if (isRTL(il)) +explanation = join(wordBackTranslations[wordClasses[i]][j], ", ") +else { +explanation = prettify("dictionary-explanation-item", +wordBackTranslations[wordClasses[i]][j][0]) +for (k = 1; k < length(wordBackTranslations[wordClasses[i]][j]); k++) +explanation = explanation prettify("dictionary-explanation", ", ")\ +prettify("dictionary-explanation-item", +wordBackTranslations[wordClasses[i]][j][k]) +} +if (isRTL(il)) +r = r RS prettify("dictionary-explanation-item", ins(2, explanation, il)) +else +r = r RS ins(2, explanation) +} +} +} +} +} +if (toSpeech) { +returnPlaylist[0]["text"] = translation +returnPlaylist[0]["tl"] = _tl +} +return r +} +BEGIN { provides("yandex") } +function genSID( content, group, temp) { +content = curl("http://translate.yandex.com") +match(content, /SID:[[:space:]]*'([^']+)'/, group) +if (group[1]) { +split(group[1], temp, ".") +SID = reverse(temp[1]) "." reverse(temp[2]) "." reverse(temp[3]) +} else { +e("[ERROR] Oops! Something went wrong and I can't translate it for you :(") +exit 1 +} +} +function yandexInit() { +genSID() +YandexWebTranslate = "z5h64q92x9.net" +HttpProtocol = "http://" +HttpHost = "translate.yandex.net" +HttpPort = 80 +} +function yandexRequestUrl(text, sl, tl, hl, group) { +split(sl, group, "-"); sl = group[1] +split(tl, group, "-"); tl = group[1] +return HttpPathPrefix "/api/v1/tr.json/translate?"\ +"id=" SID "-0-0&srv=tr-text"\ +"&text=" preprocess(text) "&lang=" (sl == "auto" ? tl : sl "-" tl) +} +function yandexPostRequestBody(text, sl, tl, hl, type) { +return "text=" quote(text) "&lang=" sl +} +function yandexGetDictionaryResponse(text, sl, tl, hl, content, header, isBody, url) { +split(sl, group, "-"); sl = group[1] +split(tl, group, "-"); tl = group[1] +url = "http://dictionary.yandex.net/dicservice.json/lookupMultiple?"\ +"&text=" preprocess(text) "&dict=" sl "-" tl +content = curl(url) +return assert(content, "[ERROR] Null response.") +} +function yandexTTSUrl(text, tl, +speaker, emotion, i, group) { +speaker = NULLSTR +emotion = NULLSTR +split(Option["narrator"], group, ",") +for (i in group) { +if (group[i] ~ /^(g(ood)?|n(eutral)?|e(vil)?)$/) +emotion = group[i] +else if (group[i] ~ /^(f(emale)?|w(oman)?)$/) +speaker = "alyss" +else if (group[i] ~ /^m(ale|an)?$/) +speaker = "zahar" +else +speaker = group[i] +} +switch (tl) { +case "ar": tl = "ar_AE"; break +case "cs": tl = "cs_CZ"; break +case "da": tl = "da_DK"; break +case "de": tl = "de_DE"; break +case "el": tl = "el_GR"; break +case "en": tl = "en_GB"; break +case "es": tl = "es_ES"; break +case "fi": tl = "fi_FI"; break +case "fr": tl = "fr_FR"; break +case "it": tl = "it_IT"; break +case "nl": tl = "nl_NL"; break +case "no": tl = "no_NO"; break +case "pl": tl = "pl_PL"; break +case "pt": tl = "pt_PT"; break +case "ru": tl = "ru_RU"; break +case "sv": tl = "sv_SE"; break +case "tr": tl = "tr_TR"; break +default: tl = NULLSTR +} +return HttpProtocol "tts.voicetech.yandex.net" "/tts?"\ +"text=" preprocess(text) (tl ? "&lang=" tl : tl)\ +(speaker ? "&speaker=" speaker : speaker)\ +(emotion ? "&emotion=" emotion : emotion)\ +"&format=mp3" "&quality=hi" +} +function yandexWebTranslateUrl(uri, sl, tl, hl) { +gsub(/:\/\//, "/", uri) +return HttpProtocol YandexWebTranslate "/proxy_u/"\ +(sl == "auto" ? tl : sl "-" tl)"/" uri +} +function yandexTranslate(text, sl, tl, hl, +isVerbose, toSpeech, returnPlaylist, returnIl, +r, +content, tokens, ast, +_sl, _tl, _hl, il, isPhonetic, +translation, +wShowOriginal, wShowTranslation, wShowLanguages, +wShowDictionary, dicContent, dicTokens, dicAst, +i, syn, mean, +group, temp) { +isPhonetic = match(tl, /^@/) +tl = substr(tl, 1 + isPhonetic) +if (!getCode(tl)) { +w("[WARNING] Unknown target language code: " tl) +} else if (isRTL(tl)) { +if (!FriBidi) +w("[WARNING] " getName(tl) " is a right-to-left language, but FriBidi is not found.") +} +_sl = getCode(sl); if (!_sl) _sl = sl +_tl = getCode(tl); if (!_tl) _tl = tl +_hl = getCode(hl); if (!_hl) _hl = hl +content = getResponse(text, _sl, _tl, _hl) +if (Option["dump"]) +return content +tokenize(tokens, content) +parseJson(ast, tokens) +l(content, "content", 1, 1) +l(tokens, "tokens", 1, 0, 1) +l(ast, "ast") +if (!isarray(ast) || !anything(ast)) { +e("[ERROR] Oops! Something went wrong and I can't translate it for you :(") +ExitCode = 1 +return +} +if (ast[0 SUBSEP "code"] != "200") { +e("[ERROR] " unparameterize(ast[0 SUBSEP "message"])) +ExitCode = 1 +return +} +translation = unparameterize(ast[0 SUBSEP "text" SUBSEP 0]) +wShowTranslationPhonetics = Option["show-translation-phonetics"] +if (wShowTranslationPhonetics && _tl != "emj") { +split(_tl, group, "-") +data = yandexPostRequestBody(translation, group[1], group[1], _hl, "translit") +content = curlPost("https://translate.yandex.net/translit/translit", data) +phonetics = (content ~ /not supported$/) ? "" : unparameterize(content) +} +split(unparameterize(ast[0 SUBSEP "lang"]), group, "-") +returnIl[0] = il = group[1] +if (Option["verbose"] < -1) +return il +else if (Option["verbose"] < 0) +return getList(il) +if (!isVerbose) { +r = isPhonetic && phonetics ? +prettify("brief-translation-phonetics", join(phonetics, " ")) : +prettify("brief-translation", s(translation, tl)) +} else { +wShowOriginal = Option["show-original"] +wShowTranslation = Option["show-translation"] +wShowLanguages = Option["show-languages"] +wShowDictionary = Option["show-dictionary"] +wShowOriginalPhonetics = Option["show-original-phonetics"] +if (wShowTranslationPhonetics && il != "emj") { +split(il, group, "-") +data = yandexPostRequestBody(text, group[1], group[1], _hl, "translit") +content = curlPost("https://translate.yandex.net/translit/translit", data) +oPhonetics = (content ~ /not supported$/) ? "" : unparameterize(content) +} +if (!oPhonetics) wShowOriginalPhonetics = 0 +if (!phonetics) wShowTranslationPhonetics = 0 +if (wShowOriginal) { +if (r) r = r RS RS +r = r m("-- display original text & phonetics") +r = r prettify("original", s(text, il)) +if (wShowOriginalPhonetics) +r = r RS prettify("original-phonetics", showPhonetics(join(oPhonetics, " "), il)) +} +if (wShowTranslation) { +if (r) r = r RS RS +r = r m("-- display major translation") +r = r prettify("translation", s(translation, tl)) +if (wShowTranslationPhonetics) +r = r RS prettify("translation-phonetics", showPhonetics(join(phonetics, " "), tl)) +} +if (wShowLanguages) { +if (r) r = r RS RS +r = r m("-- display source language -> target language") +temp = Option["fmt-languages"] +if (!temp) temp = "[ %s -> %t ]" +split(temp, group, /(%s|%S|%t|%T)/) +r = r prettify("languages", group[1]) +if (temp ~ /%s/) +r = r prettify("languages-sl", getDisplay(il)) +if (temp ~ /%S/) +r = r prettify("languages-sl", getName(il)) +r = r prettify("languages", group[2]) +if (temp ~ /%t/) +r = r prettify("languages-tl", getDisplay(tl)) +if (temp ~ /%T/) +r = r prettify("languages-tl", getName(tl)) +r = r prettify("languages", group[3]) +} +if (wShowDictionary && false) { +dicContent = yandexGetDictionaryResponse(text, il, _tl, _hl) +tokenize(dicTokens, dicContent) +parseJson(dicAst, dicTokens) +if (anything(dicAst)) { +if (r) r = r RS +r = r m("-- display dictionary entries") +saveSortedIn = PROCINFO["sorted_in"] +PROCINFO["sorted_in"] = "@ind_num_asc" +for (i in dicAst) { +if (i ~ "^0" SUBSEP "def" SUBSEP "[[:digit:]]+" SUBSEP\ +"pos$") { +r = r RS prettify("dictionary-word-class", s((literal(dicAst[i])), hl)) +syn = mean = "" +} +if (i ~ "^0" SUBSEP "def" SUBSEP "[[:digit:]]+" SUBSEP\ +"tr" SUBSEP "[[:digit:]]+" SUBSEP\ +"mean" SUBSEP "[[:digit:]]+" SUBSEP "text") { +if (mean) { +mean = mean prettify("dictionary-explanation", ", ")\ +prettify("dictionary-explanation-item", s((literal(dicAst[i])), sl)) +} else { +mean = prettify("dictionary-explanation-item", s((literal(dicAst[i])), sl)) +} +} +if (i ~ "^0" SUBSEP "def" SUBSEP "[[:digit:]]+" SUBSEP\ +"tr" SUBSEP "[[:digit:]]+" SUBSEP\ +"syn" SUBSEP "[[:digit:]]+" SUBSEP "text") { +if (syn) { +syn = syn prettify("dictionary-explanation", ", ")\ +prettify("dictionary-word", s((literal(dicAst[i])), il)) +} else { +syn = prettify("dictionary-word", s((literal(dicAst[i])), il)) +} +} +if (i ~ "^0" SUBSEP "def" SUBSEP "[[:digit:]]+" SUBSEP\ +"tr" SUBSEP "[[:digit:]]+" SUBSEP "text$") { +text = prettify("dictionary-word", s((literal(dicAst[i])), il)) +if (syn) { +r = r RS ins(1, text prettify("dictionary-explanation", ", ") syn) +} else { +r = r RS ins(1, text) +} +r = r RS ins(2, mean) +syn = mean = "" +} +} +PROCINFO["sorted_in"] = saveSortedIn +} +} +} +if (toSpeech) { +returnPlaylist[0]["text"] = translation +returnPlaylist[0]["tl"] = _tl +} +return r +} +BEGIN { provides("apertium") } +function apertiumInit() { +HttpProtocol = "http://" +HttpHost = "www.apertium.org" +HttpPort = 80 +} +function apertiumRequestUrl(text, sl, tl, hl) { +return HttpPathPrefix "/apy/translate?"\ +"langpair=" preprocess(sl) "|" preprocess(tl)\ +"&q=" preprocess(text) +} +function apertiumTTSUrl(text, tl, narrator) { +} +function apertiumWebTranslateUrl(uri, sl, tl, hl) { +} +function apertiumTranslate(text, sl, tl, hl, +isVerbose, toSpeech, returnPlaylist, returnIl, +r, +content, tokens, ast, +_sl, _tl, _hl, il, +translation, +wShowOriginal, wShowTranslation, wShowLanguages, +group, temp) { +if (!getCode(tl)) { +w("[WARNING] Unknown target language code: " tl) +} else if (isRTL(tl)) { +if (!FriBidi) +w("[WARNING] " getName(tl) " is a right-to-left language, but FriBidi is not found.") +} +_sl = getCode(sl); if (!_sl) _sl = sl +_tl = getCode(tl); if (!_tl) _tl = tl +_hl = getCode(hl); if (!_hl) _hl = hl +_sl = "auto" == _sl ? "en" : _sl +content = getResponse(text, _sl, _tl, _hl) +if (Option["dump"]) +return content +tokenize(tokens, content) +parseJson(ast, tokens) +l(content, "content", 1, 1) +l(tokens, "tokens", 1, 0, 1) +l(ast, "ast") +if (!isarray(ast) || !anything(ast)) { +e("[ERROR] Oops! Something went wrong and I can't translate it for you :(") +ExitCode = 1 +return +} +translation = uprintf(unquote(unparameterize(ast[0 SUBSEP "responseData" SUBSEP "translatedText"]))) +returnIl[0] = il = _sl +if (Option["verbose"] < -1) +return il +else if (Option["verbose"] < 0) +return getList(il) +if (!isVerbose) { +r = translation +} else { +wShowOriginal = Option["show-original"] +wShowTranslation = Option["show-translation"] +wShowLanguages = Option["show-languages"] +if (wShowOriginal) { +if (r) r = r RS RS +r = r m("-- display original text") +r = r prettify("original", s(text, il)) +} +if (wShowTranslation) { +if (r) r = r RS RS +r = r m("-- display major translation") +r = r prettify("translation", s(translation, tl)) +} +if (wShowLanguages) { +if (r) r = r RS RS +r = r m("-- display source language -> target language") +temp = Option["fmt-languages"] +if (!temp) temp = "[ %s -> %t ]" +split(temp, group, /(%s|%S|%t|%T)/) +r = r prettify("languages", group[1]) +if (temp ~ /%s/) +r = r prettify("languages-sl", getDisplay(il)) +if (temp ~ /%S/) +r = r prettify("languages-sl", getName(il)) +r = r prettify("languages", group[2]) +if (temp ~ /%t/) +r = r prettify("languages-tl", getDisplay(tl)) +if (temp ~ /%T/) +r = r prettify("languages-tl", getName(tl)) +r = r prettify("languages", group[3]) +} +} +if (toSpeech) { +returnPlaylist[0]["text"] = translation +returnPlaylist[0]["tl"] = _tl +} +return r +} +BEGIN { +provides("spell") +provides("aspell") +provides("hunspell") +} +function spellInit() { +Ispell = detectProgram("aspell", "--version") ? "aspell" : +(detectProgram("hunspell", "--version") ? "hunspell" : "") +if (!Ispell) { +e("[ERROR] Spell checker (aspell or hunspell) not found.") +exit 1 +} +} +function aspellInit() { +if (!(Ispell = detectProgram("aspell", "--version") ? "aspell" : "")) { +e("[ERROR] Spell checker (aspell) not found.") +exit 1 +} +} +function hunspellInit() { +if (!(Ispell = detectProgram("hunspell", "--version") ? "hunspell" : "")) { +e("[ERROR] Spell checker (hunspell) not found.") +exit 1 +} +} +function spellTranslate(text, sl, tl, hl, +isVerbose, toSpeech, returnPlaylist, returnIl, +args, i, j, r, line, group, word, sug) { +args = " -a" (sl != "auto" ? " -d " sl : "") +if (system("echo" PIPE Ispell args SUPOUT SUPERR)) { +e("[ERROR] No dictionary for language: " sl) +exit 1 +} +i = 1 +r = "" +while ((("echo " parameterize(text) PIPE Ispell args SUPERR) |& getline line) > 0) { +match(line, +/^& (.*) [[:digit:]]+ [[:digit:]]+: ([^,]+)(, ([^,]+))?(, ([^,]+))?/, +group) +if (RSTART) { +ExitCode = 1 +word = group[1] +sug = "[" group[2] +if (group[4]) sug = sug "|" group[4] +if (group[6]) sug = sug "|" group[6] +sug = sug "]" +j = i + index(substr(text, i), word) - 1 +r = r substr(text, i, j - i) +r = r ansi("bold", ansi("red", word)) ansi("yellow", sug) +i = j + length(word) +} +} +r = r substr(text, i) +return r +} +function aspellTranslate(text, sl, tl, hl, +isVerbose, toSpeech, returnPlaylist, returnIl) { +return spellTranslate(text, sl, tl, hl) +} +function hunspellTranslate(text, sl, tl, hl, +isVerbose, toSpeech, returnPlaylist, returnIl) { +return spellTranslate(text, sl, tl, hl) +} +function spellTTSUrl(text, tl, narrator) { +e("[ERROR] Spell checker does not support TTS.") +ExitCode = 1 +return +} +function aspellTTSUrl(text, tl, narrator) { +return spellTTSUrl(text, tl) +} +function hunspellTTSUrl(text, tl, narrator) { +return spellTTSUrl(text, tl) +} +function spellWebTranslateUrl(uri, sl, tl, hl) { +e("[ERROR] Spell checker does not support web translation.") +ExitCode = 1 +return +} +function aspellWebTranslateUrl(uri, sl, tl, hl) { +return spellWebTranslateUrl(uri, sl, tl, hl) +} +function hunspellWebTranslateUrl(uri, sl, tl, hl) { +return spellWebTranslateUrl(uri, sl, tl, hl) +} +function loadOptions(script, i, j, tokens, name, value) { +tokenize(tokens, script) +for (i in tokens) { +if (tokens[i] ~ /^:/) { +name = substr(tokens[i], 2) +value = tokens[i + 1] +if (value ~ /^[+-]?((0|[1-9][0-9]*)|[.][0-9]*|(0|[1-9][0-9]*)[.][0-9]*)([Ee][+-]?[0-9]+)?$/) { +delete Option[name] +Option[name] = value +} else if (value == "false" || value == "true") { +delete Option[name] +Option[name] = yn(value) +} else if (value ~ /^".*"$/) { +delete Option[name] +Option[name] = literal(value) +} else if (value == "[") { +delete Option[name] +for (j = 1; tokens[i + j + 1] && tokens[i + j + 1] != "]"; j++) { +if (tokens[i + j + 1] ~ /^".*"$/) +Option[name][j] = literal(tokens[i + j + 1]) +else { +e("[ERROR] Malformed configuration.") +return +} +} +} else { +e("[ERROR] Malformed configuration.") +return +} +} +} +} +function upgrade( i, newVersion, registry, tokens) { +RegistryIndex = "https://raw.githubusercontent.com/soimort/translate-shell/registry/index.trans" +registry = curl(RegistryIndex) +if (!registry) { +e("[ERROR] Failed to check for upgrade.") +ExitCode = 1 +return +} +tokenize(tokens, registry) +for (i in tokens) +if (tokens[i] == ":translate-shell") +newVersion = literal(tokens[i + 1]) +if (newerVersion(newVersion, Version)) { +w("Current version: \t" Version) +w("New version available: \t" newVersion) +w("Download from: \t" "https://www.soimort.org/translate-shell/trans") +} else { +w("Current version: \t" Version) +w("Already up-to-date.") +} +} +function welcome() { +if (Option["fmt-welcome-message"]) +print prettify("welcome-message", Option["fmt-welcome-message"]) > STDERR +if (Option["fmt-welcome-submessage"]) +print prettify("welcome-submessage", Option["fmt-welcome-submessage"]) > STDERR +} +function prompt( i, p, temp) { +p = Option["fmt-prompt"] +if (p ~ /%a/) gsub(/%a/, strftime("%a"), p) +if (p ~ /%A/) gsub(/%A/, strftime("%A"), p) +if (p ~ /%b/) gsub(/%b/, strftime("%b"), p) +if (p ~ /%B/) gsub(/%B/, strftime("%B"), p) +if (p ~ /%c/) gsub(/%c/, strftime("%c"), p) +if (p ~ /%C/) gsub(/%C/, strftime("%C"), p) +if (p ~ /%d/) gsub(/%d/, strftime("%d"), p) +if (p ~ /%D/) gsub(/%D/, strftime("%D"), p) +if (p ~ /%e/) gsub(/%e/, strftime("%e"), p) +if (p ~ /%F/) gsub(/%F/, strftime("%F"), p) +if (p ~ /%g/) gsub(/%g/, strftime("%g"), p) +if (p ~ /%G/) gsub(/%G/, strftime("%G"), p) +if (p ~ /%h/) gsub(/%h/, strftime("%h"), p) +if (p ~ /%H/) gsub(/%H/, strftime("%H"), p) +if (p ~ /%I/) gsub(/%I/, strftime("%I"), p) +if (p ~ /%j/) gsub(/%j/, strftime("%j"), p) +if (p ~ /%m/) gsub(/%m/, strftime("%m"), p) +if (p ~ /%M/) gsub(/%M/, strftime("%M"), p) +if (p ~ /%n/) gsub(/%n/, strftime("%n"), p) +if (p ~ /%p/) gsub(/%p/, strftime("%p"), p) +if (p ~ /%r/) gsub(/%r/, strftime("%r"), p) +if (p ~ /%R/) gsub(/%R/, strftime("%R"), p) +if (p ~ /%u/) gsub(/%u/, strftime("%u"), p) +if (p ~ /%U/) gsub(/%U/, strftime("%U"), p) +if (p ~ /%V/) gsub(/%V/, strftime("%V"), p) +if (p ~ /%w/) gsub(/%w/, strftime("%w"), p) +if (p ~ /%W/) gsub(/%W/, strftime("%W"), p) +if (p ~ /%x/) gsub(/%x/, strftime("%x"), p) +if (p ~ /%X/) gsub(/%X/, strftime("%X"), p) +if (p ~ /%y/) gsub(/%y/, strftime("%y"), p) +if (p ~ /%Y/) gsub(/%Y/, strftime("%Y"), p) +if (p ~ /%z/) gsub(/%z/, strftime("%z"), p) +if (p ~ /%Z/) gsub(/%Z/, strftime("%Z"), p) +if (p ~ /%_/) +gsub(/%_/, showTranslationsOf(Option["hl"]), p) +if (p ~ /%l/) +gsub(/%l/, getDisplay(Option["hl"]), p) +if (p ~ /%L/) +gsub(/%L/, getName(Option["hl"]), p) +if (p ~ /%S/) { +temp = getName(Option["sls"][1]) +for (i = 2; i <= length(Option["sls"]); i++) +temp = temp "+" getName(Option["sls"][i]) +gsub(/%S/, temp, p) +} +if (p ~ /%t/) { +temp = getDisplay(Option["tl"][1]) +for (i = 2; i <= length(Option["tl"]); i++) +temp = temp "+" getDisplay(Option["tl"][i]) +gsub(/%t/, temp, p) +} +if (p ~ /%T/) { +temp = getName(Option["tl"][1]) +for (i = 2; i <= length(Option["tl"]); i++) +temp = temp "+" getName(Option["tl"][i]) +gsub(/%T/, temp, p) +} +if (p ~ /%,/) { +temp = getDisplay(Option["tl"][1]) +for (i = 2; i <= length(Option["tl"]); i++) +temp = temp "," getDisplay(Option["tl"][i]) +gsub(/%,/, temp, p) +} +if (p ~ /% STDERR +} +function repl(line, command, group, name, i, value, words) { +split(line, words, " ") +command = words[1] +if (command ~ /^:(q|quit)$/) { +exit +} else if (command ~ /^:set$/) { +name = words[2] +value = words[3] +Option[name] = value +} else if (command ~ /^:show$/) { +name = words[2] +print prettify("welcome-submessage", toString(Option[name], 1, 0, 1)) +} else if (command ~ /^:engine$/) { +value = words[2] +Option["engine"] = value +initHttpService() +} else { +match(command, /^[{(\[]?((@?[[:alpha:]][[:alpha:]][[:alpha:]]?(-[[:alpha:]][[:alpha:]][[:alpha:]]?[[:alpha:]]?)?\+)*(@?[[:alpha:]][[:alpha:]][[:alpha:]]?(-[[:alpha:]][[:alpha:]][[:alpha:]]?[[:alpha:]]?)?)?)?(:|=)((@?[[:alpha:]][[:alpha:]][[:alpha:]]?(-[[:alpha:]][[:alpha:]][[:alpha:]]?[[:alpha:]]?)?\+)*(@?[[:alpha:]][[:alpha:]][[:alpha:]]?(-[[:alpha:]][[:alpha:]][[:alpha:]]?[[:alpha:]]?)?)?)[})\]]?$/, group) +if (RSTART) { +if (group[1]) { +split(group[1], Option["sls"], "+") +Option["sl"] = Option["sls"][1] +} +if (group[7]) split(group[7], Option["tl"], "+") +line = words[2] +for (i = 3; i <= length(words); i++) +line = line " " words[i] +} +if (line) { +translates(line) +if (Option["verbose"]) printf RS +} +} +prompt() +} +function init() { +initGawk() +initBiDiTerm() +initBiDi() +initLocale() +initLocaleAlias() +initUserLang() +RS = "\n" +ExitCode = 0 +Option["debug"] = 0 +Option["engine"] = "google" +Option["verbose"] = 1 +Option["show-original"] = 1 +Option["show-original-phonetics"] = 1 +Option["show-translation"] = 1 +Option["show-translation-phonetics"] = 1 +Option["show-prompt-message"] = 1 +Option["show-languages"] = 1 +Option["show-original-dictionary"] = 0 +Option["show-dictionary"] = 1 +Option["show-alternatives"] = 1 +Option["width"] = ENVIRON["COLUMNS"] ? ENVIRON["COLUMNS"] - 2 : 0 +Option["indent"] = 4 +Option["no-ansi"] = 0 +Option["no-autocorrect"] = 0 +Option["no-bidi"] = 0 +Option["force-bidi"] = 0 +Option["no-warn"] = 0 +Option["theme"] = "default" +Option["dump"] = 0 +Option["play"] = 0 +Option["narrator"] = "female" +Option["player"] = ENVIRON["PLAYER"] +Option["no-translate"] = 0 +Option["download-audio"] = 0 +Option["download-audio-as"] = NULLSTR +Option["view"] = 0 +Option["pager"] = ENVIRON["PAGER"] +Option["browser"] = ENVIRON["BROWSER"] +Option["proxy"] = ENVIRON["HTTP_PROXY"] ? ENVIRON["HTTP_PROXY"] : ENVIRON["http_proxy"] +Option["user-agent"] = ENVIRON["USER_AGENT"] ? ENVIRON["USER_AGENT"] : +"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) "\ +"AppleWebKit/537.36 (KHTML, like Gecko) "\ +"Chrome/81.0.4044.138 "\ +"Safari/537.36" +Option["ip-version"] = 0 +Option["no-rlwrap"] = 0 +Option["interactive"] = 0 +Option["emacs"] = 0 +Option["input"] = NULLSTR +Option["output"] = STDOUT +Option["hl"] = ENVIRON["HOME_LANG"] ? ENVIRON["HOME_LANG"] : UserLang +Option["sl"] = ENVIRON["SOURCE_LANG"] ? ENVIRON["SOURCE_LANG"] : "auto" +Option["sls"][1] = Option["sl"] +Option["tl"][1] = ENVIRON["TARGET_LANG"] ? ENVIRON["TARGET_LANG"] : UserLang +Option["join-sentence"] = 0 +} +function initScript( file, line, script, temp) { +file = ".trans" +if (!fileExists(file)) { +file = ENVIRON["HOME"] "/.translate-shell/init.trans" +if (!fileExists(file)) { +file = ENVIRON["XDG_CONFIG_HOME"] "/translate-shell/init.trans" +if (!fileExists(file)) { +file = ENVIRON["HOME"] "/.config/translate-shell/init.trans" +if (!fileExists(file)) { +file = "/etc/translate-shell" +if (!fileExists(file)) return +} +} +} +} +InitScript = file +script = NULLSTR +while (getline line < InitScript) +script = script "\n" line +loadOptions(script) +if (!isarray(Option["tl"])) { +temp = Option["tl"] +delete Option["tl"] +Option["tl"][1] = temp +} +} +function initMisc( command, group, temp) { +initHttpService() +if (!Option["width"] && detectProgram("tput", "-V")) { +command = "tput cols" SUPERR +command | getline temp +close(command) +Option["width"] = temp > 5 ? temp - 2 : 64 +} +if (Option["no-ansi"]) +delete AnsiCode +if (Option["no-bidi"] || BiDiTerm == "mlterm") +BiDi = BiDiNoPad = NULLSTR +else if (!Option["force-bidi"] && BiDiTerm == "konsole") { +BiDiNoPad = NULLSTR +BiDi = "sed \"s/'/\\\\\\'/\" | xargs -0 printf '%%%ss'" +} +initLocaleDisplay() +if (Option["no-warn"]) +STDERR = "/dev/null" +if (Option["play"]) { +if (!Option["player"]) { +initAudioPlayer() +Option["player"] = AudioPlayer ? AudioPlayer : Option["player"] +if (!Option["player"]) +initSpeechSynthesizer() +} +if (!Option["player"] && !SpeechSynthesizer) { +w("[WARNING] No available audio player or speech synthesizer.") +Option["play"] = 0 +} +} +if (Option["view"]) { +if (!Option["pager"]) { +initPager() +Option["pager"] = Pager +} +if (!Option["pager"]) { +w("[WARNING] No available terminal pager.") +Option["view"] = 0 +} +} +if (!Option["browser"]) { +Platform = detectProgram("uname", "-s", 1) +Option["browser"] = Platform == "Darwin" ? "open" : "xdg-open" +} +} +BEGIN { +init() +if (!(belongsTo("-no-init", ARGV) || belongsTo("--no-init", ARGV))) +initScript() +pos = 0 +noargc = 0 +while (ARGV[++pos]) { +match(ARGV[pos], /^--?(V|vers(i(on?)?)?)$/) +if (RSTART) { +InfoOnly = "version" +continue +} +match(ARGV[pos], /^--?(H|h(e(lp?)?)?)$/) +if (RSTART) { +InfoOnly = "help" +continue +} +match(ARGV[pos], /^--?(M|m(a(n(u(al?)?)?)?)?)$/) +if (RSTART) { +InfoOnly = "manual" +continue +} +match(ARGV[pos], /^--?(T|ref(e(r(e(n(ce?)?)?)?)?)?)$/) +if (RSTART) { +InfoOnly = "reference" +continue +} +match(ARGV[pos], /^--?r$/) +if (RSTART) { +w("[WARNING] Option '-r' has been deprecated since version 0.9.\n"\ +" Use option '-T' or '-reference' instead.") +exit 1 +} +match(ARGV[pos], /^--?(R|reference-e(n(g(l(i(sh?)?)?)?)?)?)$/) +if (RSTART) { +InfoOnly = "reference-english" +continue +} +match(ARGV[pos], /^--?(L|list)(=(.*)?)?$/, group) +if (RSTART) { +InfoOnly = "list" +if (group[2]) { +if (group[3]) split(group[3], Option["tl"], "+") +} else +split(ARGV[++pos], Option["tl"], "+") +continue +} +match(ARGV[pos], /^--?(S|list-e(n(g(i(n(es?)?)?)?)?)?)$/) +if (RSTART) { +InfoOnly = "list-engines" +continue +} +match(ARGV[pos], /^--?(U|upgrade)$/) +if (RSTART) { +InfoOnly = "upgrade" +continue +} +match(ARGV[pos], /^--?(N|nothing)$/) +if (RSTART) { +InfoOnly = "nothing" +continue +} +match(ARGV[pos], /^--?(e|engine)(=(.*)?)?$/, group) +if (RSTART) { +Option["engine"] = group[2] ? +(group[3] ? group[3] : Option["engine"]) : +ARGV[++pos] +continue +} +match(ARGV[pos], /^\/(.*)$/, group) +if (RSTART) { +Option["engine"] = group[1] +continue +} +match(ARGV[pos], /^--?verbose$/) +if (RSTART) { +Option["verbose"] = 1 +continue +} +match(ARGV[pos], /^--?b(r(i(ef?)?)?)?$/) +if (RSTART) { +Option["verbose"] = 0 +continue +} +match(ARGV[pos], /^--?d(i(c(t(i(o(n(a(ry?)?)?)?)?)?)?)?)?$/) +if (RSTART) { +Option["show-original-dictionary"] = 1 +Option["show-dictionary"] = 0 +Option["show-alternatives"] = 0 +continue +} +match(ARGV[pos], /^--?id(e(n(t(i(fy?)?)?)?)?)?$/) +if (RSTART) { +Option["verbose"] = Option["verbose"] - 2 +continue +} +match(ARGV[pos], /^--?show-original(=(.*)?)?$/, group) +if (RSTART) { +Option["show-original"] = yn(group[1] ? group[2] : ARGV[++pos]) +continue +} +match(ARGV[pos], /^--?show-original-phonetics(=(.*)?)?$/, group) +if (RSTART) { +Option["show-original-phonetics"] = yn(group[1] ? group[2] : ARGV[++pos]) +continue +} +match(ARGV[pos], /^--?show-translation(=(.*)?)?$/, group) +if (RSTART) { +Option["show-translation"] = yn(group[1] ? group[2] : ARGV[++pos]) +continue +} +match(ARGV[pos], /^--?show-translation-phonetics(=(.*)?)?$/, group) +if (RSTART) { +Option["show-translation-phonetics"] = yn(group[1] ? group[2] : ARGV[++pos]) +continue +} +match(ARGV[pos], /^--?show-prompt-message(=(.*)?)?$/, group) +if (RSTART) { +Option["show-prompt-message"] = yn(group[1] ? group[2] : ARGV[++pos]) +continue +} +match(ARGV[pos], /^--?show-languages(=(.*)?)?$/, group) +if (RSTART) { +Option["show-languages"] = yn(group[1] ? group[2] : ARGV[++pos]) +continue +} +match(ARGV[pos], /^--?show-original-dictionary(=(.*)?)?$/, group) +if (RSTART) { +Option["show-original-dictionary"] = yn(group[1] ? group[2] : ARGV[++pos]) +continue +} +match(ARGV[pos], /^--?show-dictionary(=(.*)?)?$/, group) +if (RSTART) { +Option["show-dictionary"] = yn(group[1] ? group[2] : ARGV[++pos]) +continue +} +match(ARGV[pos], /^--?show-alternatives(=(.*)?)?$/, group) +if (RSTART) { +Option["show-alternatives"] = yn(group[1] ? group[2] : ARGV[++pos]) +continue +} +match(ARGV[pos], /^--?w(i(d(th?)?)?)?(=(.*)?)?$/, group) +if (RSTART) { +Option["width"] = group[4] ? +(group[5] ? group[5] : Option["width"]) : +ARGV[++pos] +continue +} +match(ARGV[pos], /^--?indent(=(.*)?)?$/, group) +if (RSTART) { +Option["indent"] = group[1] ? +(group[2] ? group[2] : Option["indent"]) : +ARGV[++pos] +continue +} +match(ARGV[pos], /^--?theme(=(.*)?)?$/, group) +if (RSTART) { +Option["theme"] = group[1] ? +(group[2] ? group[2] : Option["theme"]) : +ARGV[++pos] +continue +} +match(ARGV[pos], /^--?no-theme$/) +if (RSTART) { +Option["theme"] = NULLSTR +continue +} +match(ARGV[pos], /^--?no-ansi$/) +if (RSTART) { +Option["no-ansi"] = 1 +continue +} +match(ARGV[pos], /^--?no-auto(correct)?$/) +if (RSTART) { +Option["no-autocorrect"] = 1 +continue +} +match(ARGV[pos], /^--?no-bidi/) +if (RSTART) { +Option["no-bidi"] = 1 +continue +} +match(ARGV[pos], /^--?bidi/) +if (RSTART) { +Option["force-bidi"] = 1 +continue +} +match(ARGV[pos], /^--?no-warn/) +if (RSTART) { +Option["no-warn"] = 1 +continue +} +match(ARGV[pos], /^--?dump/) +if (RSTART) { +Option["dump"] = 1 +continue +} +match(ARGV[pos], /^--?p(l(ay?)?)?$/) +if (RSTART) { +Option["play"] = 1 +continue +} +match(ARGV[pos], /^--?sp(e(ak?)?)?$/) +if (RSTART) { +Option["play"] = 2 +continue +} +match(ARGV[pos], /^--?(n|narrator)(=(.*)?)?$/, group) +if (RSTART) { +if (!Option["play"]) Option["play"] = 1 +Option["narrator"] = group[2] ? +(group[3] ? group[3] : Option["narrator"]) : +ARGV[++pos] +continue +} +match(ARGV[pos], /^--?player(=(.*)?)?$/, group) +if (RSTART) { +if (!Option["play"]) Option["play"] = 1 +Option["player"] = group[1] ? +(group[2] ? group[2] : Option["player"]) : +ARGV[++pos] +continue +} +match(ARGV[pos], /^--?no-play$/) +if (RSTART) { +Option["play"] = 0 +continue +} +match(ARGV[pos], /^--?no-tran(s(l(a(te?)?)?)?)?$/) +if (RSTART) { +Option["no-translate"] = 1 +continue +} +match(ARGV[pos], /^--?download-a(u(d(io?)?)?)?$/) +if (RSTART) { +Option["download-audio"] = 1 +continue +} +match(ARGV[pos], /^--?download-audio-as(=(.*)?)?$/, group) +if (RSTART) { +if (!Option["download-audio"]) Option["download-audio"] = 1 +Option["download-audio-as"] = group[1] ? +(group[2] ? group[2] : Option["download-audio-as"]) : +ARGV[++pos] +continue +} +match(ARGV[pos], /^--?v(i(ew?)?)?$/) +if (RSTART) { +Option["view"] = 1 +continue +} +match(ARGV[pos], /^--?pager(=(.*)?)?$/, group) +if (RSTART) { +Option["view"] = 1 +Option["pager"] = group[1] ? +(group[2] ? group[2] : Option["pager"]) : +ARGV[++pos] +continue +} +match(ARGV[pos], /^--?no-(view|pager)$/) +if (RSTART) { +Option["view"] = 0 +continue +} +match(ARGV[pos], /^--?browser(=(.*)?)?$/, group) +if (RSTART) { +Option["browser"] = group[1] ? +(group[2] ? group[2] : Option["browser"]) : +ARGV[++pos] +continue +} +match(ARGV[pos], /^--?no-browser$/) +if (RSTART) { +Option["browser"] = NONE +continue +} +match(ARGV[pos], /^--?(x|proxy)(=(.*)?)?$/, group) +if (RSTART) { +Option["proxy"] = group[2] ? +(group[3] ? group[3] : Option["proxy"]) : +ARGV[++pos] +continue +} +match(ARGV[pos], /^--?(u|user-agent)(=(.*)?)?$/, group) +if (RSTART) { +Option["user-agent"] = group[2] ? +(group[3] ? group[3] : Option["user-agent"]) : +ARGV[++pos] +continue +} +match(ARGV[pos], /^--?(4|ipv4|inet4-only)$/) +if (RSTART) { +Option["ip-version"] = 4 +continue +} +match(ARGV[pos], /^--?(6|ipv6|inet6-only)$/) +if (RSTART) { +Option["ip-version"] = 6 +continue +} +match(ARGV[pos], /^--?(I|int(e(r(a(c(t(i(ve?)?)?)?)?)?)?)?|shell)$/) +if (RSTART) { +Option["interactive"] = 1 +continue +} +match(ARGV[pos], /^--?(E|emacs)$/) +if (RSTART) { +Option["emacs"] = 1 +continue +} +match(ARGV[pos], /^--?no-rlwrap$/) +if (RSTART) { +Option["no-rlwrap"] = 1 +continue +} +match(ARGV[pos], /^--?prompt(=(.*)?)?$/, group) +if (RSTART) { +w("[ERROR] Option '-prompt' has been deprecated since version 0.9.\n"\ +" Use configuration variable 'fmt-prompt' instead.") +exit 1 +} +match(ARGV[pos], /^--?prompt-color(=(.*)?)?$/, group) +if (RSTART) { +w("[ERROR] Option '-prompt-color' has been deprecated since version 0.9.\n"\ +" Use configuration variable 'sgr-prompt' instead.") +exit 1 +} +match(ARGV[pos], /^--?i(n(p(ut?)?)?)?(=(.*)?)?$/, group) +if (RSTART) { +Option["input"] = group[4] ? +(group[5] ? group[5] : Option["input"]) : +ARGV[++pos] +continue +} +match(ARGV[pos], /^--?o(u(t(p(ut?)?)?)?)?(=(.*)?)?$/, group) +if (RSTART) { +Option["output"] = group[5] ? +(group[6] ? group[6] : Option["output"]) : +ARGV[++pos] +continue +} +match(ARGV[pos], /^--?(l(a(ng?)?)?|hl)(=(.*)?)?$/, group) +if (RSTART) { +Option["hl"] = group[4] ? +(group[5] ? group[5] : Option["hl"]) : +ARGV[++pos] +continue +} +match(ARGV[pos], /^--?(s(o(u(r(ce?)?)?)?|l)?|f|from)(=(.*)?)?$/, group) +if (RSTART) { +if (group[6]) { +if (group[7]) split(group[7], Option["sls"], "+") +} else +split(ARGV[++pos], Option["sls"], "+") +Option["sl"] = Option["sls"][1] +continue +} +match(ARGV[pos], /^--?t(a(r(g(et?)?)?)?|l|o)?(=(.*)?)?$/, group) +if (RSTART) { +if (group[5]) { +if (group[6]) split(group[6], Option["tl"], "+") +} else +split(ARGV[++pos], Option["tl"], "+") +continue +} +match(ARGV[pos], /^[{(\[]?((@?[[:alpha:]][[:alpha:]][[:alpha:]]?(-[[:alpha:]][[:alpha:]][[:alpha:]]?[[:alpha:]]?)?\+)*(@?[[:alpha:]][[:alpha:]][[:alpha:]]?(-[[:alpha:]][[:alpha:]][[:alpha:]]?[[:alpha:]]?)?)?)?(:|=)((@?[[:alpha:]][[:alpha:]][[:alpha:]]?(-[[:alpha:]][[:alpha:]][[:alpha:]]?[[:alpha:]]?)?\+)*(@?[[:alpha:]][[:alpha:]][[:alpha:]]?(-[[:alpha:]][[:alpha:]][[:alpha:]]?[[:alpha:]]?)?)?)[})\]]?$/, group) +if (RSTART) { +if (group[1]) { +split(group[1], Option["sls"], "+") +Option["sl"] = Option["sls"][1] +} +if (group[7]) split(group[7], Option["tl"], "+") +continue +} +match(ARGV[pos], /^--?j(o(i(n(-(s(e(n(t(e(n(ce?)?)?)?)?)?)?)?)?)?)?)?$/) +if (RSTART) { +Option["join-sentence"] = 1 +continue +} +match(ARGV[pos], /^--?(D|debug)$/) +if (RSTART) { +Option["debug"] = 1 +continue +} +match(ARGV[pos], /^--?no-init/) +if (RSTART) continue +match(ARGV[pos], /^-(-?no-op)?$/) +if (RSTART) continue +match(ARGV[pos], /^--$/) +if (RSTART) { +++pos +break +} +noargv[noargc++] = ARGV[pos] +} +if (Option["interactive"] && !Option["no-rlwrap"]) +rlwrapMe() +else if (Option["emacs"] && !Option["interactive"] && !Option["no-rlwrap"]) +if (emacsMe()) +Option["interactive"] = 1 +initMisc() +switch (InfoOnly) { +case "version": +print getVersion() +exit ExitCode +case "help": +print getHelp() +exit ExitCode +case "manual": +showMan() +exit ExitCode +case "reference": +print getReference("endonym") +exit ExitCode +case "reference-english": +print getReference("name") +exit ExitCode +case "list": +print getList(Option["tl"]) +exit ExitCode +case "list-engines": +for (translator in Translator) +print (Option["engine"] == translator ? "* " : " ") translator +exit ExitCode +case "upgrade": +upgrade() +exit ExitCode +case "nothing": +exit ExitCode +} +setTheme() +if (Option["interactive"]) +welcome() +if (pos < ARGC) +for (i = pos; i < ARGC; i++) +noargv[noargc++] = ARGV[i] +if (noargc > 1 && Option["join-sentence"]) { +noargv[0] = join(noargv, " ") +noargc = 1 +} +if (noargc) { +for (i = 0; i < noargc; i++) { +if (Option["verbose"] && i > pos) +p(prettify("source-seperator", replicate(Option["chr-source-seperator"], Option["width"]))) +translates(noargv[i], 1) +} +} else { +if (!Option["input"]) Option["input"] = STDIN +} +if (Option["input"]) +translateMain() +exit ExitCode +} +EOF +read -r -d '' TRANS_MANPAGE << 'EOF' +.\" Automatically generated by Pandoc 2.5 +.\" +.TH "TRANS" "1" "2020\-05\-11" "0.9.6.12" "" +.hy +.SH NAME +.PP +trans \- Command\-line translator using Google Translate, Bing +Translator, Yandex.Translate, etc. +.SH SYNOPSIS +.PP +\f[B]trans\f[R] [\f[I]OPTIONS\f[R]] +[\f[I]SOURCE\f[R]]:[\f[I]TARGETS\f[R]] [\f[I]TEXT\f[R]]... +.SH DESCRIPTION +.PP +This tool translates text into any language from the command\-line, +using a translation engine such as Google Translate, Bing Translator and +Yandex.Translate. +.PP +Each argument which is not a valid option is treated as \f[I]TEXT\f[R] +to be translated. +.PP +If neither \f[I]TEXT\f[R] nor the input file is specified by +command\-line arguments, the program will read and translate from +standard input. +.SH OPTIONS +.SS Information options +.TP +.B \f[B]\-V\f[R], \f[B]\-version\f[R] +Print version and exit. +.TP +.B \f[B]\-H\f[R], \f[B]\-help\f[R] +Print help message and exit. +\f[B]\-M\f[R], \f[B]\-man\f[R] +Show man page and exit. +.TP +.B \f[B]\-T\f[R], \f[B]\-reference\f[R] +Print reference table of all supported languages and codes, and exit. +Names of languages are displayed in their endonyms (language name in the +language itself). +.TP +.B \f[B]\-R\f[R], \f[B]\-reference\-english\f[R] +Print reference table of all supported languages and codes, and exit. +Names of languages are displayed in English. +.TP +.B \f[B]\-L\f[R] \f[I]CODES\f[R], \f[B]\-list\f[R] \f[I]CODES\f[R] +Print details of languages and exit. +When specifying two or more language codes, concatenate them by plus +sign \[dq]+\[dq]. +.TP +.B \f[B]\-S\f[R], \f[B]\-list\-engines\f[R] +List available translation engines and exit. +.TP +.B \f[B]\-U\f[R], \f[B]\-upgrade\f[R] +Check for upgrade of this program. +.SS Translator options +.TP +.B \f[B]\-e\f[R] \f[I]ENGINE\f[R], \f[B]\-engine\f[R] \f[I]ENGINE\f[R] +Specify the translation engine to use. +(default: google) +.SS Display options +.TP +.B \f[B]\-verbose\f[R] +Verbose mode. +.RS +.PP +Show the original text and its most relevant translation, then its +phonetic notation (if any), then its alternative translations (if any) +or its definition in the dictionary (if it is a word). +.PP +This option is unnecessary in most cases since verbose mode is enabled +by default. +.RE +.TP +.B \f[B]\-b\f[R], \f[B]\-brief\f[R] +Brief mode. +.RS +.PP +Show the most relevant translation or its phonetic notation only. +.RE +.TP +.B \f[B]\-d\f[R], \f[B]\-dictionary\f[R] +Dictionary mode. +.RS +.PP +Show the definition of the original word in the dictionary. +.RE +.TP +.B \f[B]\-identify\f[R] +Language identification. +.RS +.PP +Show the identified language of the original text. +.RE +.TP +.B \f[B]\-show\-original\f[R] \f[I]Y/n\f[R] +Show original text or not. +(default: yes) +.TP +.B \f[B]\-show\-original\-phonetics\f[R] \f[I]Y/n\f[R] +Show phonetic notation of original text or not. +(default: yes) +.TP +.B \f[B]\-show\-translation\f[R] \f[I]Y/n\f[R] +Show translation or not. +(default: yes) +.TP +.B \f[B]\-show\-translation\-phonetics\f[R] \f[I]Y/n\f[R] +Show phonetic notation of translation or not. +(default: yes) +.TP +.B \f[B]\-show\-prompt\-message\f[R] \f[I]Y/n\f[R] +Show prompt message or not. +(default: yes) +.TP +.B \f[B]\-show\-languages\f[R] \f[I]Y/n\f[R] +Show source and target languages or not. +(default: yes) +.TP +.B \f[B]\-show\-original\-dictionary\f[R] \f[I]y/N\f[R] +Show dictionary entry of original text or not. +(default: no) +.RS +.PP +This option is enabled in dictionary mode. +.RE +.TP +.B \f[B]\-show\-dictionary\f[R] \f[I]Y/n\f[R] +Show dictionary entry of translation or not. +(default: yes) +.TP +.B \f[B]\-show\-alternatives\f[R] \f[I]Y/n\f[R] +Show alternative translations or not. +(default: yes) +.TP +.B \f[B]\-w\f[R] \f[I]NUM\f[R], \f[B]\-width\f[R] \f[I]NUM\f[R] +Specify the screen width for padding. +.RS +.PP +This option overrides the setting of environment variable +$\f[B]COLUMNS\f[R]. +.RE +.TP +.B \f[B]\-indent\f[R] \f[I]NUM\f[R] +Specify the size of indent (number of spaces). +(default: 4) +.TP +.B \f[B]\-theme\f[R] \f[I]FILENAME\f[R] +Specify the theme to use. +(default: default) +.TP +.B \f[B]\-no\-theme\f[R] +Do not use any other theme than default. +.TP +.B \f[B]\-no\-ansi\f[R] +Do not use ANSI escape codes. +.TP +.B \f[B]\-no\-autocorrect\f[R] +Do not autocorrect. +(if defaulted by the translation engine) +.TP +.B \f[B]\-no\-bidi\f[R] +Do not convert bidirectional texts. +.TP +.B \f[B]\-bidi\f[R] +Always convert bidirectional texts. +.TP +.B \f[B]\-no\-warn\f[R] +Do not write warning messages to stderr. +.TP +.B \f[B]\-dump\f[R] +Print raw API response instead. +.SS Audio options +.TP +.B \f[B]\-p\f[R], \f[B]\-play\f[R] +Listen to the translation. +.RS +.PP +You must have at least one of the supported audio players +(\f[B]mplayer\f[R], \f[B]mpv\f[R] or \f[B]mpg123\f[R]) installed to +stream from Google Text\-to\-Speech engine. +Otherwise, a local speech synthesizer may be used instead (\f[B]say\f[R] +on macOS, \f[B]espeak\f[R] on Linux or other platforms). +.RE +.TP +.B \f[B]\-speak\f[R] +Listen to the original text. +.TP +.B \f[B]\-n\f[R] \f[I]VOICE\f[R], \f[B]\-narrator\f[R] \f[I]VOICE\f[R] +Specify the narrator, and listen to the translation. +.RS +.PP +Common values for this option are \f[B]male\f[R] and \f[B]female\f[R]. +.RE +.TP +.B \f[B]\-player\f[R] \f[I]PROGRAM\f[R] +Specify the audio player to use, and listen to the translation. +.RS +.PP +Option \f[B]\-play\f[R] will try to use \f[B]mplayer\f[R], \f[B]mpv\f[R] +or \f[B]mpg123\f[R] by default, since these players are known to work +for streaming URLs. +Not all command\-line audio players can work this way. +Use this option only when you have your own preference. +.PP +This option overrides the setting of environment variable +$\f[B]PLAYER\f[R]. +.RE +.TP +.B \f[B]\-no\-play\f[R] +Do not listen to the translation. +.TP +.B \f[B]\-no\-translate\f[R] +Do not translate anything when using \-speak. +.TP +.B \f[B]\-download\-audio\f[R] +Download the audio to the current directory. +.TP +.B \f[B]\-download\-audio\-as\f[R] \f[I]FILENAME\f[R] +Download the audio to the specified file. +.SS Terminal paging and browsing options +.TP +.B \f[B]\-v\f[R], \f[B]\-view\f[R] +View the translation in a terminal pager (\f[B]less\f[R], \f[B]more\f[R] +or \f[B]most\f[R]). +.TP +.B \f[B]\-pager\f[R] \f[I]PROGRAM\f[R] +Specify the terminal pager to use, and view the translation. +.RS +.PP +This option overrides the setting of environment variable +$\f[B]PAGER\f[R]. +.RE +.TP +.B \f[B]\-no\-view\f[R], \f[B]\-no\-pager\f[R] +Do not view the translation in a terminal pager. +.TP +.B \f[B]\-browser\f[R] \f[I]PROGRAM\f[R] +Specify the web browser to use. +.RS +.PP +This option overrides the setting of environment variable +$\f[B]BROWSER\f[R]. +.RE +.TP +.B \f[B]\-no\-browser\f[R] +Do not open the web browser. +.SS Networking options +.TP +.B \f[B]\-x\f[R] \f[I]HOST:PORT\f[R], \f[B]\-proxy\f[R] \f[I]HOST:PORT\f[R] +Use HTTP proxy on given port. +.RS +.PP +This option overrides the setting of environment variables +$\f[B]HTTP_PROXY\f[R] and $\f[B]http_proxy\f[R]. +.RE +.TP +.B \f[B]\-u\f[R] \f[I]STRING\f[R], \f[B]\-user\-agent\f[R] \f[I]STRING\f[R] +Specify the User\-Agent to identify as. +.RS +.PP +This option overrides the setting of environment variables +$\f[B]USER_AGENT\f[R]. +.RE +.TP +.B \f[B]\-4\f[R], \f[B]\-ipv4\f[R], \f[B]\-inet4\-only\f[R] +Connect only to IPv4 addresses. +.TP +.B \f[B]\-6\f[R], \f[B]\-ipv6\f[R], \f[B]\-inet6\-only\f[R] +Connect only to IPv6 addresses. +.SS Interactive shell options +.TP +.B \f[B]\-I\f[R], \f[B]\-interactive\f[R], \f[B]\-shell\f[R] +Start an interactive shell, invoking \f[B]rlwrap\f[R] whenever possible +(unless \f[B]\-no\-rlwrap\f[R] is specified). +.TP +.B \f[B]\-E\f[R], \f[B]\-emacs\f[R] +Start the GNU Emacs front\-end for an interactive shell. +.RS +.PP +This option does not need to, and cannot be used along with +\f[B]\-I\f[R] or \f[B]\-no\-rlwrap\f[R]. +.RE +.TP +.B \f[B]\-no\-rlwrap\f[R] +Do not invoke \f[B]rlwrap\f[R] when starting an interactive shell. +.RS +.PP +This option is useful when your terminal type is not supported by +\f[B]rlwrap\f[R] (e.g. +\f[B]emacs\f[R]). +.RE +.SS I/O options +.TP +.B \f[B]\-i\f[R] \f[I]FILENAME\f[R], \f[B]\-input\f[R] \f[I]FILENAME\f[R] +Specify the input file. +.RS +.PP +Source text to be translated will be read from the input file, instead +of standard input. +.RE +.TP +.B \f[B]\-o\f[R] \f[I]FILENAME\f[R], \f[B]\-output\f[R] \f[I]FILENAME\f[R] +Specify the output file. +.RS +.PP +Translations will be written to the output file, instead of standard +output. +.RE +.SS Language preference options +.TP +.B \f[B]\-l\f[R] \f[I]CODE\f[R], \f[B]\-hl\f[R] \f[I]CODE\f[R], \f[B]\-lang\f[R] \f[I]CODE\f[R] +Specify your home language (the language you would like to see for +displaying prompt messages in the translation). +.RS +.PP +This option affects only the display in verbose mode (anything other +than source language and target language will be displayed in your home +language). +This option has no effect in brief mode. +.PP +This option is optional. +When its setting is omitted, English will be used. +.PP +This option overrides the setting of environment variables +$\f[B]LC_ALL\f[R], $\f[B]LANG\f[R], and $\f[B]HOME_LANG\f[R]. +.RE +.TP +.B \f[B]\-s\f[R] \f[I]CODES\f[R], \f[B]\-sl\f[R] \f[I]CODES\f[R], \f[B]\-source\f[R] \f[I]CODES\f[R], \f[B]\-from\f[R] \f[I]CODES\f[R] +Specify the source language(s) (the language(s) of original text). +When specifying two or more language codes, concatenate them by plus +sign \[dq]+\[dq]. +.RS +.PP +This option is optional. +When its setting is omitted, the language of original text will be +identified automatically (with a possibility of misidentification). +.PP +This option overrides the setting of environment variable +$\f[B]SOURCE_LANG\f[R]. +.RE +.TP +.B \f[B]\-t\f[R] \f[I]CODES\f[R], \f[B]\-tl\f[R] \f[I]CODES\f[R], \f[B]\-target\f[R] \f[I]CODES\f[R], \f[B]\-to\f[R] \f[I]CODES\f[R] +Specify the target language(s) (the language(s) of translated text). +When specifying two or more language codes, concatenate them by plus +sign \[dq]+\[dq]. +.RS +.PP +This option is optional. +When its setting is omitted, everything will be translated into English. +.PP +This option overrides the setting of environment variables +$\f[B]LC_ALL\f[R], $\f[B]LANG\f[R], and $\f[B]TARGET_LANG\f[R]. +.RE +.TP +.B [\f[I]SOURCE\f[R]]:[\f[I]TARGETS\f[R]] +A simpler, alternative way to specify the source language and target +language(s) is to use a shortcut formatted string: +.RS +.IP \[bu] 2 +\f[I]SOURCE\-CODE\f[R]:\f[I]TARGET\-CODE\f[R] +.IP \[bu] 2 +\f[I]SOURCE\-CODE\f[R]:\f[I]TARGET\-CODE1\f[R]+\f[I]TARGET\-CODE2\f[R]+... +.IP \[bu] 2 +\f[I]SOURCE\-CODE\f[R]=\f[I]TARGET\-CODE\f[R] +.IP \[bu] 2 +\f[I]SOURCE\-CODE\f[R]=\f[I]TARGET\-CODE1\f[R]+\f[I]TARGET\-CODE2\f[R]+... +.PP +Delimiter \[dq]:\[dq] and \[dq]=\[dq] can be used interchangeably. +.PP +Either \f[I]SOURCE\f[R] or \f[I]TARGETS\f[R] may be omitted, but the +delimiter character must be kept. +.RE +.SS Text preprocessing options +.TP +.B \f[B]\-j\f[R], \f[B]\-join\-sentence\f[R] +Treat all arguments as one single sentence. +.SS Other options +.TP +.B \f[B]\-no\-init\f[R] +Do not load any initialization script. +.TP +.B \f[B]\-\-\f[R] +End\-of\-options. +.RS +.PP +All arguments after this option are treated as \f[I]TEXT\f[R] to be +translated. +.RE +.SH EXIT STATUS +.TP +.B \f[B]0\f[R] +Successful translation. +.TP +.B \f[B]1\f[R] +Error. +.SH ENVIRONMENT +.TP +.B \f[B]PAGER\f[R] +Equivalent to option setting \f[B]\-pager\f[R]. +.TP +.B \f[B]BROWSER\f[R] +Equivalent to option setting \f[B]\-browser\f[R]. +.TP +.B \f[B]PLAYER\f[R] +Equivalent to option setting \f[B]\-player\f[R]. +.TP +.B \f[B]HTTP_PROXY\f[R] +Equivalent to option setting \f[B]\-proxy\f[R]. +.TP +.B \f[B]USER_AGENT\f[R] +Equivalent to option setting \f[B]\-user\-agent\f[R]. +.TP +.B \f[B]HOME_LANG\f[R] +Equivalent to option setting \f[B]\-lang\f[R]. +.TP +.B \f[B]SOURCE_LANG\f[R] +Equivalent to option setting \f[B]\-source\f[R]. +.TP +.B \f[B]TARGET_LANG\f[R] +Equivalent to option setting \f[B]\-target\f[R]. +.SH FILES +.TP +.B \f[I]/etc/translate\-shell\f[R] +Initialization script. +(system\-wide) +.TP +.B \f[I]$HOME/.translate\-shell/init.trans\f[R] +Initialization script. +(user\-specific) +.TP +.B \f[I]$XDG_CONFIG_HOME/translate\-shell/init.trans\f[R] +Initialization script. +(user\-specific) +.TP +.B \f[I]./.trans\f[R] +Initialization script. +(current directory) +.SH FURTHER DOCUMENTATION +.PP + +.SH REPORTING BUGS +.PP + +.SH AUTHORS +Mort Yao . +EOF +export TRANS_MANPAGE +export TRANS_BUILD=release +gawk -f <(echo -E "$TRANS_PROGRAM") - "$@" diff --git a/.bin/OLD/transliterate b/.bin/OLD/transliterate new file mode 100755 index 0000000..79a0f19 --- /dev/null +++ b/.bin/OLD/transliterate @@ -0,0 +1,8 @@ +#!/usr/bin/sed -f +s/ä/ae/g +s/Ä/Ae/g +s/ü/ue/g +s/Ü/Ue/g +s/ö/oe/g +s/Ö/Oe/g +s/ß/ss/g diff --git a/.bin/OLD/tterm b/.bin/OLD/tterm new file mode 100755 index 0000000..c8379fd --- /dev/null +++ b/.bin/OLD/tterm @@ -0,0 +1,7 @@ +#!/bin/sh +. $HOME/.bin/_config + +tabbed -d -c \ + -g 2328x1430+200+200 \ + -n scratchpad \ + $STERM -w diff --git a/.bin/OLD/umount_iso b/.bin/OLD/umount_iso new file mode 100755 index 0000000..f68cd08 --- /dev/null +++ b/.bin/OLD/umount_iso @@ -0,0 +1,3 @@ +#!/bin/sh +doas umount -v /mnt +doas vnconfig -vu vnd0c diff --git a/.bin/OLD/undock b/.bin/OLD/undock new file mode 100755 index 0000000..ca177b1 --- /dev/null +++ b/.bin/OLD/undock @@ -0,0 +1,16 @@ +#!/bin/sh + +i=11 +sync +while true +do +i=$((i-1)) +if [ $i -eq 0 ] +then + sync + autorandr -c + exit 0 +fi +echo $i +sleep 1 +done diff --git a/.bin/OLD/unitopia b/.bin/OLD/unitopia new file mode 100755 index 0000000..afa251e --- /dev/null +++ b/.bin/OLD/unitopia @@ -0,0 +1,2 @@ +config="$(basename $0).tin" +echo tt++ ~/.bin/mud/$config diff --git a/.bin/OLD/update-abook.sh b/.bin/OLD/update-abook.sh new file mode 100755 index 0000000..13b085a --- /dev/null +++ b/.bin/OLD/update-abook.sh @@ -0,0 +1,4 @@ +#!/bin/sh +cat /home/sdk/.isync/contacts/*.vcf \ + | abook --convert --informat vcard --outformat abook \ + > /home/sdk/.abook/addressbook diff --git a/.bin/OLD/update_vol.sh b/.bin/OLD/update_vol.sh new file mode 100755 index 0000000..b7c64eb --- /dev/null +++ b/.bin/OLD/update_vol.sh @@ -0,0 +1,2 @@ +#!/bin/sh +printf 'VOL\n' >> /tmp/lemonbar.fifo diff --git a/.bin/OLD/updatebase b/.bin/OLD/updatebase new file mode 100755 index 0000000..5d76d67 --- /dev/null +++ b/.bin/OLD/updatebase @@ -0,0 +1,25 @@ +#!/bin/sh +set -xe + +NCPU=12 +[ x"$1" == x"-1" ] && NCPU=1 + +cd /usr/src +if [ x"$1" == x"-c" ]; +then + doas make build +else + doas make -j $(( NCPU )) +fi +doas make install + +cd /usr/xenocara +doas rm /usr/xobj/xorg-config.cache.amd64 +doas make bootstrap +doas make obj +if [ x"$1" == x"-c" ]; +then + doas make -j $(( NCPU )) build +else + doas make -j $(( NCPU )) +fi diff --git a/.bin/OLD/utf8chars b/.bin/OLD/utf8chars new file mode 100755 index 0000000..351310e --- /dev/null +++ b/.bin/OLD/utf8chars @@ -0,0 +1,49 @@ +#!/bin/cat + +smilies +😀😃😄😁😆😅😂😊😇🙃😉😌😍😘😗😙😚😋😛😝😜 😎😏😒😞😔😟😕😣😖😩😢😭😤😠😡😳😱😨😰😥😓 +😶😐😑😬😯😦😧😮😲😴😪😵😷😈👿👹👺💩👻💩👻 💀👽👾🎃😺😸😹😻😼😽🙀😿😾 + +hands +👐🙌👏👍👎👊✊👌👈👉👆👇✋👋💪🙏 + +männchen +👤👥👨👩👷👨🎓👨💻👨💼👨🔧 + +tiere +🐭🐰🐸🐶🐵🙈🙉🙊🐢 + +nature +🌸🌼🌻🌞🌝🌛🌜🌚🌕🌖🌗🌘🌑🌒🌓🌔🌙🌎🌍🌏💫 ⭐🌟✨⚡💥🔥🌈☀🌤⛅⛄💨💧💦☔ + +essen +🍏🍎🍐🍊🍋🍌🍉🍇🍓🍈🍒🍑🍍🍅🍆🌽🍠🍞🍳🍗🍖 🍔🍟🍕🍝🍜🍲🍛🍣🍱🍤🍚🍧🍨🍦🍮🍭🍬🍫🍩🍪🌰 +🍯🍼☕🍵🍶🍺🍻🍷🍸🍹🍴 + + +activity +⚽🏀🏈⚾🎾🏉🎱⛳🎣🎽🏂🏆🎬🎤🎧🎼🎨🎹🎷🎺🎸 🎻🎲♟🎯🎳🎮🎰 + +travel +🚗🚕🚙🚌🚎🚓🚑🚒🚐🚚🚛🚜🚲🚨🚔🚍🚖🚡🚠🚟🚃 🚋🚞🚝🚄🚅🚈🚂🚆🚇🚊🚉💺🚀🚁⛵🚤🚢⚓⛽🚧🚦 +🚥🚏🗿🗽🗼🏰🏯🎡🎢🎠⛲🌋🗻⛺🏠🏡🏭🏢🏬🏣🏤 🏥🏦🏨🏪🏫🏩💒⛪🎑🌅🌄🌠🎇🎆🌇🌆🏙🌃🌌🌉🌁 + +objects +⌚📱📲💻💽💾💿📀📼📷📹🎥📞📟📠📺📻⏰⌛⏳📡 🔋🔌💡🔦💸💵💴💶💷💰💳💎🔨🔧🔩🔫💣🔪🚬🔮💈 +🔭🔬💊💉🚽🚰🚿🛁🛀🔑🚪🎁🎈🎁🎈🎏🎀🎊🎉🎎🏮 🎐📩📨📧💌📥📤📦📪📫📬📭📮📯📜📃📄📑📊📈📉 +📆📅📇📋📁📂📰📓📔📒📕📗📘📙📚📖🔖🔗📎📐📏 📌📍📝🔍🔎🔏🔐🔒🔓 + +symbols +💛💚💙💜💔💕💞💓💗💖💘💝💟🔯⛎♈♉♊♋♌♍ ♎♏♐♑♒♓🆔🉑📴📳🈶🈚🈸🈺🈷🆚💮🉐㊙㊗🈴 +🈵🈹🈲🅰🅱🆎🆑🆘❌⭕⛔📛🚫💯💢🚷🚯🚳🚱🔞📵🚭 ❗❕❓❔🔅🔆〽🚸🔱🔰✅🈯💹❎🌐💠🌀💤🏧🚾♿ +🈳🈂🛂🛃🛄🛅🚹🚺🚼🚻🚮🎦📶🈁🔣🔤🔡🔠🆖🆗🆙 🆒🆕🆓0123456789ℹ🔟🔢⏩⏪⏫⏬◀🔼🔽🔀🔁🔂🔄 +🔃🎵🎶➕➖➗💲💱™©®🔚🔙🔛🔝🔜〰➰➿✔🔘🔴🔵 ⚫⚪🔺🔻🔸🔹🔶🔷🔳🔲▪▫◾◽⬛⬜🔈🔇🔉🔊🔔🔕 +📣📢💬💭🃏🎴🀄🕐🕑🕒🕓🕔🕕🕖🕗🕘🕙🕚🕛🕜🕝 🕞🕟🕠🕡🕢🕣🕤🕥🕦🕧🏁🌈 + +Selection: +™©®✅⭕❌⭐🔑🔎💌💾👤👥🐰🐸💛💚💙💜📷🌷 + +Icons: +                          +                          +             diff --git a/.bin/v b/.bin/OLD/v similarity index 100% rename from .bin/v rename to .bin/OLD/v diff --git a/.bin/OLD/videosort b/.bin/OLD/videosort new file mode 100755 index 0000000..24ece70 --- /dev/null +++ b/.bin/OLD/videosort @@ -0,0 +1,21 @@ +#!/bin/sh +mkdir -p 720p 1080p 2160p SD FIX +find . -type f | while read file; +do + unset w + w="$(mediainfo --Output="Video;%Width%" "$file")" + [ -z $w ] && continue + printf '%s | %s\n' "$w" "$file"; + if [ $w -ge 16000 ]; then + mv "$file" FIX/ + elif [ $w -ge 3200 ]; then + mv "$file" 2160p/ + elif [ $w -ge 1700 ]; then + mv "$file" 1080p/ + elif [ $w -ge 1200 ]; then + mv "$file" 720p/ + else + mv "$file" SD/ + fi +done +find . -empty -delete diff --git a/.bin/OLD/vim-fzf b/.bin/OLD/vim-fzf new file mode 100755 index 0000000..faf8960 --- /dev/null +++ b/.bin/OLD/vim-fzf @@ -0,0 +1,4 @@ +#!/bin/sh + +_dir="$1" +cd "${_dir:=.}" && vim $(fzf) diff --git a/.bin/OLD/vimb b/.bin/OLD/vimb new file mode 100755 index 0000000..ee978ce --- /dev/null +++ b/.bin/OLD/vimb @@ -0,0 +1,4 @@ +#!/bin/sh +unset _SWM_WM +unset LD_PRELOAD +/usr/local/bin/vimb --no-maximize $@ diff --git a/.bin/OLD/vimdiff-rej b/.bin/OLD/vimdiff-rej new file mode 100755 index 0000000..45a3068 --- /dev/null +++ b/.bin/OLD/vimdiff-rej @@ -0,0 +1,6 @@ +#!/bin/sh + +for f in $(find . -type f -name "*.rej") +do + vimdiff -c':set noscb' -c':set nocursorbind' $f ${f%.*} +done diff --git a/.bin/webdev b/.bin/OLD/webdev similarity index 100% rename from .bin/webdev rename to .bin/OLD/webdev diff --git a/.bin/website-add-image-to-gallery b/.bin/OLD/website-add-image-to-gallery similarity index 100% rename from .bin/website-add-image-to-gallery rename to .bin/OLD/website-add-image-to-gallery diff --git a/.bin/whatmem b/.bin/OLD/whatmem similarity index 100% rename from .bin/whatmem rename to .bin/OLD/whatmem diff --git a/.bin/OLD/wifi-cast b/.bin/OLD/wifi-cast new file mode 100755 index 0000000..28ada35 --- /dev/null +++ b/.bin/OLD/wifi-cast @@ -0,0 +1,2 @@ +#!/bin/sh -x +doas ifconfig iwx0 nwid "Fiyapoo BF91C306" wpakey GeekConnection diff --git a/.bin/OLD/wifi-discmate b/.bin/OLD/wifi-discmate new file mode 100755 index 0000000..65de0d6 --- /dev/null +++ b/.bin/OLD/wifi-discmate @@ -0,0 +1,2 @@ +#!/bin/sh -x +doas ifconfig iwx0 nwid DiscMate wpakey GeekConnection23 diff --git a/.bin/OLD/wifi-freifunk b/.bin/OLD/wifi-freifunk new file mode 100755 index 0000000..a103e22 --- /dev/null +++ b/.bin/OLD/wifi-freifunk @@ -0,0 +1,2 @@ +#!/bin/sh -x +doas ifconfig iwx0 nwid freifunk-rhein-neckar.de diff --git a/.bin/OLD/wifi-hotspot b/.bin/OLD/wifi-hotspot new file mode 100755 index 0000000..6b384b4 --- /dev/null +++ b/.bin/OLD/wifi-hotspot @@ -0,0 +1,2 @@ +#!/bin/sh -x +doas ifconfig iwx0 nwid iphone-14-pro-s wpakey dudeldei diff --git a/.bin/OLD/wifi-mobilemate b/.bin/OLD/wifi-mobilemate new file mode 100755 index 0000000..bde58fa --- /dev/null +++ b/.bin/OLD/wifi-mobilemate @@ -0,0 +1,2 @@ +#!/bin/sh -x +doas ifconfig iwx0 nwid MobileMate wpakey GeekConnection23 diff --git a/.bin/OLD/winlist b/.bin/OLD/winlist new file mode 100755 index 0000000..44b5f25 --- /dev/null +++ b/.bin/OLD/winlist @@ -0,0 +1,13 @@ +#!/bin/sh + +HIDE=$(lswin -o; lswin -r) +for xid in $(lswin -a); +do + if printf "$HIDE" | grep -q $xid; then + continue; + fi + _name=$(wname $xid) + if [ ! -z "$_name" ]; then + echo "$xid | $(wname $xid)" + fi +done diff --git a/.bin/OLD/wmren b/.bin/OLD/wmren new file mode 100755 index 0000000..5a8793a --- /dev/null +++ b/.bin/OLD/wmren @@ -0,0 +1,2 @@ +#!/bin/sh +printf "\e]0;$@\a" diff --git a/.bin/OLD/wslauncher.sh b/.bin/OLD/wslauncher.sh new file mode 100755 index 0000000..22cbeb5 --- /dev/null +++ b/.bin/OLD/wslauncher.sh @@ -0,0 +1,17 @@ +#!/bin/sh + +# current WS if nothing is specified +WS=$_SWM_WS + +# specify target WS for some programs +# note: the actual WS is +1 so use 6 for something to spawn on WS 7. +case $1 in + firefox) WS=6; ;; + chrome) WS=1; ;; +esac + +# move to desktop +wmctrl -s $WS + +# spawn program +_SWM_WS=$WS $@ diff --git a/.bin/OLD/xbell b/.bin/OLD/xbell new file mode 100755 index 0000000..7ade471 --- /dev/null +++ b/.bin/OLD/xbell @@ -0,0 +1,2 @@ +#!/bin/sh +tput bel diff --git a/.bin/OLD/xcons b/.bin/OLD/xcons new file mode 100755 index 0000000..be920a9 --- /dev/null +++ b/.bin/OLD/xcons @@ -0,0 +1,26 @@ +#!/bin/sh + +# set the following quirk in .config/spectrwm/spectrwm.conf +# quirk[XConsole] = FLOAT + ANYWHERE + +# get XConsole window id +WID=$(wmctrl -x -l XConsole | fgrep '.XConsole' | cut -d" " -f1) + +if [ -z "$WID" ] +then + xconsole & +else + # check if window is iconfified or on another WS (or both) + if xwininfo -id $WID | fgrep -q IsUnMapped + then + # move window to current workspace + wmctrl -i -r $WID -t $(xprop -root _NET_CURRENT_DESKTOP | cut -d'=' -f2) + #wmctrl -i -r $WID -t $_SWM_WS + # remove hidden flag + wmctrl -i -r $WID -b remove,hidden + else + wmctrl -i -r $WID -t 11 + # window is visible => hide + wmctrl -i -r $WID -b add,hidden + fi +fi diff --git a/.bin/OLD/xfilesthumb b/.bin/OLD/xfilesthumb new file mode 100755 index 0000000..65afe46 --- /dev/null +++ b/.bin/OLD/xfilesthumb @@ -0,0 +1,47 @@ +#!/bin/sh + +BACKGROUND="#0A0A0A" +THUMBSIZE=64 +umask 077 + +case "$#" in +(2) + ;; +(*) + printf "usage: %s file\n" "$0" >&2 + exit 1 + ;; +esac + +case "$2" in +(*/*) + mkdir -p "${2%/*}" + ;; +(*) + ;; +esac + +case "${1##*.}" in +png|jpg|jpeg|gif|xpm|xbm|ppm) + convert "${1}[0]" -background "$BACKGROUND" -flatten \ + -define filename:literal=true -format ppm \ + -thumbnail "${THUMBSIZE}x${THUMBSIZE}" \ + "${2}" + ;; +webm|mp4|mkv|ogv) + ffmpegthumbnailer -c png -i "${1}" -o - -s "${THUMBSIZE}" \ + | convert - -define filename:literal=true -format ppm \ + "${2}" + ;; +svg) + rsvg-convert -h "${THUMBSIZE}" "${1}" \ + | convert - -format ppm "${2}" + ;; +pdf) + pdftoppm -f 1 -l 1 -scale-to "${THUMBSIZE}" -singlefile \ + "${1}" "${2%.ppm}" + ;; +*) + exit 1 + ;; +esac 2>/dev/null diff --git a/.bin/xpick_copy b/.bin/OLD/xpick_copy similarity index 100% rename from .bin/xpick_copy rename to .bin/OLD/xpick_copy diff --git a/.bin/OLD/yt-dlp b/.bin/OLD/yt-dlp new file mode 100755 index 0000000..112634b Binary files /dev/null and b/.bin/OLD/yt-dlp differ diff --git a/.bin/OLD/yubikey-gui b/.bin/OLD/yubikey-gui new file mode 100755 index 0000000..49d1cf1 --- /dev/null +++ b/.bin/OLD/yubikey-gui @@ -0,0 +1,9 @@ +#!/bin/sh +export QT_AUTO_SCREEN_SCALE_FACTOR=0 +export QT_SCALE_FACTOR=2 +export QT_QPA_PLATFORMTHEME=qt5ct +doas chmod 660 /dev/usb* +doas chmod 660 /dev/ugen* +yubikey-personalization-gui +#doas chmod 640 /dev/usb* + diff --git a/.bin/_config b/.bin/_config index ac3a993..33dc590 100644 --- a/.bin/_config +++ b/.bin/_config @@ -21,15 +21,15 @@ COLOR_SF="#EEEEEE" # TERMINALS # -STERM="st -f Terminus:pixelsize=18" -BTERM="st -f Terminus:pixelsize=26" -HTERM="st -f spleen:pixelsize=32" +STERM="st -f JetBrainsMonoNerdFont:pixelsize=18" +BTERM="st -f JetBrainsMonoNerdFont:pixelsize=26" +HTERM="st -f JetBrainsMonoNerdFont:pixelsize=32" # # DMENU # -DMENUOPTS="-fn Terminus:pixelsize=20 \ +DMENUOPTS="-fn JetBrainsMonoNerdFont:pixelsize=18 \ -nb $COLOR_NB \ -nf $COLOR_NF \ -sf $COLOR_SF \ diff --git a/.bin/apps/audiodevice b/.bin/apps/audiodevice new file mode 100755 index 0000000..4902cc9 --- /dev/null +++ b/.bin/apps/audiodevice @@ -0,0 +1,3 @@ +#!/bin/sh +. $HOME/.bin/_config +sndioctl -q server.device=$(setaudio | $DMENU_CMD -p "Device" -l 10 | cut -b3) diff --git a/.bin/apps/email b/.bin/apps/email new file mode 100755 index 0000000..ef40698 --- /dev/null +++ b/.bin/apps/email @@ -0,0 +1,27 @@ +#!/bin/sh + +# ALIASES=$(ksh -ic alias | grep ^mutt- | cut -d= -f1) +# +# MAILBOX="imaps://mail.codevoid.de" +# +# SEL=$(printf "$ALIASES" | $DMENU_CMD -p Mutt) +# +# [ -z "$SEL" ] || texec $SEL + +. $HOME/.bin/_config +# MAILBOXES=$(cd ~/.emails && find Mailboxes/*/ \ +# -mindepth 1 -maxdepth 1 -type d \ +# -not -path "*/tmp*" \ +# -not -path "*/cur*" \ +# -not -path "*/new*") + +MAILBOXES="$(print "t1 login sdk $(pass Internet/mail.codevoid.de | head -1)\nt1 list \"\" \"*\"\nt1 logout" \ + | openssl s_client -quiet -connect mail.codevoid.de:993 -crlf - 2>/dev/null \ + | grep "^\* LIST" | awk '{ print $NF }' | sort | dos2unix)" + + +HOST="imaps://mail.codevoid.de" + +SEL=$(echo "$MAILBOXES" | $DMENU_CMD -l 12 -p Mailbox) + +[ -z "$SEL" ] || texec "mutt -F $HOME/.mutt/rc-account-private -f $HOST/$SEL" diff --git a/.bin/apps/mastodon b/.bin/apps/mastodon new file mode 100755 index 0000000..c0b7a77 --- /dev/null +++ b/.bin/apps/mastodon @@ -0,0 +1,3 @@ +#!/bin/sh +. $HOME/.bin/_config +texec "ksh -ic tuta" diff --git a/.bin/apps/matrix b/.bin/apps/matrix new file mode 100755 index 0000000..6194377 --- /dev/null +++ b/.bin/apps/matrix @@ -0,0 +1,3 @@ +#!/bin/sh +. $HOME/.bin/_config +texec "gomuks" diff --git a/.bin/apps/media.ccc.de b/.bin/apps/media.ccc.de new file mode 100755 index 0000000..cb333dd --- /dev/null +++ b/.bin/apps/media.ccc.de @@ -0,0 +1,19 @@ +#!/bin/sh + +. ~/.bin/_config + +if [ ! -f ~/.cache/media.ccc.list ] +then + media-ccc-list-update +fi + +# S=$(cat ~/.cache/media.ccc.list | fgrep '/webm-hd/' | fzf -i -e -d '/' --with-nth=-4,-3,-1) +S=$(cat ~/.cache/media.ccc.list | fgrep '/webm-hd/' | $DMENU_CMD -p "Media CCC" -l 40) + +if [ ! -z "$S" ] +then + echo "Playing: $S" + mpv "$S" +fi + + diff --git a/.bin/apps/midjourney b/.bin/apps/midjourney new file mode 100755 index 0000000..bb6f005 --- /dev/null +++ b/.bin/apps/midjourney @@ -0,0 +1,3 @@ +#!/bin/sh +. $HOME/.bin/_config +chrome https://discord.com/channels/@me/1133396223613747240 & diff --git a/.bin/apps/mixer b/.bin/apps/mixer new file mode 100755 index 0000000..02a24ee --- /dev/null +++ b/.bin/apps/mixer @@ -0,0 +1,3 @@ +#!/bin/sh +. $HOME/.bin/_config +texec "cmixer" diff --git a/.bin/apps/ports b/.bin/apps/ports new file mode 100755 index 0000000..df75e2e --- /dev/null +++ b/.bin/apps/ports @@ -0,0 +1,24 @@ +#!/bin/sh + +# provides DMENU_CMD (dmenu + color parameter) +. $HOME/.bin/_config + +cd /usr/ports +DIR=$( ls -1d */* mystuff/*/* | egrep -v '^pobj|^distfiles|^log|^plist|^packages|CVS|Makefile|\.tgz$' | $DMENU_CMD -p "Port" -l 20); +if [ ! -z "$DIR" ]; then + cd /usr/ports/$DIR + DIR2=$(printf "%s\n\n%s\n%s\n%s\n %s\n" \ + "/usr/ports/$DIR" \ + "Package: $(make show=FULLPKGNAME)" \ + "Maintainer: $(make show=MAINTAINER)" \ + "Homepage: $(make show=HOMEPAGE)" \ + | $DMENU_CMD -p "Info" -l 20) + if [ ! -z "$DIR2" ]; then + case "$DIR2" in + Homepage*) $BROWSER "$(make show=HOMEPAGE)" & ;; + Package*) make show=FULLPKGNAME | xclip -r ;; + Maintainer*) make show=MAINTAINER | xclip -r ;; + *) cd "$DIR2"; port mark; sterm & ;; + esac + fi +fi diff --git a/.bin/apps/reddit b/.bin/apps/reddit new file mode 100755 index 0000000..5e400f7 --- /dev/null +++ b/.bin/apps/reddit @@ -0,0 +1,20 @@ +#!/bin/sh +. $HOME/.bin/_config + +SEL=$(printf "OpenBSD\nSpectrWM\nCommandline\nC_Programming\nADHD\nALL" \ + | $DMENU_CMD -p Subreddit) + +case $SEL in + "OpenBSD") + texec "tuir -s openbsd"; ;; + "SpectrWM") + texec "tuir -s spectrwm"; ;; + "ADHD") + texec "tuir -s adhd+adhs"; ;; + "Commandline") + texec "tuir -s commandline"; ;; + "C_Programming") + texec "tuir -s C_programming"; ;; + "All") + texec "tuir"; ;; +esac diff --git a/.bin/apps/telegram b/.bin/apps/telegram new file mode 100755 index 0000000..98d1970 --- /dev/null +++ b/.bin/apps/telegram @@ -0,0 +1,3 @@ +#!/bin/sh +. $HOME/.bin/_config +telegram-desktop & diff --git a/.bin/apps/youtube b/.bin/apps/youtube new file mode 100755 index 0000000..749fef0 --- /dev/null +++ b/.bin/apps/youtube @@ -0,0 +1,3 @@ +#!/bin/sh +. $HOME/.bin/_config +ytfzf -i ext --skip-thumb-download --rii -l diff --git a/.bin/bat-fullcharge b/.bin/bat-fullcharge new file mode 100755 index 0000000..1e519c6 --- /dev/null +++ b/.bin/bat-fullcharge @@ -0,0 +1,3 @@ +#!/bin/sh +doas sysctl hw.battery.chargestop=98 +doas sysctl hw.battery.chargestart=97 diff --git a/.bin/cam b/.bin/cam new file mode 100755 index 0000000..9e38cc0 --- /dev/null +++ b/.bin/cam @@ -0,0 +1,4 @@ +#!/bin/sh +#ffplay -f v4l2 -list_formats all -i /dev/video0 +_SWM_WS=-1 ffplay -loglevel quiet -f v4l2 -input_format mjpeg -video_size 424x240 -i /dev/video0 $@ & + diff --git a/.bin/cbar b/.bin/cbar index 1016558..668e892 100755 Binary files a/.bin/cbar and b/.bin/cbar differ diff --git a/.bin/chromed b/.bin/chromed new file mode 100755 index 0000000..f37245b --- /dev/null +++ b/.bin/chromed @@ -0,0 +1,61 @@ +#!/bin/sh +/usr/local/bin/ungoogled-chromium \ + --bwsi \ + --enable-easy-off-store-extension-install \ + --disable-3d-apis \ + --disable-angle-features=allowETCFormats \ + --disable-auto-reload \ + --disable-breakpad \ + --disable-client-side-phishing-detection \ + --disable-component-cloud-policy \ + --disable-component-update \ + --enable-chrome-browser-cloud-management \ + --enable-chrome-browser-cloud \ + --disable-crash-reporter \ + --disable-device-discovery-notifications \ + --disable-features=WebAssembly,AsmJsToWebAssembly,WebAssemblyStreaming \ + --disable-logging \ + --disable-login-animations \ + --disable-notifications \ + --disable-pinch \ + --disable-vulkan-surface \ + --disable-software-rasterizer \ + --disable-gpu-process-crash-limit \ + --disable-chrome-browser-cloud-management \ + --disable-field-trial-config \ + --disable-cookie-encryption \ + --disable-cloud-print-proxy \ + --dbus-stub \ + --cros-disks-fake \ + --disable-stack-profiler \ + --disable-touch-drag-drop \ + --disable-usb-keyboard-detect \ + --disable-wayland-ime \ + --disable-default-apps \ + --disable-dev-shm-usage \ + --disable-gaia-services \ + --disable-gpu-early-init \ + --disable-histogram-customizer \ + --disable-in-process-stack-traces \ + --no-service-autorun \ + --no-experiments \ + --use-gl=egl \ + --disable-wayland-ime \ + --enable-features=RunVideoCaptureServiceInBrowserProcess,WebUIDarkMode \ + --force-dark-mode \ + --hide-crash-restore-bubble \ + --js-flags=--noexpose-wasm \ + --noexpose-wasm \ + --no-default-browser-check \ + --no-proxy-server \ + --no-recovery-component \ + --password-store=basic \ + --structured-metrics-disabled \ + --wm-window-animations-disabled \ + --no-startup-window & + + #--use-gl=egl \ +# --disable-yuv-image-decoding \ +# --use-gl=desktop \ +# --high-dpi-support=1 \ +# --force-device-scale-factor=1.5 \ diff --git a/.bin/conf b/.bin/conf new file mode 100755 index 0000000..4618861 --- /dev/null +++ b/.bin/conf @@ -0,0 +1,2 @@ +#!/bin/sh +git --git-dir=${HOME}/.cfg/ --work-tree=${HOME} $@ diff --git a/.bin/developers b/.bin/developers new file mode 100755 index 0000000..cf004b6 --- /dev/null +++ b/.bin/developers @@ -0,0 +1,9 @@ +#!/bin/sh +ssh sdk@cvs.openbsd.org 'fgrep -v ksh- /etc/passwd' \ + | egrep 111\|122 \ + | grep -v gitsync \ + | cut -d: -f1,5 | tr -s ',' \ + | sed 's/,/, /g;s/,[, ]*$//g' \ + | column -s":" -t \ + | fzf -i -e + diff --git a/.bin/dexec_browser b/.bin/dexec_browser index 93c12db..522a4f8 100755 --- a/.bin/dexec_browser +++ b/.bin/dexec_browser @@ -84,7 +84,7 @@ Zalando" *.io|*.sh|*.pw|*.party) DEFAULT="OPEN (default)"; C="http://${C}"; ;; *.coffee|*.me|*.cloud) DEFAULT="OPEN (default)"; C="http://${C}"; ;; *.[a-zA-Z]*/*) DEFAULT="OPEN (default)"; C="http://${C}"; ;; - *) DEFAULT="Startpage Web Search (default)"; ;; + *) DEFAULT="DuckDuckGo Web Search (default)"; ;; esac local S="$(printf "%s\n%s" "${DEFAULT}" "${SE}" \ diff --git a/.bin/firefox b/.bin/firefox new file mode 100755 index 0000000..0a97226 --- /dev/null +++ b/.bin/firefox @@ -0,0 +1,5 @@ +#!/bin/sh +export XDG_CACHE_HOME=/tmp firefox +export MOZ_X11_EGL=1 + +/usr/local/bin/firefox "$@" diff --git a/.bin/format.sh b/.bin/format.sh new file mode 100755 index 0000000..5f6adeb --- /dev/null +++ b/.bin/format.sh @@ -0,0 +1,29 @@ +#!/bin/sh -e + +_dev="$1" + +[ -z $_dev ] && printf "usage: %s \n" "$(basename $0)" && exit 2 +[ $(id -u) -gt 0 ] && printf "you need superuser rights\n" && exit 2 + +dmesg | grep "$_dev" | grep -A1 scsibus | tail -n 2 + +printf "Format ${_dev} [y/N]? " +read +case $REPLY in + [yY]) ;; + *) exit 0; ;; +esac + +printf "Overwriting first MBs with zeros:" +dd of=/dev/r${_dev}c if=/dev/zero bs=1M count=1 > /dev/null 2>&1 +printf " ✅\n" + +printf "Creating FAT32 partition:" +echo "edit 0\n0B\n\n512\n*\nw\nq\n" | fdisk -e "$_dev" > /dev/null 2>&1 +printf " ✅\n" + +printf "Creating FAT32 file system (this may take a while)...\n" +newfs_msdos -F32 -b65536 "${_dev}i" +printf "Creating FAT32 file system: ✅\n" + +printf "Mount:\ndoas mkdir -p /mnt/%s && doas mount_msdos /dev/%si /mnt/%s\n" "$_dev" "$_dev" "$_dev" diff --git a/.bin/geolocate-me b/.bin/geolocate-me new file mode 100755 index 0000000..f57d441 --- /dev/null +++ b/.bin/geolocate-me @@ -0,0 +1,2 @@ +#!/bin/sh +curl -s ipinfo.io | jq -r diff --git a/.bin/hcloud b/.bin/hcloud new file mode 100755 index 0000000..125497f --- /dev/null +++ b/.bin/hcloud @@ -0,0 +1,4 @@ +#!/bin/sh +HCLOUD_TOKEN="$(pass Internet/api.hetzner.cloud | head -1)"; +HCLOUD_CONTEXT="sh"; +/usr/local/bin/hcloud "$@"; diff --git a/.bin/ksh-update-completions b/.bin/ksh-update-completions index 33a9207..1fc9557 100755 --- a/.bin/ksh-update-completions +++ b/.bin/ksh-update-completions @@ -1,33 +1,109 @@ #!/bin/ksh -rm -f "${HOME}/.ksh/complete.ksh" +FILE="$HOME/.ksh.complete" -add() { ( printf '%s %s' "$1" "$2" | tr '\n' ' '; printf '\n') >> "${HOME}/.ksh/complete.ksh"; } +rm -f "${FILE}" -if [ -d ~/.password-store ]; then +add() { + echo "$1 $2" | xargs >> "${FILE}"; +} + +# +# PASSWORD STORE +# +if [ -d ~/.password-store ] +then ARGS="$(cd ~/.password-store && ls -1d */* | sed 's/\.gpg$//g;s/ /\\ /g')" add "set -A complete_pass -- change edit insert show rm cp mv search find " "$ARGS" fi -if [ -f ${HOME}/.ssh/config ]; then - add "set -A complete_ssh -- " "$(awk '/^Host .*/ { print $2 }' ${HOME}/.ssh/config)" +# +# SSH HOSTS +# +if [ -f ~/.ssh/config ] +then + ARGS="$(awk '/^Host .*/ { print $2 }' ~/.ssh/config)" + add "set -A complete_ssh -- " "$ARGS" fi +# +# KILL +# add "set -A complete_kill_1 -- " "-9 -HUP -INFO -KILL -TERM" -add "set -A complete_ifconfig_1 -- " "$(ifconfig | grep ^[a-z] | cut -d: -f1)" -add "set -A complete_amused_1 -- " "add flush jump load monitor next pause play prev repeat restart show status stop toggle" -add "set -A complete_got_1 -- " "$(got -h 2>&1 | sed -n s/commands://p)" -add "set -A complete_make_1 -- " "$(sh ~/.ksh/complete.portvars)" +# +# IFCONFIG +# +add "set -A complete_ifconfig_1 -- " "$(ifconfig | grep ^[a-z] | cut -d: -f1)" + +# +# AMUSED +# +ARGS="add flush jump load monitor next pause play prev repeat restart show status stop toggle" +add "set -A complete_amused_1 -- " "$ARGS" + +# +# GOT +# +if [ -f /usr/local/bin/got ] +then + ARGS="$(got -h 2>&1 | sed -n s/commands://p)" + add "set -A complete_got_1 -- " "$ARGS" +fi + +ARGS="all all-dir-depends all-lib-depends-args build build-depends-list \ +build-dir-depends check-register check-register-all checkpatch \ +checksum clean clean-depends clean=all clean=build clean=bulk \ +clean=depends clean=dist clean=fake clean=flavors clean=install \ +clean=package clean=packages clean=plist clean=sub clean=test \ +clean=work configure distclean distpatch do-build do-configure \ +do-distpatch do-extract do-fake do-gen do-install do-patch \ +do-test dump-vars extract fake fake-wantlib-args fetch fetch-all \ +fix-permissions full-all-depends full-build-depends full-run-depends \ +full-test-depends gen generate-readmes install install-all \ +install-depends lib-depends-args lib-depends-check lib-depends-list \ +license-check lock makesum no-lib-depends-args no-wantlib-args package \ +patch peek-ftp pkglocatedb port-lib-depends-check port-wantlib-args \ +post-build post-configure post-distpatch post-extract post-fake \ +post-gen post-install post-patch post-test pre-build pre-configure \ +pre-distpatch pre-extract pre-fake pre-gen pre-install pre-patch \ +pre-test prepare print-build-depends print-package-args print-plist \ +print-plist-all print-plist-all-libs print-plist-all-with-depends \ +print-plist-contents print-plist-libs print-plist-libs-with-depends \ +print-plist-with-depends print-run-depends print-update-signature \ +rebuild regen reinstall repackage reprepare retest run-depends-args \ +run-depends-list run-dir-depends show-debug-info show-fake-size \ +show-indexed show-list show-prepare-results show-prepare-test-results \ +show-required-by show-run-depends show-size subpackage test test-depends \ +test-depends-list test-dir-depends unlock update update-patches \ +update-plist update-update-or-install update-update-or-install-all \ +verbose-show wantlib-args" +add "set -A complete_make_1 -- " "$ARGS" ARGS="reload restart stop start disable enable ls" add "set -A complete_rcctl_1 -- " "$ARGS" add "set -A complete_rcctl_2 -- " "$(rcctl ls all)" -add "set -A complete_got_1 -- " "$(got -h 2>&1 | sed -n s/commands://p)" -add "set -A complete_xdl_1 -- " "$(cd ~/x && ls -d *)" -add "set -A complete_ytdl_1 -- " "$(cd ~/Videos/YouTube && ls -d *)" +# +# VIDEO +# +if [ -d ~/ytdl ] +then + add "set -A complete_ytdl_1 -- " "$(cd ~/ytdl && ( ls -d *; ls -d */* ))" +fi -add "set -A complete_catgirl -- " "$(cd ~/.config/catgirl && ls *)" +# +# CATGIRL +# +if [ -d ~/.config/catgirl ] +then + add "set -A complete_catgirl -- " "$(cd ~/.config/catgirl && ls *)" +fi -add "set -A complete_man -- " "port-modules bsd.port.mk ports packages dpb make ffmpeg-complete mpv cabal-module cargo-module go-module gnome-module python-module qmake-module ruby-module cargo" +# +# MANPAGES +# +ARGS="port-modules bsd.port.mk ports packages dpb make ffmpeg-all \ +mpv cabal-module cargo-module go-module gnome-module python-module \ +qmake-module ruby-module cargo" +add "set -A complete_man -- " "$ARGS" diff --git a/.bin/mansearch b/.bin/mansearch new file mode 100755 index 0000000..18888ce --- /dev/null +++ b/.bin/mansearch @@ -0,0 +1,2 @@ +#!/bin/sh +man -k any=$1 diff --git a/.bin/media-ccc-list-update b/.bin/media-ccc-list-update new file mode 100755 index 0000000..29ef64f --- /dev/null +++ b/.bin/media-ccc-list-update @@ -0,0 +1,25 @@ +#!/bin/sh + +mv ~/.cache/media.ccc.list ~/.cache/media.ccc.list.1 + +curl -s \ + -H "CONTENT-TYPE: application/json" \ + https://media.ccc.de/public/conferences \ + | jq -rc '.[][].url' \ + | while read conference +do + echo "+ Scraping ${conference##*/}" + curl -s \ + -H "CONTENT-TYPE: application/json" \ + "$conference" \ + | jq -rc '.events[].url' \ + | while read event + do + echo "| Event: ${event##*/}" + curl -s \ + -H "CONTENT-TYPE: application/json" \ + "$event" \ + | jq -rc '.recordings[] | select(.high_quality == true and .folder == "webm-hd").recording_url' \ + >> ~/.cache/media.ccc.list + done +done diff --git a/.bin/media-ccc-play b/.bin/media-ccc-play new file mode 100755 index 0000000..0c717f5 --- /dev/null +++ b/.bin/media-ccc-play @@ -0,0 +1,18 @@ +#!/bin/sh + +. ~/.bin/_config + +if [ ! -f ~/.cache/media.ccc.list ] +then + media-ccc-list-update +fi + +S=$(cat ~/.cache/media.ccc.list | fgrep '/webm-hd/' | fzf -i -e -d '/' --with-nth=-4,-3,-1) + +if [ ! -z "$S" ] +then + echo "Playing: $S" + mpv "$S" +fi + + diff --git a/.bin/mount_msdos b/.bin/mount_msdos new file mode 100755 index 0000000..e64c366 --- /dev/null +++ b/.bin/mount_msdos @@ -0,0 +1,2 @@ +#/bin/sh +doas /sbin/mount_msdos -o nodev,nosuid,noatime -u 1000 -g 1000 diff --git a/.bin/mount_tank b/.bin/mount_tank new file mode 100755 index 0000000..dad2ba8 --- /dev/null +++ b/.bin/mount_tank @@ -0,0 +1,4 @@ +#!/bin/sh +awk '$3=="nfs"{print $2}' /etc/fstab \ + | xargs -n1 doas mount \ + | cut -d" " -f-3 diff --git a/.bin/mplay b/.bin/mplay new file mode 100755 index 0000000..080242a --- /dev/null +++ b/.bin/mplay @@ -0,0 +1,4 @@ +#!/bin/sh -xe +cd ~/ytdl +PLAY="$(fzf -e)" +[ ! -z "$PLAY" ] && mpv "$PLAY" diff --git a/.bin/mpv b/.bin/mpv new file mode 100755 index 0000000..00b3b11 --- /dev/null +++ b/.bin/mpv @@ -0,0 +1,16 @@ +#!/bin/sh + +RES=$(xrandr | grep "*+" | awk '{print $1}' | head -1) + +RESH=${RES%x*} +RESV=${RES#*x} + +GAP=$(( RESH / 12 )) + +H=$(( RESH - 2 * GAP )) +V=$(( RESV - 2 * GAP )) + +echo "Executing mpv --geometry=${H}x${V}" +_SWM_WS=-1 /usr/local/bin/mpv --x11-name=scratchpad --geometry=${H}x${V} "$@" + + diff --git a/.bin/port-clean b/.bin/port-clean new file mode 100755 index 0000000..dadca6f --- /dev/null +++ b/.bin/port-clean @@ -0,0 +1,6 @@ +#!/bin/sh -x + +cd /usr/ports +doas rm -rf pobj/* plist logs packages bulk update distfiles/* +mkdir -p plist logs packages bulk update +doas make fix-permissions diff --git a/.bin/port-commit b/.bin/port-commit new file mode 100755 index 0000000..c2a964e --- /dev/null +++ b/.bin/port-commit @@ -0,0 +1,2 @@ +#!/bin/sh -x +doas -u sdk cvs -d $CVSROOT $@ diff --git a/.bin/port-diff b/.bin/port-diff new file mode 100755 index 0000000..b6d0323 --- /dev/null +++ b/.bin/port-diff @@ -0,0 +1,11 @@ +#!/bin/sh -x + +pwd | fgrep -q '/usr/ports/' || return 1 +set -A N $(make show="PKGNAME EPOCH REVISION") +PN="${N[0]}${N[1]:+v${N[1]}}${N[2]:+p${N[2]}}" +PD=$(pwd | cut -d"/" -f4,5) + +cd /usr/ports +cvs -d $CVSROOT diff -uNp "${PD}" > ~sdk/diffs/${PN}.diff +echo ~/diffs/${PN}.diff + diff --git a/.bin/port-sweep b/.bin/port-sweep new file mode 100755 index 0000000..958b686 --- /dev/null +++ b/.bin/port-sweep @@ -0,0 +1,8 @@ +#!/bin/sh + +find . \( -name "*.orig" \ + -o -name "*.rej" \ + -o -name ".#*" \ + -o -empty \ + \) -delete + diff --git a/.bin/pw b/.bin/pw new file mode 100755 index 0000000..b853602 --- /dev/null +++ b/.bin/pw @@ -0,0 +1,6 @@ +#!/bin/sh +pwgen \ + -1 \ + -y \ + --remove-chars=\~\`\"\'{}\(\)\[\]\*.\;\|,\<\> \ + 22 diff --git a/.bin/remindview b/.bin/remindview new file mode 100755 index 0000000..ef07b4b --- /dev/null +++ b/.bin/remindview @@ -0,0 +1,15 @@ +#!/bin/sh + +remind -n ~sdk/.reminders \ + | sort -n \ + | head -n 10 \ + | while read -r line +do + echo "Input: $line" + echo "$line" \ + | awk '$1 == /^[0-9][0-9]\/[0-9][0-9]\/[0-9][0-9]/ + { print "Date: "$1 } + $2 == /^[0-9][0-9]:[0-9][0-9][ap]m/ + { print "Time: "$2 } + { $1=""; $2=""; print "Text: "$0 }' +done diff --git a/.bin/scratchpad b/.bin/scratchpad new file mode 100755 index 0000000..29a74ed --- /dev/null +++ b/.bin/scratchpad @@ -0,0 +1,52 @@ +#!/bin/sh + +# read resolution from xrandr: "1920x1080 60.03*+" +RES=$(xrandr | grep "*+" | awk '{print $1}' | head -1) + +# parse xrandr output +RESH=${RES%x*} +RESV=${RES#*x} + +# calculate pixel gap that should surround the window +GAP=$(( RESH / 12 )) + +# Calculate the horzontal/vertical dimensions of the window +H=$(( RESH - 2 * GAP )) +V=$(( RESV - 2 * GAP )) + +# set the quirk in .config/spectrwm/spectrwm.conf +# quirk[scratchpad] = FLOAT + ANYWHERE + FOCUSPREV + +# get scratchpad window id +WID=$(wmctrl -x -l scratchpad | fgrep '.scratchpad' | cut -d" " -f1) + +if [ -z "$WID" ] +then + # start terminal (sterm is st.suckless.org) + sterm -c scratchpad -g 159x42+$GAP+$GAP & + # XXX we cannot resize with wmctrl here, because the window is not + # mapped yet. Adding a sleep here and resize then is visually + # unpleasant. Therefore st is started with hardcoded dimensions + # and resized when hidden. +else + # check if window is iconified or on another WS (or both) + if xwininfo -id $WID | fgrep -q IsUnMapped + then + # move window to current workspace + [ -z $_SWM_WS ] \ + && wmctrl -i -r $WID -t $(xprop -root _NET_CURRENT_DESKTOP | cut -d'=' -f2) \ + || wmctrl -i -r $WID -t $_SWM_WS + # remove hidden flag + wmctrl -i -r $WID -b remove,hidden + # activate (give focus) + wmctrl -i -a $WID + else + # window is visible => hide + wmctrl -i -r $WID -b add,hidden + # correct size while hidden + wmctrl -i -r $WID -e 0,$GAP,$GAP,$H,$V + # move it beyond the WS limit to completely hide it from the bar + # XXX could also be skip_pager / skip_taskbar? + wmctrl -i -r $WID -t 11 + fi +fi diff --git a/.bin/sshot-farbfeld b/.bin/sshot-farbfeld new file mode 100755 index 0000000..9d4f49e --- /dev/null +++ b/.bin/sshot-farbfeld @@ -0,0 +1,13 @@ +#!/bin/sh + +[ -z $1 ] && exit 2 + +. ${HOME}/.bin/_config + +# TAKE SCREENSHOT +flameshot gui -p "/tmp/$1.png" > /dev/null 2>&1 +test -f "/tmp/$1.png" || exit 1 + +png2ff < "/tmp/$1.png" | bzip2 > "$1.ff.bz2" + +echo "@$1.ff.bz2" diff --git a/.bin/backup b/.bin/tarsnap-backup similarity index 100% rename from .bin/backup rename to .bin/tarsnap-backup diff --git a/.bin/timer b/.bin/timer new file mode 100755 index 0000000..0feb993 --- /dev/null +++ b/.bin/timer @@ -0,0 +1,11 @@ +#!/bin/sh + +case $1 in + stop) rm -f /tmp/timer.txt \ + && echo stopped + ;; + *) [ -f /tmp/timer.txt ] \ + && echo $(( $(date +%s) - $( /tmp/timer.txt && echo started ) + ;; +esac diff --git a/.bin/twitch-play b/.bin/twitch-play new file mode 100755 index 0000000..a778533 --- /dev/null +++ b/.bin/twitch-play @@ -0,0 +1,2 @@ +#!/bin/sh +mpv https://www.twitch.tv/c0dev0id diff --git a/.bin/twitch-stream b/.bin/twitch-stream new file mode 100755 index 0000000..502ade3 --- /dev/null +++ b/.bin/twitch-stream @@ -0,0 +1,5 @@ +#!/bin/sh +API_KEY=$(pass Internet/Twitch | head -1) +RES=$(xrandr | grep "*+" | awk '{print $1}') +FAUX_OPTS="-d snd/default -m -vmic 5.0 -vmon 0.2 -r $RES -f 20 -b 4000" +fauxstream $FAUX_OPTS rtmp://live-ams.twitch.tv/app/$API_KEY diff --git a/.bin/umount_tank b/.bin/umount_tank new file mode 100755 index 0000000..12e00cb --- /dev/null +++ b/.bin/umount_tank @@ -0,0 +1,4 @@ +#!/bin/sh +awk '$3=="nfs"{print $2}' /etc/fstab \ + | xargs -n1 doas umount \ + | cut -d" " -f-3 diff --git a/.bin/update-abook.sh b/.bin/update-abook.sh new file mode 100755 index 0000000..13b085a --- /dev/null +++ b/.bin/update-abook.sh @@ -0,0 +1,4 @@ +#!/bin/sh +cat /home/sdk/.isync/contacts/*.vcf \ + | abook --convert --informat vcard --outformat abook \ + > /home/sdk/.abook/addressbook diff --git a/.bin/update-calendar b/.bin/update-calendar new file mode 100755 index 0000000..23e786f --- /dev/null +++ b/.bin/update-calendar @@ -0,0 +1,26 @@ +#!/bin/sh -xe + +# snapshot +cd /home/sdk/.reminders +git add * +git commit -m "Update $(date +"%Y-%m-%d %H:%M:%S")" || true + +# copy uugrn calendard to dalek +scp -q vorstand@vorstand.uugrn.org:private/Kalender/uugrn.rem \ + sdk@home.codevoid.de:.reminders/uugrn.rem + +# copy all calendars from dalek to local +scp -q sdk@home.codevoid.de:.reminders/\*.rem \ + /home/sdk/.reminders/ + +# download vcal/vcard from icloud / radical +vdirsyncer sync + +# create import.rem from ical events (XXX fix this mess) +find ~/.isync -name "*.ics" -exec cat {} + \ + | ical2rem --no-todos \ + | fgrep -v "REM MSG" \ + | sed 's,\\n, ,g' \ + | tr -d '\' \ + | sed 's/ / /g' \ + > /home/sdk/.reminders/import.rem diff --git a/.bin/upload b/.bin/upload new file mode 100755 index 0000000..d392e13 --- /dev/null +++ b/.bin/upload @@ -0,0 +1,25 @@ +#!/bin/sh -e + +file="$1" + +[ -z $file ] \ + && file="$(find $PWD $HOME $HOME/Downloads -maxdepth 2 -type f \ + | fgrep -v "/." \ + | sort -u \ + | fzf -e -x -i)" + +[ -z $file ] \ + && exit 0 + +scp "$file" \ + sdk@home.codevoid.de:make-web/src/paste/ + +ssh sdk@home.codevoid.de \ + "cd ~/make-web && make install" + +echo "https://ptrace.org/$(basename "$file")" \ + | sed 's/ /%20/g' \ + | xclip -f -r + +echo + diff --git a/.bin/vimb b/.bin/vimb new file mode 100755 index 0000000..ee978ce --- /dev/null +++ b/.bin/vimb @@ -0,0 +1,4 @@ +#!/bin/sh +unset _SWM_WM +unset LD_PRELOAD +/usr/local/bin/vimb --no-maximize $@ diff --git a/.bin/yt-dlp b/.bin/yt-dlp new file mode 100755 index 0000000..112634b Binary files /dev/null and b/.bin/yt-dlp differ diff --git a/.bin/ytdl b/.bin/ytdl new file mode 100755 index 0000000..7167403 --- /dev/null +++ b/.bin/ytdl @@ -0,0 +1,12 @@ +#!/bin/sh -xe +if [ -z $2 ] +then + echo "First argument should be a category." + exit 2 +fi + +mkdir -p "$HOME/ytdl/$1/" +ksh-update-completions & +cd "$HOME/ytdl/$1/" +yt-dlp "$2" + diff --git a/.config/luakit/rc.lua b/.config/luakit/rc.lua index 77f5a6f..4c400ff 100644 --- a/.config/luakit/rc.lua +++ b/.config/luakit/rc.lua @@ -8,13 +8,13 @@ local unique_instance = require "unique_instance" unique_instance.open_links_in_new_window = true -- Set the number of web processes to use. A value of 0 means 'no limit'. -luakit.process_limit = 8 +luakit.process_limit = 1 -- Load library of useful functions for luakit local lousy = require "lousy" -- Cookie acceptance policy -soup.accept_policy = "always" -- always, never, no_third_party +soup.accept_policy = "no_third_party" -- always, never, no_third_party -- Cookie storage location soup.cookies_storage = luakit.data_dir .. "/cookies.db" @@ -36,10 +36,10 @@ window.add_signal("build", function (w) local widgets, l, r = require "lousy.widget", w.sbar.l, w.sbar.r -- Left-aligned status bar widgets - l.layout:pack(widgets.zoom()) l.layout:pack(widgets.uri()) l.layout:pack(widgets.hist()) l.layout:pack(widgets.progress()) + l.layout:pack(widgets.zoom()) -- Right-aligned status bar widgets r.layout:pack(widgets.buf()) @@ -58,28 +58,28 @@ local settings = require "settings" local settings_chrome = require "settings_chrome" settings.window.home_page = "luakit://newtab" -settings.window.scroll_step = 20 +-- settings.window.scroll_step = 20 settings.window.zoom_step = 0.2 settings.webview.zoom_level = 100 settings.window.close_with_last_tab = true -- search engines settings.window.search_engines.ddg = "https://duckduckgo.com/?q=%s" -settings.window.search_engines.g = "https://google.com/?q=%s" -settings.window.search_engines.mg = "https://metager.org/?q=%s" -settings.window.search_engines.gh = "https://github.com/search?q=%s" -settings.window.search_engines.default = settings.window.search_engines.ddg +settings.window.search_engines.g = "https://google.com/?q=%s" +settings.window.search_engines.mg = "https://metager.org/?q=%s" +settings.window.search_engines.gh = "https://github.com/search?q=%s" +settings.window.search_engines.default = settings.window.search_engines.ddg ---------------------------------- -- Optional user script loading -- ---------------------------------- -- Add adblock -local adblock = require "adblock" -local adblock_chrome = require "adblock_chrome" +-- local adblock = require "adblock" +-- local adblock_chrome = require "adblock_chrome" -- Enable Developer Tools -local webinspector = require "webinspector" +-- local webinspector = require "webinspector" -- Add uzbl-like form filling -- local formfiller = require "formfiller" @@ -88,7 +88,7 @@ local webinspector = require "webinspector" -- }) -- Add proxy support & manager -local proxy = require "proxy" +-- local proxy = require "proxy" -- Add quickmarks support & manager -- local quickmarks = require "quickmarks" @@ -100,13 +100,13 @@ local proxy = require "proxy" local gopher = require "gopher" -- Delete website data -local clear_data = require "clear_data" +-- local clear_data = require "clear_data" -- Add command to list closed tabs & bind to open closed tabs local undoclose = require "undoclose" -- Add command to list tab history items -local tabhistory = require "tabhistory" +-- local tabhistory = require "tabhistory" -- Add greasemonkey-like javascript userscript support --- local userscripts = require "userscripts" @@ -121,7 +121,7 @@ local downloads_chrome = require "downloads_chrome" downloads.default_dir = os.getenv("HOME") .. "/Downloads" -- Add automatic PDF downloading and opening --- local viewpdf = require "viewpdf" +local viewpdf = require "viewpdf" -- Add vimperator-like link hinting & following local follow = require "follow" @@ -133,7 +133,7 @@ local cmdhist = require "cmdhist" local search = require "search" -- Add ordering of new tabs -local taborder = require "taborder" +-- local taborder = require "taborder" -- Save web history local history = require "history" @@ -156,7 +156,7 @@ local completion = require "completion" -- `,ts` to toggle scripts, `,tp` to toggle plugins, `,tr` to reset. -- If you use this module, don't use any site-specific `enable_scripts` or -- `enable_plugins` settings, as these will conflict. -require "noscript" +-- require "noscript" local follow_selected = require "follow_selected" local go_input = require "go_input" @@ -172,22 +172,22 @@ local error_page = require "error_page" local styles = require "styles" follow.stylesheet = follow.stylesheet .. [===[ #luakit_select_overlay .hint_label { - background-color: #f8f8f8; - border: 1px solid #f00; - padding: 1px; - color: #181818; - font-size: 18px; - opacity: 1; + background-color: #f8f8f8 !important; + border: 1px solid #f00 !important; + padding: 1px !important; + color: #181818 !important; + font-size: 16px !important; + opacity: 0.7 !important; } ]===] -- Hide scrollbars on all pages -local hide_scrollbars = require "hide_scrollbars" +-- local hide_scrollbars = require "hide_scrollbars" -- local vertical_tabs = require "vertical_tabs" -- Add a stylesheet when showing images -local image_css = require "image_css" +-- local image_css = require "image_css" -- Add a new tab page local newtab_chrome = require "newtab_chrome" @@ -199,7 +199,7 @@ newtab_chrome.new_tab_src = [==[ ]==] -- Add tab favicons mod --- local tab_favicons = require "tab_favicons" +local tab_favicons = require "tab_favicons" -- local tab = require("lousy.widget.tab") -- tab.label_format = "" @@ -207,7 +207,7 @@ newtab_chrome.new_tab_src = [==[ -- tablist.min_width = 100 -- Add :view-source command -local view_source = require "view_source" +-- local view_source = require "view_source" -- Use "asdfqwerzxcv" for generating labels local select = require "select" @@ -261,31 +261,31 @@ follow.pattern_maker = follow.pattern_styles.match_label -- end) -- social media blocker -local webview = require "webview" -webview.add_signal('init', function (view) - view:add_signal('navigation-request', function(v, uri) - local blocklist_pattern = { - "facebook.com", - ".fb.com", - ".fbcdn.com", - ".fbsbx.com", - ".fbcdn.net", - ".tfbnw.net", - "whatsapp.com", - "online-metrix.net", - ".fb.me", - "facebook-web-clients.appspot.com", - "fbcdn-profile-a.akamaihd.net" - } - for key,value in ipairs(blocklist_pattern) - do - if v.uri:match(value) then - print("Navigation request to " .. v.uri .. " blocked.") - return false - end - end - end) -end) +-- local webview = require "webview" +-- webview.add_signal('init', function (view) +-- view:add_signal('navigation-request', function(v, uri) +-- local blocklist_pattern = { +-- "facebook.com", +-- ".fb.com", +-- ".fbcdn.com", +-- ".fbsbx.com", +-- ".fbcdn.net", +-- ".tfbnw.net", +-- "whatsapp.com", +-- "online-metrix.net", +-- ".fb.me", +-- "facebook-web-clients.appspot.com", +-- "fbcdn-profile-a.akamaihd.net" +-- } +-- for key,value in ipairs(blocklist_pattern) +-- do +-- if v.uri:match(value) then +-- print("Navigation request to " .. v.uri .. " blocked.") +-- return false +-- end +-- end +-- end) +-- end) ----------------------------- -- End user script loading -- diff --git a/.config/spectrwm/spectrwm.conf b/.config/spectrwm/spectrwm.conf index 25d5591..77a4988 100644 --- a/.config/spectrwm/spectrwm.conf +++ b/.config/spectrwm/spectrwm.conf @@ -39,7 +39,7 @@ bar_font_color = rgb:99/99/99 bar_font_color_free = rgb:99/99/99 bar_font_color_selected = rgb:ff/ff/ff -bar_font = Terminess Nerd Font:pixelsize=18 +bar_font = JetBrainsMonoNerdFont:pixelsize=18 bar_action = cbar bar_action_expand = 0 bar_at_bottom = 0 @@ -146,24 +146,15 @@ bind[bterm] = MOD+Shift+Return program[hterm] = hterm bind[hterm] = MOD+Control+Return -program[mcorner] = move-to-corner -bind[mcorner] = MOD+Shift+X - program[mixer] = texec cmixer bind[mixer] = MOD+Shift+M -program[vim] = texec "vim -c ':History'" -bind[vim] = MOD+Shift+o - program[vpn] = dexec_vpn bind[vpn] = MOD+V program[exec] = dexec bind[exec] = MOD+D -program[cexec] = dexec_command -bind[cexec] = MOD+C - program[texec] = dexec_term bind[texec] = MOD+Shift+D @@ -173,10 +164,7 @@ bind[ssh] = MOD+S program[ssh] = dexec_ssh bind[ssh] = MOD+S -program[edit] = dexec_edit -bind[edit] = MOD+numbersign - -program[scratchpad] = sp +program[scratchpad] = scratchpad bind[scratchpad] = MOD+minus program[xconsole] = xcons @@ -198,13 +186,10 @@ bind[pim] = MOD+P program[screenshot_wind] = sshot bind[screenshot_wind] = Print -program[xpick] = xpick_copy -bind[xpick] = MOD+Print - program[lock] = /usr/bin/false -autorun = ws[10]:xconsole -autorun = ws[10]:sp +autorun = ws[10]:xcons +autorun = ws[10]:scratchpad # +-------------------------------------------------- # | KEYBOARD MAPPING diff --git a/.ksh/aliases.ksh b/.ksh/aliases.ksh index 34c5a38..7aaf6ec 100644 --- a/.ksh/aliases.ksh +++ b/.ksh/aliases.ksh @@ -17,6 +17,9 @@ alias exrc="vim ~/.exrc" alias trans-en="trans -l de -s en -t de --no-ansi" alias trans-de="trans -l en -s de -t en --no-ansi" +alias g="ugrep -In --break --sort" +alias gf="g -F" + # taskwarrior alias t=task alias tall="task rc.context:" diff --git a/.ksh/complete.portvars b/.ksh/complete.portvars new file mode 100644 index 0000000..bf2bec8 --- /dev/null +++ b/.ksh/complete.portvars @@ -0,0 +1,367 @@ +#!/bin/sh +echo {build,run,all,test}-dir-depends +echo full-{build,run,all,test}-depends +echo {build,lib,test,run}-depends-list +echo print-{build,run}-depends +echo {pre,do,post}-{build,configure,distpatch,extract,fake,gen,install,patch,test} +echo all-lib-depends-args +echo build +echo all +echo check-register +echo check-register-all +echo checkpatch +echo checksum +echo clean +echo clean={work,bulk,build,depends,dist,fake,flavors,install,package,plist,test,sub,packages,all} +echo clean-depends +echo configure +echo distclean +echo distpatch +echo dump-vars +echo extract +echo fake +echo fake-wantlib-args +echo fetch +echo fetch-all +echo fix-permissions +echo gen +echo generate-readmes +echo install +echo install-{all,depends} +echo lib-depends-args +echo lib-depends-check +echo license-check +echo lock +echo makesum +echo no-lib-depends-args +echo no-wantlib-args +echo package +echo patch +echo peek-ftp +echo pkglocatedb +echo port-lib-depends-check +echo port-wantlib-args +echo prepare +echo print-package-args +echo print-update-signature +echo print-plist +echo print-plist-{all,all-with-depends,contents,libs,all-libs,libs-with-depends,with-depends} +echo rebuild +echo regen +echo reinstall +echo repackage +echo run-depends-args +echo reprepare +echo retest +echo show-{debug-info,fake-size,indexed,list,prepare-results,prepare-test-results,required-by,run-depends,size} +echo subpackage +echo test +echo test-depends +echo unlock +echo update-{patches,update-or-install,update-or-install-all,plist} +echo update +echo verbose-show +echo wantlib-args +# echo show=ALL_DISTFILES +# echo show=ALL_FAKE_FLAGS +# echo show=ALL_PATCHFILES +# echo show=ALL_SUPDISTFILES +# echo show=ALL_TEST_ENV +# echo show=ALL_TEST_FLAGS +# echo show=ALL_TARGET +# echo show=APM_ARCHS +# echo show=ARCH +# echo show=AUTOCONF +# echo show=AUTOCONF_DIR +# echo show=AUTOCONF_ENV +# echo show=AUTOCONF_VERSION +# echo show=AUTOHEADER +# echo show=AUTOMAKE_VERSION +# echo show=AUTORECONF +# echo show=BASE_PKGPATH +# echo show=BASELOCALSTATEDIR +# echo show=BASESYSCONFDIR +# echo show=BATCH +# echo show=BE_ARCHS +# echo show=BUILD_DEPENDS +# echo show=BUILD_ONCE +# echo show=BUILD_PKGPATH +# echo show=BUILD_PACKAGES +# echo show=BROKEN +# echo show=BUILD_UNLINKED +# echo show=BUILD_USER +# echo show=BROKEN-arch +# echo show=BSD_INSTALL_{PROGRAM,SCRIPT,DATA,MAN}{,_DIR} +# echo show=BULK +# echo show=BULK_COOKIES_DIR +# echo show=BULK_DO +# echo show=BULK_FLAGS +# echo show=BULK_TARGETS +# echo show=BZIP2 +# echo show=CATEGORIES +# echo show=CCACHE_DIR +# echo show=CCACHE_ENV +# echo show=CDIAGFLAGS +# echo show=CFLAGS +# echo show=CFLAGS_{base-clang,ports-gcc} +# echo show=CHECK_LIB_DEPENDS +# echo show=CHECK_LIB_DEPENDS_ARGS +# echo show=CHECKSUMFILES +# echo show=CHECKSUM_FILE +# echo show=CHECKSUM_PACKAGES +# echo show=CHOSEN_COMPILER +# echo show=CLEANDEPENDS +# echo show=COMMENT +# echo show=COMMENT-foo +# echo show=COMMENT-vanilla +# echo show=COMMENT-foo-vanilla +# echo show=COMES_WITH +# echo show=COMPILER +# echo show=COMPILER_LANGS +# echo show=COMPILER_LINKS +# echo show=COMPILER_WRAPPER +# echo show=CONFIG_SITE_LIST +# echo show=CLANG_ARCHS +# echo show=GCC3_ARCHS +# echo show=GCC4_ARCHS +# echo show=CONFIGURE_ARGS +# echo show=CONFIGURE_ENV +# echo show=CONFIGURE_SCRIPT +# echo show=CONFIGURE_STYLE +# echo show=COPTS +# echo show=CXXDIAGFLAGS +# echo show=CXXFLAGS +# echo show=CXXFLAGS_{base-clang,ports-gcc} +# echo show=CXXOPTS +# echo show=DEBUG_CONFIGURE_ARGS +# echo show=DEBUG_PACKAGES +# echo show=DEBUGINFO_ARCHS +# echo show=DESCR +# echo show=DESTDIR +# echo show=DESTDIRNAME +# echo show=DIST_TUPLE +# echo show=DISTDIR +# echo show=DISTFILES* +# echo show=DISTNAME +# echo show=DISTORIG +# echo show=DIST_SUBDIR +# echo show=DPB +# echo show=DPB_LOCKNAME +# echo show=DPB_PROPERTIES +# echo show=DUMMY_PACKAGE +# echo show=ECHO_MSG +# echo show=ECHO_REORDER +# echo show=EDIT_PATCHES +# echo show=EPOCH +# echo show=ERRORS +# echo show=EXTRACT_CASES +# echo show=EXTRACT_ONLY +# echo show=EXTRACT_SUFX +# echo show=EXTRACT_SUFX.name +# echo show=EXTRACT_FILES +# echo show=FAKE_FLAGS +# echo show=FAKE_SETUP +# echo show=FAKE_TARGET +# echo show=FAKEOBJDIR +# echo show=FETCH_CMD +# echo show=FETCH_MANUALLY +# echo show=FETCH_PACKAGES +# echo show=FILESDIR +# echo show=FETCH_USER +# echo show=FIX_CLEANUP_PERMISSIONS +# echo show=FIX_CRLF_FILES +# echo show=FIX_EXTRACT_PERMISSIONS +# echo show=FLAVOR +# echo show=FLAVORS +# echo show=FLAVOR_EXT +# echo show=FORCE_UPDATE +# echo show=FULLDISTDIR +# echo show=FULLPKGNAME +# echo show=FULLPKGPATH +# echo show=GH_ACCOUNT +# echo show=GH_COMMIT +# echo show=GH_DISTFILE +# echo show=GH_PROJECT +# echo show=GH_TAGNAME +# echo show=GMAKE +# echo show=HOMEPAGE +# echo show=IGNORE +# echo show=IGNORE_IS_FATAL +# echo show=IGNORE_SILENT +# echo show=INSTALL_DEBUG_PACKAGES +# echo show=INSTALL_{PROGRAM,SCRIPT,DATA,MAN}{,_DIR} +# echo show=INSTALL_TARGET +# echo show=INTERACTIVE +# echo show=IS_INTERACTIVE +# echo show=LE_ARCHS +# echo show=LIB_DEPENDS +# echo show=lib_depends_args +# echo show=LIBCXX +# echo show=LIBTOOL +# echo show=LIBTOOL_FLAGS +# echo show=LLD_EMUL +# echo show=LLVM_ARCHS +# echo show=LOCALBASE +# echo show=LOCALSTATEDIR +# echo show=LOCKDIR +# echo show=LOCK_CMD +# echo show=LOCK_VERBOSE +# echo show=LP64_ARCHS +# echo show=MAINTAINER +# echo show=MAKE_ENV +# echo show=MAKE_FLAGS +# echo show=MAKE_FILE +# echo show=MAKE_JOBS +# echo show=MAKE_PROGRAM +# echo show=MAKEFILE_LIST +# echo show=MAKESUMFILES +# echo show=MESSAGE +# echo show=MISSING_FILES +# echo show=MODGNU_CONFIG_GUESS_DIRS +# echo show=MODPERL_ADJ_FILES +# echo show=MODPERL_BIN_ADJ +# echo show=MODPERL_BUILD_TARGET +# echo show=MODPERL_INSTALL_TARGET +# echo show=MODPERL_TEST_TARGET +# echo show=MODPERL_REGEN_PPPORT +# echo show=MODULES +# echo show=MULTI_PACKAGES +# echo show=NO_ARCH +# echo show=NOT_FOR_ARCHS +# echo show=NO_BUILD +# echo show=NO_CCACHE +# echo show=NO_CHECKSUM +# echo show=NO_DEPENDS +# echo show=NO_IGNORE +# echo show=NO_SCCACHE +# echo show=NO_TEST +# echo show=ONLY_FOR_ARCHS +# echo show=OSREV +# echo show=PACKAGE_REPOSITORY +# echo show=PARALLEL_MAKE_FLAGS +# echo show=PARALLEL_MAKE_JOBS +# echo show=PATCH +# echo show=PATCHORIG +# echo show=PATCH_CASES +# echo show=PATCHDIR +# echo show=PATCHFILES* +# echo show=PATCH_ARGS +# echo show=PATCH_CHECK_ONLY +# echo show=PATCH_DIST_ARGS +# echo show=PATCH_DIST_STRIP +# echo show=PATCH_LIST +# echo show=PATCH_STRIP +# echo show=PERMIT_DISTFILES +# echo show=PERMIT_PACKAGE +# echo show=PKG_ADD +# echo show=PKG_ARCH +# echo show=PKG_ARGS +# echo show=PKG_CREATE +# echo show=PKG_CREATE_NO_CHECKS +# echo show=PKG_DBDIR +# echo show=PKG_DELETE +# echo show=PKG_INFO +# echo show=PKG_TMPDIR +# echo show=PORTHOME +# echo show=PORTPATH +# echo show=PORTSDIR +# echo show=PORTSDIR_PATH +# echo show=PORTS_PRIVSEP +# echo show=PKGDIR +# echo show=PKGFILE +# echo show=PKGFILES +# echo show=PKGNAME +# echo show=PKGNAMES +# echo show=PKGNAME-foo +# echo show=PKGPATH +# echo show=PKGPATHS +# echo show=PKGSPEC +# echo show=PKGSTEM +# echo show=PLIST +# echo show=PLIST_DB +# echo show=PLIST_REPOSITORY +# echo show=PORTROACH +# echo show=PREFIX +# echo show=PREPARE_CHECK_ONLY +# echo show=PROGRESS_METER +# echo show=PROPERTIES +# echo show=PSEUDO_FLAVOR +# echo show=PSEUDO_FLAVORS +# echo show=RANDOMIZE_SUBDIRS +# echo show=RCDIR +# echo show=REFETCH +# echo show=REGISTER_PLIST_OPTS +# echo show=REORDER_DEPENDENCIES +# echo show=REPORT_PROBLEM +# echo show=REPORT_PROBLEM_LOGFILE +# echo show=REVISION +# echo show=ROACH_SITES +# echo show=ROACH_URL +# echo show=RUN_DEPENDS +# echo show=SCCACHE_DIR +# echo show=SCCACHE_ENV +# echo show=SEPARATE_BUILD +# echo show=SETENV +# echo show=SHARED_LIBS +# echo show=SITE_BACKUP +# echo show=SITES +# echo show=SKIPDIR +# echo show=STATIC_PLIST +# echo show=STARTAFTER +# echo show=STARTDIR +# echo show=SUBPACKAGE +# echo show=SUBST_CMD +# echo show=SUBST_CMD-sub +# echo show=SUBST_DATA +# echo show=SUBST_MAN +# echo show=SUBST_PROGRAM +# echo show=SUBST_VARS +# echo show=SUDO +# echo show=SUPDISTFILES +# echo show=SYSCONFDIR +# echo show=TAR +# echo show=TARGETS +# echo show=TEMPLATE_DISTFILES.name +# echo show=TEMPLATE_HOMEPAGE.name +# echo show=TEST_DEPENDS +# echo show=TEST_ENV +# echo show=TEST_FLAGS +# echo show=TEST_IS_INTERACTIVE +# echo show=TEST_LOG +# echo show=TEST_LOGFILE +# echo show=TEST_TARGET +# echo show=TRUEPREFIX +# echo show=TRY_BROKEN +# echo show=UNLOCK_CMD +# echo show=UNLINKED +# echo show=UNMESSAGE +# echo show=UNZIP +# echo show=UPDATE_COOKIES_DIR +# echo show=UPDATE_PLIST_ARGS +# echo show=UPDATE_PLIST_OPTS +# echo show=USE_CCACHE +# echo show=USE_GMAKE +# echo show=USE_GROFF +# echo show=USE_LIBTOOL +# echo show=USE_LLD +# echo show=USE_MFS +# echo show=USE_NOBTCFI +# echo show=USE_NOEXECONLY +# echo show=USE_SCCACHE +# echo show=USE_WXNEEDED +# echo show=USE_X11 +# echo show=VARBASE +# echo show=WANTLIB +# echo show=WARNINGS +# echo show=WRKBUILD +# echo show=WRKCONF +# echo show=WRKDIR +# echo show=WRKDIST +# echo show=WRKSRC +# echo show=WRKINST +# echo show=WRKOBJDIR +# echo show=WRKOBJDIR_MFS +# echo show=X11BASE +# echo show=XAUTHORITY +# echo show=XMKMF +# echo show=YACC diff --git a/.ksh/prompt-ksh.ksh b/.ksh/prompt-ksh.ksh index 2ec4013..c81c6aa 100644 --- a/.ksh/prompt-ksh.ksh +++ b/.ksh/prompt-ksh.ksh @@ -7,4 +7,15 @@ C1="\[$(tput setaf 241)\]" # gray C2="\[$(tput setaf 37)\]" # green C0="\[$(tput op)\]" # reset x=$(print \\001) # hack from ksh(1) -PS1="$x\${C1}[\${C2}\h\${C1}](\${C2}\${?}\${C1})(\${C2}\W\${C1})\\$ \${C0}$x" + +# accent + +if [ $(id -u) -eq 0 ] +then + C2="\[$(tput setaf 160)\]" # red +else + #C2="\[$(tput setaf 209)\]" # orange + C2="\[$(tput setaf 37)\]" # green +fi + +PS1="$x\${C1}[\${C2}\h\${C1}](\${C2}\${?}\${C1})(\${C2}\w\${C1})\\$ \${C0}$x" diff --git a/.kshrc b/.kshrc index 900289b..c905085 100644 --- a/.kshrc +++ b/.kshrc @@ -6,7 +6,6 @@ ### SEARCH PATHS PATH=~/.bin\ -:~/.local/bin\ :/bin\ :/sbin\ :/usr/bin\ @@ -14,10 +13,7 @@ PATH=~/.bin\ :/usr/local/bin\ :/usr/local/sbin\ :/usr/X11R6/bin\ -:/usr/games\ :/usr/ports/infrastructure/bin -JAVA_HOME=/usr/local/jdk-11/bin -PATH=${PATH}:${JAVA_HOME} export PATH ### LANGUAGE @@ -25,7 +21,7 @@ LANG=en_US.UTF-8 LC_MESSAGES=C LC_NUMERIC=C LC_TIME=de_DE.UTF-8 -export LANG LC_ALL LC_MESSAGES LC_NUMERIC LC_TIME +export LANG LC_MESSAGES LC_NUMERIC LC_TIME ### SOFTWARE PREFERENCES EDITOR="vim" @@ -44,7 +40,7 @@ export PRINTER [[ $- != *i* ]] && return ######################################################################## -# MANDATORY ENVIRONMENT +# INTERACTIVE ENVIRONMENT ######################################################################## ### HISTORY @@ -58,7 +54,6 @@ LESS="-giJmR--tilde" LESSHISTFILE="$HOME/.less-history" export LESS LESSHISTFILE - ######################################################################## # SHELL SETTINGS ######################################################################## @@ -69,52 +64,188 @@ set -o emacs set bell-style none ######################################################################## -# MODULE LOADER +# LOAD LOCAL ADDITIONS ######################################################################## -load() { [ -f ~/.ksh/$1 ] && . ~/.ksh/$1; } - -load environment.ksh -load functions.ksh -load aliases.ksh - -if hostname | fgrep -q codevoid -then - load email.ksh - load porttools.ksh - load remind.ksh - load amused.ksh - load gnupg.ksh -fi - -load prompt-${SHELL##*/}.ksh -load ytdl.ksh -load fzf.ksh -load dotfiles.ksh -load localstuff.ksh -load complete.ksh - +[ -f ~/.ksh.local ] && . ~/.ksh.local +[ -f ~/.ksh.complete ] && . ~/.ksh.complete ######################################################################## -# ALIASES (MISC) +# PROMPT ######################################################################## -# mount -alias mount_msdos="doas \mount_msdos -o nodev,nosuid,noatime -u 1000 -g 1000" -mount_tank() { awk '$3=="nfs"{print $2}' /etc/fstab | xargs -n1 doas mount -v | cut -d" " -f-3; } -umount_tank() { awk '$3=="nfs"{print $2}' /etc/fstab | xargs -n1 doas umount -v | cut -d" " -f-3; } +C1="\[$(tput setaf 241)\]" # gray +C2="\[$(tput setaf 37)\]" # green +C0="\[$(tput op)\]" # reset +x=$(echo -e \\001) # hack from ksh(1) -pw() { pwgen -1 -y --remove-chars=\~\`\"\'{}\(\)\[\]\*.\;\|,\<\> 22; } +[ $(id -u) -eq 0 ] \ + && C2="\[$(tput setaf 196)\]" # gray + +PS1="${C1}[${C2}\h${C1}](${C2}\${?}${C1})(${C2}\w${C1})\$ ${C0}" + +# PS1="\\$ " ######################################################################## -# TWITCH FROM CLI +# ALIASES ######################################################################## -alias twitch_play="mpv https://www.twitch.tv/c0dev0id" -twitch_stream() { - local API_KEY=$(pass Internet/Twitch | head -1) - local RES=$(xrandr | grep "*+" | awk '{print $1}') - local FAUX_OPTS="-d snd/default -m -vmic 5.0 -vmon 0.2 -r $RES -f 20 -b 4000" - fauxstream $FAUX_OPTS rtmp://live-ams.twitch.tv/app/$API_KEY +# config files +alias kshrc="vim ~/.kshrc" +alias muttrc="vim ~/.mutt/rc-common" +alias vimrc="vim ~/.vim/vimrc" +alias luakitrc="vim ~/.config/luakit/rc.lua" +alias spectrwmrc="vim ~/.config/spectrwm/spectrwm.conf" +alias vifmrc="vim ~/.config/vifm/vifmrc" + +# task warrior +alias t=task +alias ta="task add" +alias tm="task mod" + +# social media +alias tuta="tut -u 'sh@bsd.network uugrn@chaos.social'" + +# servers +alias x="ssh -t sdk@home.codevoid.de tmux -u at \|\| tmux" + +alias myps="ps -fU sdk" + +alias portroach="portroach-cli -m codevoid" + +alias ugrep="\ugrep -nI --exclude=tags --exclude=.tags --exclude='cscope.*'" + +######################################################################## +# AMUSED +######################################################################## +alias amused-next="_amused_cmd next" +alias amused-prev="_amused_cmd prev" +alias amused-play="_amused_cmd play" +alias amused-stop="_amused_cmd stop" +alias amused+="_amused_cmd seek +15" +alias amused-="_amused_cmd seek -15" +alias amused-jump="_amused_jump" +alias amused-shuffle="amused show | sort -R | amused load" +alias amused-sort="amused show | sort -h | amused load" + +_amused_cmd() { + . ~/.bin/_config + amused "${@}" 2>&1 > /dev/null + STATUS="$(amused status | head -1 | cut -d'/' -f5-)" + NOTIFY_CMD "$STATUS" + echo "$@: $STATUS" } +_amused_jump() { + S="$(echo "$(amused show | cut -d'/' -f5-)" | sort -h | fzf -i -e)" + [ ! -z "$S" ] \ + && _amused_cmd jump "$S" +} + +######################################################################## +# EMAIL HANDLING +######################################################################## + +# mailboxes +MUTT_HOST="imaps://mail.codevoid.de" + +# account aliases +alias mutt-acc-gmx="\mutt -F $HOME/.mutt/rc-account-gmx" +alias mutt-acc-priv="\mutt -F $HOME/.mutt/rc-account-private" +alias mutt-acc-work="\mutt -F $HOME/.mutt/rc-account-work" +alias mutt-acc-offl="\mutt -F $HOME/.mutt/rc-account-offline" +alias mutt-acc-mborg="\mutt -F $HOME/.mutt/rc-account-mborg" +alias mutt-acc-uugrn="\mutt -F $HOME/.mutt/rc-account-uugrn" + +# default +alias mutt="mutt-acc-priv" +alias muttopen="\mutt -F ~/.mutt/rc-common -f" + +# select mailbox +mutt-textmail() { mutt-acc-priv -f $MUTT_HOST/Mailboxes/textmail.me/$1; } +mutt-codevoid() { mutt-acc-priv -f $MUTT_HOST/Mailboxes/codevoid.de/sh+$1; } + +# shortcuts +alias mutt-all="mutt -f $MUTT_HOST/Virtual/ALL" +alias mutt-last-day="mutt -f $MUTT_HOST/Virtual/LAST_DAY" +alias mutt-last-week="mutt -f $MUTT_HOST/Virtual/LAST_WEEK" +alias mutt-last-month="mutt -f $MUTT_HOST/Virtual/LAST_MONTH" +alias mutt-last-year="mutt -f $MUTT_HOST/Virtual/LAST_YEAR" +alias mutt-openbsd-all="mutt -f $MUTT_HOST/Virtual/OpenBSD" +alias mutt-amazon="mutt-textmail amazon" +alias mutt-ccc-intern="mutt-textmail ccc-intern" +alias mutt-lieferando="mutt-textmail lieferando" +alias mutt-mutt-users="mutt-codevoid mutt-users" +alias mutt-openbsd-bugs="mutt-codevoid openbsd-bugs" +alias mutt-openbsd-hackers="mutt-codevoid openbsd-hackers" +alias mutt-openbsd-misc="mutt-codevoid openbsd-misc" +alias mutt-openbsd-ports-bugs="mutt-codevoid openbsd-ports-bugs" +alias mutt-openbsd-ports-cvs="mutt-codevoid openbsd-ports-cvs" +alias mutt-openbsd-ports="mutt-codevoid openbsd-ports" +alias mutt-openbsd-sparc="mutt-codevoid openbsd-sparc" +alias mutt-openbsd-src-cvs="mutt-codevoid openbsd-src-cvs" +alias mutt-openbsd-tech="mutt-codevoid openbsd-tech" +alias mutt-openbsd-x11="mutt-codevoid openbsd-x11" +alias mutt-paypal="mutt-textmail paypal" +alias mutt-uugrn="mutt-codevoid uugrn" +alias mutt-vorstand="mutt-codevoid vorstand" + + +######################################################################## +# PORT TOOLS +######################################################################## +CVSROOT="sdk@cvs.openbsd.org:/cvs" +export CVSROOT + +cvs_update_all() {( + set -ex + cd /usr/src && doas -u sdk cvs -d $CVSROOT -z1 -q up -Pd -A + cd /usr/xenocara && doas -u sdk cvs -d $CVSROOT -z1 -q up -Pd -A + cd /usr/ports && doas -u sdk cvs -d $CVSROOT -z1 -q up -Pd -A + cd /usr/www && doas -u sdk cvs -d $CVSROOT -z1 -q up -Pd -A +)} + +po() { cd $(make show=WRKSRC); } +pj() { + [ -z $1 ] && return 1 + cd /usr/ports + PATTERN="pobj|plist|CVS|locks|packages|distfiles|infrastructure" + LIST=$( ls -d1 \ + *$1* \ + */*$1* \ + mystuff/*$1* \ + mystuff/*/*$1* \ + openbsd-wip/*$1* \ + openbsd-wip/*/*$1* \ + 2>/dev/null \ + | grep -Ev "$PATTERN" \ + | sort -u + ) + + [ $(echo "$LIST" | wc -l) -gt 1 ] \ + && cd $(echo "$LIST" | fzf -e -i) \ + || cd $LIST +} +######################################################################## +# REMIND +######################################################################## + +alias rem="remind -@1,1,1 -c+cu4 -wt ~sdk/.reminders.rem" +alias remy="remind -@1,1,1 -c+cu52 -wt ~sdk/.reminders.rem | less" +#alias rem="remind -@1,1,1 -c+3 -g ~sdk/.reminders.rem" +#alias remy="remind -cu12 -wt ~sdk/.reminders | less -r" +alias rems="remind -n ~sdk/.reminders | sort -n | head -10" +alias remc="remindcal ~sdk/.reminders" +alias rem-personal="rem-edit personal" +alias rem-birthdays="rem-edit birthdays" +alias rem-uugrn="rem-edit uugrn" + +rem-edit() { + vim sftp://sdk@home.codevoid.de/.reminders/$1.rem + scp -q sdk@home.codevoid.de:.reminders/$1.rem ~sdk/.reminders/$1.rem + [ "$1" == "uugrn" ] \ + && echo "Running ~sdk/.bin/make_calendar.sh" \ + && ssh -q sdk@vorstand.uugrn.org sh \ + ~sdk/.bin/make_calendar.sh \ + || true +} diff --git a/.mutt/mailcap b/.mutt/mailcap index 983395a..d5b3490 100644 --- a/.mutt/mailcap +++ b/.mutt/mailcap @@ -24,6 +24,7 @@ # html text/html; ~/.mutt/scripts/call-browser.sh %s; test=test -n "$DISPLAY"; needsterminal; text/html; w3m -I %{charset} -T %t -cols "$COLUMNS" -s -no-graph -o display_link=1 -o display_link_number=1; copiousoutput; +message/*; cat %s; needsterminal; # documents application/pdf; ~/.mutt/scripts/call.sh mupdf %s; nametemplate=%s.pdf; diff --git a/.mutt/rc-common b/.mutt/rc-common index cd226f7..916123d 100644 --- a/.mutt/rc-common +++ b/.mutt/rc-common @@ -307,7 +307,7 @@ set ssl_verify_host = no set crypt_use_gpgme = yes # use the new gpgme method (disabling cumbersome gpg commands below) set crypt_replyencrypt = yes # encrypt, if original mail was encrypted set crypt_replysign = yes # sign, if original mail was signed -set crypt_verify_sig = yes # verify sig, if sig is available +set crypt_verify_sig = yes # verify sig, if sig is available set crypt_autosign = no # sign mails per default set crypt_use_pka = yes # http://www.g10code.de/docs/pka-intro.de.pdf set crypt_autosmime = no @@ -315,6 +315,7 @@ set crypt_protected_headers_save = yes set crypt_protected_headers_write = yes set crypt_protected_headers_subject = "..." set crypt_opportunistic_encrypt = yes # encrypt when key can be found +set crypt_opportunistic_encrypt_strong_keys = yes # autoselect key with trust full+ set autocrypt = no set pgp_use_gpg_agent = yes diff --git a/.vim/pack/plugins/start/vim-autotag/README.markdown b/.vim/pack/plugins/start/vim-autotag/README.markdown deleted file mode 100644 index 586e69a..0000000 --- a/.vim/pack/plugins/start/vim-autotag/README.markdown +++ /dev/null @@ -1,96 +0,0 @@ -autotag.vim -============ - -If you use ctags to make tags files of your source, it's nice to be able to re-run ctags on a source file when you save it. - -However, using `ctags -a` will only change existing entries in a tags file or add new ones. It doesn't delete entries that no longer exist. Should you delete an entity from your source file that's represented by an entry in a tags file, that entry will remain after calling `ctags -a`. - -This python function will do two things: - -1) It will search for a tags file starting in the directory where your source file resides and moving up a directory at a time until it either finds one or runs out of directories to try. - -2) Should it find a tags file, it will then delete all entries in said tags file referencing the source file you've just saved and then execute `ctags -a` on that source file using the relative path to the source file from the tags file. - -This way, every time you save a file, your tags file will be seamlessly updated. - -Installation ------------- - -Currently I suggest you use Vundle and install as a normal Bundle - -From the Vim command-line - - :BundleInstall 'craigemery/vim-autotag' - -And add to your ~/.vimrc - - Bundle 'craigemery/vim-autotag' - -Or you can manually install - cd - git clone git://github.com/craigemery/vim-autotag.git - cd ~/.vim/ - mkdir -p plugin - cp ~/vim-autotag.git/plugin/* plugin/ - -### Install as a Pathogen bundle -``` -git clone git://github.com/craigemery/vim-autotag.git ~/.vim/bundle/vim-autotag -``` - -Getting round other ctags limitations -------------------------------------- -ctags is very file name suffix driven. When the file has no suffix, ctags can fail to detect the file type. -The easiest way to replicate this is when using a #! shebang. I've seen "#!/usr/bin/env python3" in a -shebang not get detected by ctags. -But Vim is better at this. So Vim's filetype buffer setting can help. -So when the buffer being written has no suffix to the file name then the Vim filetype value will be used instead. -So far I've only implemented "python" as one that is given to ctags --language-force= as is. -Other filetypes could be mapped. There's a dict in the AutTag class. -To not map a filetype to a forced language kind, add the vim file type to the comma "," separated -list in autotagExcludeFiletypes. - -Configuration -------------- -Autotag can be configured using the following global variables: - -| Name | Purpose | -| ---- | ------- | -| `g:autotagExcludeSuffixes` | suffixes to not ctags on | -| `g:autotagExcludeFiletypes` | filetypes to not try & force a language choice on ctags | -| `g:autotagVerbosityLevel` | logging verbosity (as in Python logging module) | -| `g:autotagCtagsCmd` | name of ctags command | -| `g:autotagTagsFile` | name of tags file to look for | -| `g:autotagDisabled` | Disable autotag (enable by setting to any non-blank value) | -| `g:autotagStopAt` | stop looking for a tags file (and make one) at this directory (defaults to $HOME) | -| `g:autotagStartMethod` | Now AutoTag uses Python multiprocessing, the start method is an internal aspect that Python uses. - -These can be overridden with buffer specific ones. b: instead of g: -Example: -``` -let g:autotagTagsFile=".tags" -``` - -macOS, Python 3.8 and 'spawn' ------------------------------ -With the release of Python 3.8, the default start method for multiprocessing on macOS has become 'spawn' -At the time of writing there are issues with 'spawn' and I advise making AutoTag ask Python to use 'fork' -i.e. before loading the plugin: -``` -let g:autotagStartMethod='fork' -``` - -Self-Promotion --------------- - -Like autotag.vim? Follow the repository on -[GitHub](https://github.com/craigemery/vim-autotag) and vote for it on -[vim.org](http://www.vim.org/scripts/script.php?script_id=1343). And if -you're feeling especially charitable, follow [craigemery] on -[GitHub](https://github.com/craigemery). - -License -------- - -Copyright (c) Craig Emery. Distributed under the same terms as Vim itself. -See `:help license`. diff --git a/.vim/pack/plugins/start/vim-autotag/autoload/autotag.py b/.vim/pack/plugins/start/vim-autotag/autoload/autotag.py deleted file mode 100644 index b07e2e9..0000000 --- a/.vim/pack/plugins/start/vim-autotag/autoload/autotag.py +++ /dev/null @@ -1,319 +0,0 @@ -""" -(c) Craig Emery 2017-2022 -AutoTag.py -""" - -from __future__ import print_function -import sys -import os -import fileinput -import logging -from collections import defaultdict -import subprocess -from traceback import format_exc -import multiprocessing as mp -from glob import glob -import vim # pylint: disable=import-error - -__all__ = ["autotag"] - -# global vim config variables used (all are g:autotag): -# name purpose -# ExcludeSuffixes suffixes to not ctags on -# VerbosityLevel logging verbosity (as in Python logging module) -# CtagsCmd name of ctags command -# TagsFile name of tags file to look for -# Disabled Disable autotag (enable by setting to any non-blank value) -# StopAt stop looking for a tags file (and make one) at this directory (defaults to $HOME) -GLOBALS_DEFAULTS = dict(ExcludeSuffixes="tml.xml.text.txt", - VerbosityLevel=logging.WARNING, - CtagsCmd="ctags", - TagsFile="tags", - TagsDir="", - Disabled=0, - StopAt=0, - StartMethod="") - - -def do_cmd(cmd, cwd): - """ Abstract subprocess """ - with subprocess.Popen(cmd, cwd=cwd, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, - stderr=subprocess.PIPE, universal_newlines=True) as proc: - stdout = proc.communicate()[0] - return stdout.split("\n") - - -def vim_global(name, kind=str): - """ Get global variable from vim, cast it appropriately """ - ret = GLOBALS_DEFAULTS.get(name, None) - try: - vname = "autotag" + name - v_buffer = "b:" + vname - exists_buffer = (vim.eval(f"exists('{v_buffer}')") == "1") - v_global = "g:" + vname - exists_global = (vim.eval(f"exists('{v_global}')") == "1") - if exists_buffer: - ret = vim.eval(v_buffer) - elif exists_global: - ret = vim.eval(v_global) - else: - if isinstance(ret, int): - vim.command(f"let {v_global}={ret}") - else: - vim.command(f"let {v_global}=\"{ret}\"") - finally: - if kind == bool: - ret = (ret in [1, "1", "true", "yes"]) - elif kind == int: - try: - val = int(ret) - except TypeError: - val = ret - except ValueError: - val = ret - ret = val - elif kind == str: - ret = str(ret) - return ret - - -def init_multiprocessing(): - """ Init multiprocessing, set_executable() & get the context we'll use """ - wanted_start_method = vim_global("StartMethod") or None - used_start_method = mp.get_start_method() - if wanted_start_method in mp.get_all_start_methods(): - used_start_method = wanted_start_method - else: - wanted_start_method = None - # here wanted_start_method is either a valid method or None - # used_start_method is what the module has as the default or our overriden value - ret = mp.get_context(wanted_start_method) # wanted_start_method might be None - try: - mp.set_executable - except AttributeError: - return ret - if used_start_method == 'spawn': - suff = os.path.splitext(sys.executable)[1] - pat1 = f"python*{suff}" - pat2 = os.path.join("bin", pat1) - exes = glob(os.path.join(sys.exec_prefix, pat1)) + glob(os.path.join(sys.exec_prefix, pat2)) - if exes: - win = [exe for exe in exes if exe.endswith(f"w{suff}")] - if win: - # In Windows pythonw.exe is best - ret.set_executable(win[0]) - else: - # This isn't great, for now pick the first one - ret.set_executable(exes[0]) - return ret - - -CTX = init_multiprocessing() - - -class VimAppendHandler(logging.Handler): - """ Logger handler that finds a buffer and appends the log message as a new line """ - def __init__(self, name): - logging.Handler.__init__(self) - self.__name = name - self.__formatter = logging.Formatter() - - def __find_buffer(self): - """ Look for the named buffer """ - for buff in vim.buffers: - if buff and buff.name and buff.name.endswith(self.__name): - yield buff - - def emit(self, record): - """ Emit the logging message """ - for buff in self.__find_buffer(): - buff.append(self.__formatter.format(record)) - - -def set_logger_verbosity(): - """ Set the verbosity of the logger """ - level = vim_global("VerbosityLevel", kind=int) - LOGGER.setLevel(level) - - -def make_and_add_handler(logger, name): - """ Make the handler and add it to the standard logger """ - ret = VimAppendHandler(name) - logger.addHandler(ret) - return ret - - -try: - LOGGER -except NameError: - DEBUG_NAME = "autotag_debug" - LOGGER = logging.getLogger(DEBUG_NAME) - HANDLER = make_and_add_handler(LOGGER, DEBUG_NAME) - set_logger_verbosity() - - -class AutoTag(): # pylint: disable=too-many-instance-attributes - """ Class that does auto ctags updating """ - LOG = LOGGER - AUTOFILETYPES = ["python"] - FILETYPES = {} - - def __init__(self): - self.locks = {} - self.tags = defaultdict(list) - self.excludesuffix = ["." + s for s in vim_global("ExcludeSuffixes").split(".")] - self.excludefiletype = vim_global("ExcludeFiletypes").split(",") - set_logger_verbosity() - self.sep_used_by_ctags = '/' - self.ctags_cmd = vim_global("CtagsCmd") - self.tags_file = str(vim_global("TagsFile")) - self.tags_dir = str(vim_global("TagsDir")) - self.parents = os.pardir * (len(os.path.split(self.tags_dir)) - 1) - self.count = 0 - self.stop_at = vim_global("StopAt") - - def find_tag_file(self, source): - """ Find the tag file that belongs to the source file """ - AutoTag.LOG.info('source = "%s"', source) - (drive, fname) = os.path.splitdrive(source) - ret = None - while ret is None: - fname = os.path.dirname(fname) - AutoTag.LOG.info('drive = "%s", file = "%s"', drive, fname) - tags_dir = os.path.join(drive, fname) - tags_file = os.path.join(tags_dir, self.tags_dir, self.tags_file) - AutoTag.LOG.info('testing tags_file "%s"', tags_file) - if os.path.isfile(tags_file): - stinf = os.stat(tags_file) - if stinf: - size = getattr(stinf, 'st_size', None) - if size is None: - AutoTag.LOG.warning("Could not stat tags file %s", tags_file) - ret = "" - ret = (fname, tags_file) - elif tags_dir and tags_dir == self.stop_at: - AutoTag.LOG.info("Reached %s. Making one %s", self.stop_at, tags_file) - open(tags_file, 'wb').close() - ret = (fname, tags_file) - ret = "" - elif not fname or fname == os.sep or fname == "//" or fname == "\\\\": - AutoTag.LOG.info('bail (file = "%s")', fname) - ret = "" - return ret or None - - def add_source(self, source, filetype): - """ Make a note of the source file, ignoring some etc """ - if not source: - AutoTag.LOG.warning('No source') - return - if os.path.basename(source) == self.tags_file: - AutoTag.LOG.info("Ignoring tags file %s", self.tags_file) - return - suff = os.path.splitext(source)[1] - if suff: - AutoTag.LOG.info("Source %s has suffix %s, so filetype doesn't count!", source, suff) - filetype = None - else: - AutoTag.LOG.info("Source %s has no suffix, so filetype counts!", source) - - if suff in self.excludesuffix: - AutoTag.LOG.info("Ignoring excluded suffix %s for file %s", suff, source) - return - if filetype in self.excludefiletype: - AutoTag.LOG.info("Ignoring excluded filetype %s for file %s", filetype, source) - return - found = self.find_tag_file(source) - if found: - (tags_dir, tags_file) = found - relative_source = os.path.splitdrive(source)[1][len(tags_dir):] - if relative_source[0] == os.sep: - relative_source = relative_source[1:] - if os.sep != self.sep_used_by_ctags: - relative_source = relative_source.replace(os.sep, self.sep_used_by_ctags) - key = (tags_dir, tags_file, filetype) - self.tags[key].append(relative_source) - if key not in self.locks: - self.locks[key] = CTX.Lock() - - @staticmethod - def good_tag(line, excluded): - """ Filter method for stripping tags """ - if line[0] == '!': - return True - fields = line.split('\t') - AutoTag.LOG.log(1, "read tags line:%s", str(fields)) - if len(fields) > 3 and fields[1] not in excluded: - return True - return False - - def strip_tags(self, tags_file, sources): - """ Strip all tags for a given source file """ - AutoTag.LOG.info("Stripping tags for %s from tags file %s", ",".join(sources), tags_file) - backup = ".SAFE" - try: - with fileinput.FileInput(files=tags_file, inplace=True, backup=backup) as source: - for line in source: - line = line.strip() - if self.good_tag(line, sources): - print(line) - finally: - try: - os.unlink(tags_file + backup) - except IOError: - pass - - def _vim_ft_to_ctags_ft(self, name): - """ convert vim filetype strings to ctags strings """ - if name in AutoTag.AUTOFILETYPES: - return name - return self.FILETYPES.get(name, None) - - def update_tags_file(self, key, sources): - """ Strip all tags for the source file, then re-run ctags in append mode """ - (tags_dir, tags_file, filetype) = key - lock = self.locks[key] - if self.tags_dir: - sources = [os.path.join(self.parents + s) for s in sources] - cmd = [self.ctags_cmd] - if self.tags_file: - cmd += ["-f", self.tags_file] - if filetype: - ctags_filetype = self._vim_ft_to_ctags_ft(filetype) - if ctags_filetype: - cmd += [f"--language-force={ctags_filetype}"] - cmd += ["-a"] - - def is_file(src): - """ inner """ - return os.path.isfile(os.path.join(tags_dir, self.tags_dir, src)) - - srcs = list(filter(is_file, sources)) - if not srcs: - return - - cmd += [f'"{s}"' for s in srcs] - cmd = " ".join(cmd) - with lock: - self.strip_tags(tags_file, sources) - AutoTag.LOG.log(1, "%s: %s", tags_dir, cmd) - for line in do_cmd(cmd, self.tags_dir or tags_dir): - AutoTag.LOG.log(10, line) - - def rebuild_tag_files(self): - """ rebuild the tags file thread worker """ - for (key, sources) in self.tags.items(): - AutoTag.LOG.info('Process(%s, %s)', key, ",".join(sources)) - proc = CTX.Process(target=self.update_tags_file, args=(key, sources)) - proc.daemon = True - proc.start() - - -def autotag(): - """ Do the work """ - try: - if not vim_global("Disabled", bool): - runner = AutoTag() - runner.add_source(vim.eval("expand(\"%:p\")"), vim.eval("&ft")) - runner.rebuild_tag_files() - except Exception: # pylint: disable=broad-except - logging.warning(format_exc()) diff --git a/.vim/pack/plugins/start/vim-autotag/autoload/autotag.vim b/.vim/pack/plugins/start/vim-autotag/autoload/autotag.vim deleted file mode 100644 index 31f5c39..0000000 --- a/.vim/pack/plugins/start/vim-autotag/autoload/autotag.vim +++ /dev/null @@ -1,16 +0,0 @@ -if ! has("python3") - finish -endif -python3 import sys, os, vim -python3 sys.path.insert(0, os.path.dirname(vim.eval('expand("")'))) -python3 import autotag - -function! autotag#Run() - if exists("b:netrw_method") - return - endif - python3 autotag.autotag() - if exists(":TlistUpdate") - TlistUpdate - endif -endfunction diff --git a/.vim/pack/plugins/start/vim-autotag/plugin/autotag.vim b/.vim/pack/plugins/start/vim-autotag/plugin/autotag.vim deleted file mode 100755 index d09fff7..0000000 --- a/.vim/pack/plugins/start/vim-autotag/plugin/autotag.vim +++ /dev/null @@ -1,39 +0,0 @@ -" -" (c) Craig Emery 2017-2022 -" -" Increment the number below for a dynamic #include guard -let s:autotag_vim_version=1 - -if exists("g:autotag_vim_version_sourced") - if s:autotag_vim_version == g:autotag_vim_version_sourced - finish - endif -endif - -let g:autotag_vim_version_sourced=s:autotag_vim_version - -" This file supplies automatic tag regeneration when saving files -" There's a problem with ctags when run with -a (append) -" ctags doesn't remove entries for the supplied source file that no longer exist -" so this script (implemented in Python) finds a tags file for the file vim has -" just saved, removes all entries for that source file and *then* runs ctags -a - -if !has("python3") - finish -endif " !has("python3") - -function! AutoTagDebug() - new - file autotag_debug - setlocal buftype=nowrite - setlocal bufhidden=delete - setlocal noswapfile - normal  -endfunction - -augroup autotag - au! - autocmd BufWritePost,FileWritePost * call autotag#Run () -augroup END - -" vim:shiftwidth=3:ts=3 diff --git a/.vim/pack/plugins/start/vim-easy-align/autoload/easy_align.vim b/.vim/pack/plugins/start/vim-easy-align/autoload/easy_align.vim deleted file mode 100644 index 795ea31..0000000 --- a/.vim/pack/plugins/start/vim-easy-align/autoload/easy_align.vim +++ /dev/null @@ -1,1148 +0,0 @@ -" Copyright (c) 2014 Junegunn Choi -" -" MIT License -" -" Permission is hereby granted, free of charge, to any person obtaining -" a copy of this software and associated documentation files (the -" "Software"), to deal in the Software without restriction, including -" without limitation the rights to use, copy, modify, merge, publish, -" distribute, sublicense, and/or sell copies of the Software, and to -" permit persons to whom the Software is furnished to do so, subject to -" the following conditions: -" -" The above copyright notice and this permission notice shall be -" included in all copies or substantial portions of the Software. -" -" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -" EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -" NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -" LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -" OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -" WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -if exists("g:loaded_easy_align") - finish -endif -let g:loaded_easy_align = 1 - -let s:cpo_save = &cpo -set cpo&vim - -let s:easy_align_delimiters_default = { -\ ' ': { 'pattern': ' ', 'left_margin': 0, 'right_margin': 0, 'stick_to_left': 0 }, -\ '=': { 'pattern': '===\|<=>\|\(&&\|||\|<<\|>>\)=\|=\~[#?]\?\|=>\|[:+/*!%^=><&|.?-]\?=[#?]\?', -\ 'left_margin': 1, 'right_margin': 1, 'stick_to_left': 0 }, -\ ':': { 'pattern': ':', 'left_margin': 0, 'right_margin': 1, 'stick_to_left': 1 }, -\ ',': { 'pattern': ',', 'left_margin': 0, 'right_margin': 1, 'stick_to_left': 1 }, -\ '|': { 'pattern': '|', 'left_margin': 1, 'right_margin': 1, 'stick_to_left': 0 }, -\ '.': { 'pattern': '\.', 'left_margin': 0, 'right_margin': 0, 'stick_to_left': 0 }, -\ '#': { 'pattern': '#\+', 'delimiter_align': 'l', 'ignore_groups': ['!Comment'] }, -\ '"': { 'pattern': '"\+', 'delimiter_align': 'l', 'ignore_groups': ['!Comment'] }, -\ '&': { 'pattern': '\\\@ winlen ? '..' : '' - - echon "\r" - let yet = 0 - for [hl, msg] in a:tokens - if empty(msg) | continue | endif - execute "echohl ". hl - let yet += len(msg) - if yet > winlen - len(ellipsis) - echon msg[ 0 : (winlen - len(ellipsis) - yet - 1) ] . ellipsis - break - else - echon msg - endif - endfor - finally - echohl None - let [&ruler, &showcmd] = xy - endtry -endfunction - -function! s:echon(l, n, r, d, o, warn) - let tokens = [ - \ ['Function', s:live ? ':LiveEasyAlign' : ':EasyAlign'], - \ ['ModeMsg', get(s:mode_labels, a:l, a:l)], - \ ['None', ' ']] - - if a:r == -1 | call add(tokens, ['Comment', '(']) | endif - call add(tokens, [a:n =~ '*' ? 'Repeat' : 'Number', a:n]) - call extend(tokens, a:r == 1 ? - \ [['Delimiter', '/'], ['String', a:d], ['Delimiter', '/']] : - \ [['Identifier', a:d == ' ' ? '\ ' : (a:d == '\' ? '\\' : a:d)]]) - if a:r == -1 | call extend(tokens, [['Normal', '_'], ['Comment', ')']]) | endif - call add(tokens, ['Statement', empty(a:o) ? '' : ' '.string(a:o)]) - if !empty(a:warn) - call add(tokens, ['WarningMsg', ' ('.a:warn.')']) - endif - - call s:echon_(tokens) - return join(map(tokens, 'v:val[1]'), '') -endfunction - -function! s:exit(msg) - call s:echon_([['ErrorMsg', a:msg]]) - throw 'exit' -endfunction - -function! s:ltrim(str) - return substitute(a:str, '^\s\+', '', '') -endfunction - -function! s:rtrim(str) - return substitute(a:str, '\s\+$', '', '') -endfunction - -function! s:trim(str) - return substitute(a:str, '^\s*\(.\{-}\)\s*$', '\1', '') -endfunction - -function! s:fuzzy_lu(key) - if has_key(s:known_options, a:key) - return a:key - endif - let key = tolower(a:key) - - " stl -> ^s.*_t.*_l.* - let regexp1 = '^' .key[0]. '.*' .substitute(key[1 : -1], '\(.\)', '_\1.*', 'g') - let matches = filter(keys(s:known_options), 'v:val =~ regexp1') - if len(matches) == 1 - return matches[0] - endif - - " stl -> ^s.*t.*l.* - let regexp2 = '^' . substitute(substitute(key, '-', '_', 'g'), '\(.\)', '\1.*', 'g') - let matches = filter(keys(s:known_options), 'v:val =~ regexp2') - - if empty(matches) - call s:exit("Unknown option key: ". a:key) - elseif len(matches) == 1 - return matches[0] - else - " Avoid ambiguity introduced by deprecated margin_left and margin_right - if sort(matches) == ['margin_left', 'margin_right', 'mode_sequence'] - return 'mode_sequence' - endif - if sort(matches) == ['ignore_groups', 'ignores'] - return 'ignore_groups' - endif - call s:exit("Ambiguous option key: ". a:key ." (" .join(matches, ', '). ")") - endif -endfunction - -function! s:shift(modes, cycle) - let item = remove(a:modes, 0) - if a:cycle || empty(a:modes) - call add(a:modes, item) - endif - return item -endfunction - -function! s:normalize_options(opts) - let ret = {} - for k in keys(a:opts) - let v = a:opts[k] - let k = s:fuzzy_lu(k) - " Backward-compatibility - if k == 'margin_left' | let k = 'left_margin' | endif - if k == 'margin_right' | let k = 'right_margin' | endif - if k == 'mode_sequence' | let k = 'align' | endif - let ret[k] = v - unlet v - endfor - return s:validate_options(ret) -endfunction - -function! s:compact_options(opts) - let ret = {} - for k in keys(a:opts) - let ret[s:shorthand[k]] = a:opts[k] - endfor - return ret -endfunction - -function! s:validate_options(opts) - for k in keys(a:opts) - let v = a:opts[k] - if index(s:known_options[k], type(v)) == -1 - call s:exit("Invalid type for option: ". k) - endif - unlet v - endfor - return a:opts -endfunction - -function! s:split_line(line, nth, modes, cycle, fc, lc, pattern, stick_to_left, ignore_unmatched, ignore_groups) - let mode = '' - - let string = a:lc ? - \ strpart(getline(a:line), a:fc - 1, a:lc - a:fc + 1) : - \ strpart(getline(a:line), a:fc - 1) - let idx = 0 - let nomagic = match(a:pattern, '\\v') > match(a:pattern, '\C\\[mMV]') - let pattern = '^.\{-}\s*\zs\('.a:pattern.(nomagic ? ')' : '\)') - let tokens = [] - let delims = [] - - " Phase 1: split - let ignorable = 0 - let token = '' - let phantom = 0 - while 1 - let matchidx = match(string, pattern, idx) - " No match - if matchidx < 0 | break | endif - let matchend = matchend(string, pattern, idx) - let spaces = matchstr(string, '\s'.(a:stick_to_left ? '*' : '\{-}'), matchend + (matchidx == matchend)) - - " Match, but empty - if len(spaces) + matchend - idx == 0 - let char = strpart(string, idx, 1) - if empty(char) | break | endif - let [match, part, delim] = [char, char, ''] - " Match - else - let match = strpart(string, idx, matchend - idx + len(spaces)) - let part = strpart(string, idx, matchidx - idx) - let delim = strpart(string, matchidx, matchend - matchidx) - endif - - let ignorable = s:highlighted_as(a:line, idx + len(part) + a:fc, a:ignore_groups) - if ignorable - let token .= match - else - let [pmode, mode] = [mode, s:shift(a:modes, a:cycle)] - call add(tokens, token . match) - call add(delims, delim) - let token = '' - endif - - let idx += len(match) - - " If the string is non-empty and ends with the delimiter, - " append an empty token to the list - if idx == len(string) - let phantom = 1 - break - endif - endwhile - - let leftover = token . strpart(string, idx) - if !empty(leftover) - let ignorable = s:highlighted_as(a:line, len(string) + a:fc - 1, a:ignore_groups) - call add(tokens, leftover) - call add(delims, '') - elseif phantom - call add(tokens, '') - call add(delims, '') - endif - let [pmode, mode] = [mode, s:shift(a:modes, a:cycle)] - - " Preserve indentation - merge first two tokens - if len(tokens) > 1 && empty(s:rtrim(tokens[0])) - let tokens[1] = tokens[0] . tokens[1] - call remove(tokens, 0) - call remove(delims, 0) - let mode = pmode - endif - - " Skip comment line - if ignorable && len(tokens) == 1 && a:ignore_unmatched - let tokens = [] - let delims = [] - " Append an empty item to enable right/center alignment of the last token - " - if the last token is not ignorable or ignorable but not the only token - elseif a:ignore_unmatched != 1 && - \ (mode ==? 'r' || mode ==? 'c') && - \ (!ignorable || len(tokens) > 1) && - \ a:nth >= 0 " includes -0 - call add(tokens, '') - call add(delims, '') - endif - - return [tokens, delims] -endfunction - -function! s:do_align(todo, modes, all_tokens, all_delims, fl, ll, fc, lc, nth, recur, dict) - let mode = a:modes[0] - let lines = {} - let min_indent = -1 - let max = { 'pivot_len2': 0, 'token_len': 0, 'just_len': 0, 'delim_len': 0, - \ 'indent': 0, 'tokens': 0, 'strip_len': 0 } - let d = a:dict - let [f, fx] = s:parse_filter(d.filter) - - " Phase 1 - for line in range(a:fl, a:ll) - let snip = a:lc > 0 ? getline(line)[a:fc-1 : a:lc-1] : getline(line) - if f == 1 && snip !~ fx - continue - elseif f == -1 && snip =~ fx - continue - endif - - if !has_key(a:all_tokens, line) - " Split line into the tokens by the delimiters - let [tokens, delims] = s:split_line( - \ line, a:nth, copy(a:modes), a:recur == 2, - \ a:fc, a:lc, d.pattern, - \ d.stick_to_left, d.ignore_unmatched, d.ignore_groups) - - " Remember tokens for subsequent recursive calls - let a:all_tokens[line] = tokens - let a:all_delims[line] = delims - else - let tokens = a:all_tokens[line] - let delims = a:all_delims[line] - endif - - " Skip empty lines - if empty(tokens) - continue - endif - - " Calculate the maximum number of tokens for a line within the range - let max.tokens = max([max.tokens, len(tokens)]) - - if a:nth > 0 " Positive N-th - if len(tokens) < a:nth - continue - endif - let nth = a:nth - 1 " make it 0-based - else " -0 or Negative N-th - if a:nth == 0 && mode !=? 'l' - let nth = len(tokens) - 1 - else - let nth = len(tokens) + a:nth - endif - if empty(delims[len(delims) - 1]) - let nth -= 1 - endif - - if nth < 0 || nth == len(tokens) - continue - endif - endif - - let prefix = nth > 0 ? join(tokens[0 : nth - 1], '') : '' - let delim = delims[nth] - let token = s:rtrim( tokens[nth] ) - let token = s:rtrim( strpart(token, 0, len(token) - len(s:rtrim(delim))) ) - if empty(delim) && !exists('tokens[nth + 1]') && d.ignore_unmatched - continue - endif - - let indent = s:strwidth(matchstr(tokens[0], '^\s*')) - if min_indent < 0 || indent < min_indent - let min_indent = indent - endif - if mode ==? 'c' - let token .= substitute(matchstr(token, '^\s*'), '\t', repeat(' ', &tabstop), 'g') - endif - let [pw, tw] = [s:strwidth(prefix), s:strwidth(token)] - let max.indent = max([max.indent, indent]) - let max.token_len = max([max.token_len, tw]) - let max.just_len = max([max.just_len, pw + tw]) - let max.delim_len = max([max.delim_len, s:strwidth(delim)]) - - if mode ==? 'c' - let pivot_len2 = pw * 2 + tw - if max.pivot_len2 < pivot_len2 - let max.pivot_len2 = pivot_len2 - endif - let max.strip_len = max([max.strip_len, s:strwidth(s:trim(token))]) - endif - let lines[line] = [nth, prefix, token, delim] - endfor - - " Phase 1-5: indentation handling (only on a:nth == 1) - if a:nth == 1 - let idt = d.indentation - if idt ==? 'd' - let indent = max.indent - elseif idt ==? 's' - let indent = min_indent - elseif idt ==? 'n' - let indent = 0 - elseif idt !=? 'k' - call s:exit('Invalid indentation: ' . idt) - end - - if idt !=? 'k' - let max.just_len = 0 - let max.token_len = 0 - let max.pivot_len2 = 0 - - for [line, elems] in items(lines) - let [nth, prefix, token, delim] = elems - - let tindent = matchstr(token, '^\s*') - while 1 - let len = s:strwidth(tindent) - if len < indent - let tindent .= repeat(' ', indent - len) - break - elseif len > indent - let tindent = tindent[0 : -2] - else - break - endif - endwhile - - let token = tindent . s:ltrim(token) - if mode ==? 'c' - let token = substitute(token, '\s*$', repeat(' ', indent), '') - endif - let [pw, tw] = [s:strwidth(prefix), s:strwidth(token)] - let max.token_len = max([max.token_len, tw]) - let max.just_len = max([max.just_len, pw + tw]) - if mode ==? 'c' - let pivot_len2 = pw * 2 + tw - if max.pivot_len2 < pivot_len2 - let max.pivot_len2 = pivot_len2 - endif - endif - - let lines[line][2] = token - endfor - endif - endif - - " Phase 2 - for [line, elems] in items(lines) - let tokens = a:all_tokens[line] - let delims = a:all_delims[line] - let [nth, prefix, token, delim] = elems - - " Remove the leading whitespaces of the next token - if len(tokens) > nth + 1 - let tokens[nth + 1] = s:ltrim(tokens[nth + 1]) - endif - - " Pad the token with spaces - let [pw, tw] = [s:strwidth(prefix), s:strwidth(token)] - let rpad = '' - if mode ==? 'l' - let pad = repeat(' ', max.just_len - pw - tw) - if d.stick_to_left - let rpad = pad - else - let token = token . pad - endif - elseif mode ==? 'r' - let pad = repeat(' ', max.just_len - pw - tw) - let indent = matchstr(token, '^\s*') - let token = indent . pad . s:ltrim(token) - elseif mode ==? 'c' - let p1 = max.pivot_len2 - (pw * 2 + tw) - let p2 = max.token_len - tw - let pf1 = s:floor2(p1) - if pf1 < p1 | let p2 = s:ceil2(p2) - else | let p2 = s:floor2(p2) - endif - let strip = s:ceil2(max.token_len - max.strip_len) / 2 - let indent = matchstr(token, '^\s*') - let token = indent. repeat(' ', pf1 / 2) .s:ltrim(token). repeat(' ', p2 / 2) - let token = substitute(token, repeat(' ', strip) . '$', '', '') - - if d.stick_to_left - if empty(s:rtrim(token)) - let center = len(token) / 2 - let [token, rpad] = [strpart(token, 0, center), strpart(token, center)] - else - let [token, rpad] = [s:rtrim(token), matchstr(token, '\s*$')] - endif - endif - endif - let tokens[nth] = token - - " Pad the delimiter - let dpadl = max.delim_len - s:strwidth(delim) - let da = d.delimiter_align - if da ==? 'l' - let [dl, dr] = ['', repeat(' ', dpadl)] - elseif da ==? 'c' - let dl = repeat(' ', dpadl / 2) - let dr = repeat(' ', dpadl - dpadl / 2) - elseif da ==? 'r' - let [dl, dr] = [repeat(' ', dpadl), ''] - else - call s:exit('Invalid delimiter_align: ' . da) - endif - - " Before and after the range (for blockwise visual mode) - let cline = getline(line) - let before = strpart(cline, 0, a:fc - 1) - let after = a:lc ? strpart(cline, a:lc) : '' - - " Determine the left and right margin around the delimiter - let rest = join(tokens[nth + 1 : -1], '') - let nomore = empty(rest.after) - let ml = (empty(prefix . token) || empty(delim) && nomore) ? '' : d.ml - let mr = nomore ? '' : d.mr - - " Adjust indentation of the lines starting with a delimiter - let lpad = '' - if nth == 0 - let ipad = repeat(' ', min_indent - s:strwidth(token.ml)) - if mode ==? 'l' - let token = ipad . token - else - let lpad = ipad - endif - endif - - " Align the token - let aligned = join([lpad, token, ml, dl, delim, dr, mr, rpad], '') - let tokens[nth] = aligned - - " Update the line - let a:todo[line] = before.join(tokens, '').after - endfor - - if a:nth < max.tokens && (a:recur || len(a:modes) > 1) - call s:shift(a:modes, a:recur == 2) - return [a:todo, a:modes, a:all_tokens, a:all_delims, - \ a:fl, a:ll, a:fc, a:lc, a:nth + 1, a:recur, a:dict] - endif - return [a:todo] -endfunction - -function! s:input(str, default, vis) - if a:vis - normal! gv - redraw - execute "normal! \" - else - " EasyAlign command can be called without visual selection - redraw - endif - let got = input(a:str, a:default) - return got -endfunction - -function! s:atoi(str) - return (a:str =~ '^[0-9]\+$') ? str2nr(a:str) : a:str -endfunction - -function! s:shift_opts(opts, key, vals) - let val = s:shift(a:vals, 1) - if type(val) == 0 && val == -1 - call remove(a:opts, a:key) - else - let a:opts[a:key] = val - endif -endfunction - -function! s:interactive(range, modes, n, d, opts, rules, vis, bvis) - let mode = s:shift(a:modes, 1) - let n = a:n - let d = a:d - let ch = '' - let opts = s:compact_options(a:opts) - let vals = deepcopy(s:option_values) - let regx = 0 - let warn = '' - let undo = 0 - - while 1 - " Live preview - let rdrw = 0 - if undo - silent! undo - let undo = 0 - let rdrw = 1 - endif - if s:live && !empty(d) - let output = s:process(a:range, mode, n, d, s:normalize_options(opts), regx, a:rules, a:bvis) - let &undolevels = &undolevels " Break undo block - call s:update_lines(output.todo) - let undo = !empty(output.todo) - let rdrw = 1 - endif - if rdrw - if a:vis - normal! gv - endif - redraw - if a:vis | execute "normal! \" | endif - endif - call s:echon(mode, n, -1, regx ? '/'.d.'/' : d, opts, warn) - - let check = 0 - let warn = '' - - try - let c = getchar() - catch /^Vim:Interrupt$/ - let c = 27 - endtry - let ch = nr2char(c) - if c == 3 || c == 27 " CTRL-C / ESC - if undo - silent! undo - endif - throw 'exit' - elseif c == "\" - if !empty(d) - let d = '' - let regx = 0 - elseif len(n) > 0 - let n = strpart(n, 0, len(n) - 1) - endif - elseif c == 13 " Enter key - let mode = s:shift(a:modes, 1) - if has_key(opts, 'a') - let opts.a = mode . strpart(opts.a, 1) - endif - elseif ch == '-' - if empty(n) | let n = '-' - elseif n == '-' | let n = '' - else | let check = 1 - endif - elseif ch == '*' - if empty(n) | let n = '*' - elseif n == '*' | let n = '**' - elseif n == '**' | let n = '' - else | let check = 1 - endif - elseif empty(d) && ((c == 48 && len(n) > 0) || c > 48 && c <= 57) " Numbers - if n[0] == '*' | let check = 1 - else | let n = n . ch - end - elseif ch == "\" - call s:shift_opts(opts, 'da', vals['delimiter_align']) - elseif ch == "\" - call s:shift_opts(opts, 'idt', vals['indentation']) - elseif ch == "\" - let lm = s:input("Left margin: ", get(opts, 'lm', ''), a:vis) - if empty(lm) - let warn = 'Set to default. Input 0 to remove it' - silent! call remove(opts, 'lm') - else - let opts['lm'] = s:atoi(lm) - endif - elseif ch == "\" - let rm = s:input("Right margin: ", get(opts, 'rm', ''), a:vis) - if empty(rm) - let warn = 'Set to default. Input 0 to remove it' - silent! call remove(opts, 'rm') - else - let opts['rm'] = s:atoi(rm) - endif - elseif ch == "\" - call s:shift_opts(opts, 'iu', vals['ignore_unmatched']) - elseif ch == "\" - call s:shift_opts(opts, 'ig', vals['ignore_groups']) - elseif ch == "\" - if s:live - if !empty(d) - let ch = d - break - else - let s:live = 0 - endif - else - let s:live = 1 - endif - elseif c == "\" - let opts['stl'] = 1 - let opts['lm'] = 0 - elseif c == "\" - let opts['stl'] = 0 - let opts['lm'] = 1 - elseif c == "\" - let opts['lm'] = 0 - let opts['rm'] = 0 - elseif c == "\" - silent! call remove(opts, 'stl') - silent! call remove(opts, 'lm') - silent! call remove(opts, 'rm') - elseif ch == "\" || ch == "\" - let modes = tolower(s:input("Alignment ([lrc...][[*]*]): ", get(opts, 'a', mode), a:vis)) - if match(modes, '^[lrc]\+\*\{0,2}$') != -1 - let opts['a'] = modes - let mode = modes[0] - while mode != s:shift(a:modes, 1) - endwhile - else - silent! call remove(opts, 'a') - endif - elseif ch == "\" || ch == "\" - if s:live && regx && !empty(d) - break - endif - - let prompt = 'Regular expression: ' - let ch = s:input(prompt, '', a:vis) - if !empty(ch) && s:valid_regexp(ch) - let regx = 1 - let d = ch - if !s:live | break | endif - else - let warn = 'Invalid regular expression: '.ch - endif - elseif ch == "\" - let f = s:input("Filter (g/../ or v/../): ", get(opts, 'f', ''), a:vis) - let m = matchlist(f, '^[gv]/\(.\{-}\)/\?$') - if empty(f) - silent! call remove(opts, 'f') - elseif !empty(m) && s:valid_regexp(m[1]) - let opts['f'] = f - else - let warn = 'Invalid filter expression' - endif - elseif ch =~ '[[:print:]]' - let check = 1 - else - let warn = 'Invalid character' - endif - - if check - if empty(d) - if has_key(a:rules, ch) - let d = ch - if !s:live - if a:vis - execute "normal! gv\" - endif - break - endif - else - let warn = 'Unknown delimiter key: '.ch - endif - else - if regx - let warn = 'Press to finish' - else - if d == ch - break - else - let warn = 'Press '''.d.''' again to finish' - endif - end - endif - endif - endwhile - if s:live - let copts = call('s:summarize', output.summarize) - let s:live = 0 - let g:easy_align_last_command = s:echon('', n, regx, d, copts, '') - let s:live = 1 - end - return [mode, n, ch, opts, regx] -endfunction - -function! s:valid_regexp(regexp) - try - call matchlist('', a:regexp) - catch - return 0 - endtry - return 1 -endfunction - -function! s:test_regexp(regexp) - let regexp = empty(a:regexp) ? @/ : a:regexp - if !s:valid_regexp(regexp) - call s:exit('Invalid regular expression: '. regexp) - endif - return regexp -endfunction - -let s:shorthand_regex = - \ '\s*\%(' - \ .'\(lm\?[0-9]\+\)\|\(rm\?[0-9]\+\)\|\(iu[01]\)\|\(\%(s\%(tl\)\?[01]\)\|[<>]\)\|' - \ .'\(da\?[clr]\)\|\(\%(ms\?\|a\)[lrc*]\+\)\|\(i\%(dt\)\?[kdsn]\)\|\([gv]/.*/\)\|\(ig\[.*\]\)' - \ .'\)\+\s*$' - -function! s:parse_shorthand_opts(expr) - let opts = {} - let expr = substitute(a:expr, '\s', '', 'g') - let regex = '^'. s:shorthand_regex - - if empty(expr) - return opts - elseif expr !~ regex - call s:exit("Invalid expression: ". a:expr) - else - let match = matchlist(expr, regex) - for m in filter(match[ 1 : -1 ], '!empty(v:val)') - for key in ['lm', 'rm', 'l', 'r', 'stl', 's', '<', '>', 'iu', 'da', 'd', 'ms', 'm', 'ig', 'i', 'g', 'v', 'a'] - if stridx(tolower(m), key) == 0 - let rest = strpart(m, len(key)) - if key == 'i' | let key = 'idt' | endif - if key == 'g' || key == 'v' - let rest = key.rest - let key = 'f' - endif - - if key == 'idt' || index(['d', 'f', 'm', 'a'], key[0]) >= 0 - let opts[key] = rest - elseif key == 'ig' - try - let arr = eval(rest) - if type(arr) == 3 - let opts[key] = arr - else - throw 'Not an array' - endif - catch - call s:exit("Invalid ignore_groups: ". a:expr) - endtry - elseif key =~ '[<>]' - let opts['stl'] = key == '<' - else - let opts[key] = str2nr(rest) - endif - break - endif - endfor - endfor - endif - return s:normalize_options(opts) -endfunction - -function! s:parse_args(args) - if empty(a:args) - return ['', '', {}, 0] - endif - let n = '' - let ch = '' - let args = a:args - let cand = '' - let opts = {} - - " Poor man's option parser - let idx = 0 - while 1 - let midx = match(args, '\s*{.*}\s*$', idx) - if midx == -1 | break | endif - - let cand = strpart(args, midx) - try - let [l, r, c, k, s, d, n] = ['l', 'r', 'c', 'k', 's', 'd', 'n'] - let [L, R, C, K, S, D, N] = ['l', 'r', 'c', 'k', 's', 'd', 'n'] - let o = eval(cand) - if type(o) == 4 - let opts = o - if args[midx - 1 : midx] == '\ ' - let midx += 1 - endif - let args = strpart(args, 0, midx) - break - endif - catch - " Ignore - endtry - let idx = midx + 1 - endwhile - - " Invalid option dictionary - if len(substitute(cand, '\s', '', 'g')) > 2 && empty(opts) - call s:exit("Invalid option: ". cand) - else - let opts = s:normalize_options(opts) - endif - - " Shorthand option notation - let sopts = matchstr(args, s:shorthand_regex) - if !empty(sopts) - let args = strpart(args, 0, len(args) - len(sopts)) - let opts = extend(s:parse_shorthand_opts(sopts), opts) - endif - - " Has /Regexp/? - let matches = matchlist(args, '^\(.\{-}\)\s*/\(.*\)/\s*$') - - " Found regexp - if !empty(matches) - return [matches[1], s:test_regexp(matches[2]), opts, 1] - else - let tokens = matchlist(args, '^\([1-9][0-9]*\|-[0-9]*\|\*\*\?\)\?\s*\(.\{-}\)\?$') - " Try swapping n and ch - let [n, ch] = empty(tokens[2]) ? reverse(tokens[1:2]) : tokens[1:2] - - " Resolving command-line ambiguity - " '\ ' => ' ' - " '\' => ' ' - if ch =~ '^\\\s*$' - let ch = ' ' - " '\\' => '\' - elseif ch =~ '^\\\\\s*$' - let ch = '\' - endif - - return [n, ch, opts, 0] - endif -endfunction - -function! s:parse_filter(f) - let m = matchlist(a:f, '^\([gv]\)/\(.\{-}\)/\?$') - if empty(m) - return [0, ''] - else - return [m[1] == 'g' ? 1 : -1, m[2]] - endif -endfunction - -function! s:interactive_modes(bang) - return get(g:, - \ (a:bang ? 'easy_align_bang_interactive_modes' : 'easy_align_interactive_modes'), - \ (a:bang ? ['r', 'l', 'c'] : ['l', 'r', 'c'])) -endfunction - -function! s:alternating_modes(mode) - return a:mode ==? 'r' ? 'rl' : 'lr' -endfunction - -function! s:update_lines(todo) - for [line, content] in items(a:todo) - call setline(line, s:rtrim(content)) - endfor -endfunction - -function! s:parse_nth(n) - let n = a:n - let recur = 0 - if n == '*' | let [nth, recur] = [1, 1] - elseif n == '**' | let [nth, recur] = [1, 2] - elseif n == '-' | let nth = -1 - elseif empty(n) | let nth = 1 - elseif n == '0' || ( n != '-0' && n != string(str2nr(n)) ) - call s:exit('Invalid N-th parameter: '. n) - else - let nth = n - endif - return [nth, recur] -endfunction - -function! s:build_dict(delimiters, ch, regexp, opts) - if a:regexp - let dict = { 'pattern': a:ch } - else - if !has_key(a:delimiters, a:ch) - call s:exit('Unknown delimiter key: '. a:ch) - endif - let dict = copy(a:delimiters[a:ch]) - endif - call extend(dict, a:opts) - - let ml = get(dict, 'left_margin', ' ') - let mr = get(dict, 'right_margin', ' ') - if type(ml) == 0 | let ml = repeat(' ', ml) | endif - if type(mr) == 0 | let mr = repeat(' ', mr) | endif - call extend(dict, { 'ml': ml, 'mr': mr }) - - let dict.pattern = get(dict, 'pattern', a:ch) - let dict.delimiter_align = - \ get(dict, 'delimiter_align', get(g:, 'easy_align_delimiter_align', 'r'))[0] - let dict.indentation = - \ get(dict, 'indentation', get(g:, 'easy_align_indentation', 'k'))[0] - let dict.stick_to_left = - \ get(dict, 'stick_to_left', 0) - let dict.ignore_unmatched = - \ get(dict, 'ignore_unmatched', get(g:, 'easy_align_ignore_unmatched', 2)) - let dict.ignore_groups = - \ get(dict, 'ignore_groups', get(dict, 'ignores', s:ignored_syntax())) - let dict.filter = - \ get(dict, 'filter', '') - return dict -endfunction - -function! s:build_mode_sequence(expr, recur) - let [expr, recur] = [a:expr, a:recur] - let suffix = matchstr(a:expr, '\*\+$') - if suffix == '*' - let expr = expr[0 : -2] - let recur = 1 - elseif suffix == '**' - let expr = expr[0 : -3] - let recur = 2 - endif - return [tolower(expr), recur] -endfunction - -function! s:process(range, mode, n, ch, opts, regexp, rules, bvis) - let [nth, recur] = s:parse_nth((empty(a:n) && exists('g:easy_align_nth')) ? g:easy_align_nth : a:n) - let dict = s:build_dict(a:rules, a:ch, a:regexp, a:opts) - let [mode_sequence, recur] = s:build_mode_sequence( - \ get(dict, 'align', recur == 2 ? s:alternating_modes(a:mode) : a:mode), - \ recur) - - let ve = &virtualedit - set ve=all - let args = [ - \ {}, split(mode_sequence, '\zs'), - \ {}, {}, a:range[0], a:range[1], - \ a:bvis ? min([virtcol("'<"), virtcol("'>")]) : 1, - \ (!recur && a:bvis) ? max([virtcol("'<"), virtcol("'>")]) : 0, - \ nth, recur, dict ] - let &ve = ve - while len(args) > 1 - let args = call('s:do_align', args) - endwhile - - " todo: lines to update - " summarize: arguments to s:summarize - return { 'todo': args[0], 'summarize': [ a:opts, recur, mode_sequence ] } -endfunction - -function s:summarize(opts, recur, mode_sequence) - let copts = s:compact_options(a:opts) - let nbmode = s:interactive_modes(0)[0] - if !has_key(copts, 'a') && ( - \ (a:recur == 2 && s:alternating_modes(nbmode) != a:mode_sequence) || - \ (a:recur != 2 && (a:mode_sequence[0] != nbmode || len(a:mode_sequence) > 1)) - \ ) - call extend(copts, { 'a': a:mode_sequence }) - endif - return copts -endfunction - -function! s:align(bang, live, visualmode, first_line, last_line, expr) - " Heuristically determine if the user was in visual mode - if a:visualmode == 'command' - let vis = a:first_line == line("'<") && a:last_line == line("'>") - let bvis = vis && visualmode() == "\" - elseif empty(a:visualmode) - let vis = 0 - let bvis = 0 - else - let vis = 1 - let bvis = a:visualmode == "\" - end - let range = [a:first_line, a:last_line] - let modes = s:interactive_modes(a:bang) - let mode = modes[0] - let s:live = a:live - - let rules = s:easy_align_delimiters_default - if exists('g:easy_align_delimiters') - let rules = extend(copy(rules), g:easy_align_delimiters) - endif - - let [n, ch, opts, regexp] = s:parse_args(a:expr) - - let bypass_fold = get(g:, 'easy_align_bypass_fold', 0) - let ofm = &l:foldmethod - try - if bypass_fold | let &l:foldmethod = 'manual' | endif - - if empty(n) && empty(ch) || s:live - let [mode, n, ch, opts, regexp] = s:interactive(range, copy(modes), n, ch, opts, rules, vis, bvis) - endif - - if !s:live - let output = s:process(range, mode, n, ch, s:normalize_options(opts), regexp, rules, bvis) - call s:update_lines(output.todo) - let copts = call('s:summarize', output.summarize) - let g:easy_align_last_command = s:echon('', n, regexp, ch, copts, '') - endif - finally - if bypass_fold | let &l:foldmethod = ofm | endif - endtry -endfunction - -function! easy_align#align(bang, live, visualmode, expr) range - try - call s:align(a:bang, a:live, a:visualmode, a:firstline, a:lastline, a:expr) - catch /^\%(Vim:Interrupt\|exit\)$/ - if empty(a:visualmode) - echon "\r" - echon "\r" - else - normal! gv - endif - endtry -endfunction - -let &cpo = s:cpo_save -unlet s:cpo_save - diff --git a/.vim/pack/plugins/start/vim-easy-align/doc/easy_align.txt b/.vim/pack/plugins/start/vim-easy-align/doc/easy_align.txt deleted file mode 100644 index 5a82e5e..0000000 --- a/.vim/pack/plugins/start/vim-easy-align/doc/easy_align.txt +++ /dev/null @@ -1,891 +0,0 @@ -easy-align.txt easy-align Last change: December 14 2014 -EASY-ALIGN - TABLE OF CONTENTS *easyalign* *easy-align* *easy-align-toc* -============================================================================== - - vim-easy-align - Demo |easy-align-1| - Features |easy-align-2| - Installation |easy-align-3| - TLDR - One-minute guide |easy-align-4| - Usage |easy-align-5| - Concept of alignment rule |easy-align-5-1| - Execution models |easy-align-5-2| - 1. Using mappings |easy-align-5-2-1| - 2. Using :EasyAlign command |easy-align-5-2-2| - Interactive mode |easy-align-5-3| - Predefined alignment rules |easy-align-5-3-1| - Examples |easy-align-5-3-2| - Using regular expressions |easy-align-5-3-3| - Alignment options in interactive mode |easy-align-5-3-4| - Live interactive mode |easy-align-5-4| - Non-interactive mode |easy-align-5-5| - Partial alignment in blockwise-visual mode |easy-align-5-6| - Alignment options |easy-align-6| - List of options |easy-align-6-1| - Filtering lines |easy-align-6-2| - Examples |easy-align-6-2-1| - Ignoring delimiters in comments or strings |easy-align-6-3| - Ignoring unmatched lines |easy-align-6-4| - Aligning delimiters of different lengths |easy-align-6-5| - Adjusting indentation |easy-align-6-6| - Alignments over multiple occurrences of delimiters |easy-align-6-7| - Extending alignment rules |easy-align-6-8| - Examples |easy-align-6-8-1| - Other options |easy-align-7| - Disabling &foldmethod during alignment |easy-align-7-1| - Left/right/center mode switch in interactive mode |easy-align-7-2| - Advanced examples and use cases |easy-align-8| - Related work |easy-align-9| - Author |easy-align-10| - License |easy-align-11| - - -VIM-EASY-ALIGN *vim-easy-align* -============================================================================== - -A simple, easy-to-use Vim alignment plugin. - - - *easy-align-1* -DEMO *easy-align-demo* -============================================================================== - -Screencast: -https://raw.githubusercontent.com/junegunn/i/master/vim-easy-align.gif - -(Too fast? Slower GIF is {here}{1}) - -{1} https://raw.githubusercontent.com/junegunn/i/master/vim-easy-align-slow.gif - - - *easy-align-2* -FEATURES *easy-align-features* -============================================================================== - - - Easy to use - - Comes with a predefined set of alignment rules - - Provides a fast and intuitive interface - - Extensible - - You can define your own rules - - Supports arbitrary regular expressions - - Optimized for code editing - - Takes advantage of syntax highlighting feature to avoid unwanted - alignments - - - *easy-align-3* -INSTALLATION *easy-align-installation* -============================================================================== - -Use your favorite plugin manager. - -Using {vim-plug}{2}: -> - Plug 'junegunn/vim-easy-align' -< - {2} https://github.com/junegunn/vim-plug - - - *easy-align-4* -TLDR - ONE-MINUTE GUIDE *easy-align-tldr-one-minute-guide* -============================================================================== - -Add the following mappings to your .vimrc. - - *(EasyAlign)* -> - " Start interactive EasyAlign in visual mode (e.g. vip) - vmap (EasyAlign) - - " Start interactive EasyAlign for a motion/text object (e.g. gaip) - nmap ga (EasyAlign) -< -And with the following lines of text, -> - apple =red - grass+=green - sky-= blue -< -try these commands: - - - vip= - - `v`isual-select `i`nner `p`aragraph - - Start EasyAlign command () - - Align around `=` - - `gaip=` - - Start EasyAlign command (`ga`) for `i`nner `p`aragraph - - Align around `=` - -Notice that the commands are repeatable with `.` key if you have installed -{repeat.vim}{3}. Install {visualrepeat}{4} as well if you want to repeat in -visual mode. - - {3} https://github.com/tpope/vim-repeat - {4} https://github.com/vim-scripts/visualrepeat - - - *easy-align-5* -USAGE *easy-align-usage* -============================================================================== - - -< Concept of alignment rule >_________________________________________________~ - *easy-align-concept-of-alignment-rule* - *easy-align-5-1* - -Though easy-align can align lines of text around any delimiter, it provides -shortcuts for the most common use cases with the concept of "alignment rule". - -An alignment rule is a predefined set of options for common alignment tasks, -which is identified by a single character, DELIMITER KEY, such as , -`=`, `:`, `.`, `|`, `&`, `#`, and `,`. - -Think of it as a shortcut. Instead of writing regular expression and setting -several options, you can just type in a single character. - - -< Execution models >__________________________________________________________~ - *easy-align-execution-models* - *easy-align-5-2* - -There are two ways to use easy-align. - - -1. Using mappings~ - *easy-align-1-using-plug-mappings* - *easy-align-5-2-1* - -The recommended method is to use mappings as described earlier. - - *(LiveEasyAlign)* - - ----------------------+--------+----------------------------------------------------- - Mapping | Mode | Description ~ - ----------------------+--------+----------------------------------------------------- - (EasyAlign) | normal | Start interactive mode for a motion/text object - (EasyAlign) | visual | Start interactive mode for the selection - (LiveEasyAlign) | normal | Start live-interactive mode for a motion/text object - (LiveEasyAlign) | visual | Start live-interactive mode for the selection - ----------------------+--------+----------------------------------------------------- - - -2. Using :EasyAlign command~ - *easy-align-2-using-easyalign-command* - *easy-align-5-2-2* - - *:EasyAlign* - -If you prefer command-line or do not want to start interactive mode, you can -use `:EasyAlign` command instead. - - *:LiveEasyAlign* - - -------------------------------------------+----------------------------------------------- - Mode | Command ~ - -------------------------------------------+----------------------------------------------- - Interactive mode | `:EasyAlign[!] [OPTIONS]` - Live interactive mode | `:LiveEasyAlign[!] [...]` - Non-interactive mode (predefined rules) | `:EasyAlign[!] [N-th] DELIMITER_KEY [OPTIONS]` - Non-interactive mode (regular expressions) | `:EasyAlign[!] [N-th] /REGEXP/ [OPTIONS]` - -------------------------------------------+----------------------------------------------- - - -< Interactive mode >__________________________________________________________~ - *easy-align-interactive-mode* - *easy-align-5-3* - -The following sections will assume that you have (EasyAlign) mappings in -your .vimrc as below: -> - " Start interactive EasyAlign in visual mode (e.g. vip) - vmap (EasyAlign) - - " Start interactive EasyAlign for a motion/text object (e.g. gaip) - nmap ga (EasyAlign) -< -With these mappings, you can align text with only a few keystrokes. - - 1. key in visual mode, or `ga` followed by a motion or a text object to - start interactive mode - 2. Optional: Enter keys to select alignment mode (left, right, or center) - 3. Optional: N-th delimiter (default: 1) - - `1` Around the 1st occurrences of delimiters - - `2` Around the 2nd occurrences of delimiters - - ... - - `*` Around all occurrences of delimiters - - `**` Left-right alternating alignment around all delimiters - - `-` Around the last occurrences of delimiters (`-1`) - - `-2` Around the second to last occurrences of delimiters - - ... - 4. Delimiter key (a single keystroke; , `=`, `:`, `.`, `|`, `&`, `#`, `,`) - - -Predefined alignment rules~ - *easy-align-predefined-alignment-rules* - *easy-align-5-3-1* - - --------------+-------------------------------------------------------------------- - Delimiter key | Description/Use cases ~ - --------------+-------------------------------------------------------------------- - | General alignment around whitespaces - `=` | Operators containing equals sign ( `=` , `==,` `!=` , `+=` , `&&=` , ...) - `:` | Suitable for formatting JSON or YAML - `.` | Multi-line method chaining - `,` | Multi-line method arguments - `&` | LaTeX tables (matches `&` and `\\` ) - `#` | Ruby/Python comments - `"` | Vim comments - | Table markdown - --------------+-------------------------------------------------------------------- - - *g:easy_align_delimiters* - -You can override these default rules or define your own rules with -`g:easy_align_delimiters`, which will be described in {the later section}{5}. - - {5} https://github.com/junegunn/vim-easy-align#extending-alignment-rules - - -Examples~ - *easy-align-examples* - *easy-align-5-3-2* - - ------------------+------------------------------------+-------------------- - With visual map | Description | Equivalent command ~ - ------------------+------------------------------------+-------------------- - | Around 1st whitespaces | :'<,'>EasyAlign\ - 2 | Around 2nd whitespaces | :'<,'>EasyAlign2\ - - | Around the last whitespaces | :'<,'>EasyAlign-\ - -2 | Around the 2nd to last whitespaces | :'<,'>EasyAlign-2\ - : | Around 1st colon ( `key: value` ) | :'<,'>EasyAlign: - : | Around 1st colon ( `key : value` ) | :'<,'>EasyAlign:= | Around 1st operators with = | :'<,'>EasyAlign= - 3= | Around 3rd operators with = | :'<,'>EasyAlign3= - *= | Around all operators with = | :'<,'>EasyAlign*= - **= | Left-right alternating around = | :'<,'>EasyAlign**= - = | Right alignment around 1st = | :'<,'>EasyAlign!= - **= | Right-left alternating around = | :'<,'>EasyAlign!**= - ------------------+------------------------------------+-------------------- - - -Using regular expressions~ - *easy-align-using-regular-expressions* - *easy-align-5-3-3* - -Instead of finishing the command with a predefined delimiter key, you can type -in a regular expression after CTRL-/ or CTRL-X key. For example, if you want -to align text around all occurrences of numbers: - - - - - `*` - - CTRL-X - - `[0-9]\+` - - -Alignment options in interactive mode~ - *easy-align-alignment-options-in-interactive-mode* - *easy-align-5-3-4* - -While in interactive mode, you can set alignment options using special -shortcut keys listed below. The meaning of each option will be described in -{the following sections}{6}. - - --------+--------------------+--------------------------------------------------- - Key | Option | Values ~ - --------+--------------------+--------------------------------------------------- - CTRL-F | `filter` | Input string ( `[gv]/.*/?` ) - CTRL-I | `indentation` | shallow, deep, none, keep - CTRL-L | `left_margin` | Input number or string - CTRL-R | `right_margin` | Input number or string - CTRL-D | `delimiter_align` | left, center, right - CTRL-U | `ignore_unmatched` | 0, 1 - CTRL-G | `ignore_groups` | [], ["String'], ["Comment'], ["String', "Comment'] - CTRL-A | `align` | Input string ( `/[lrc]+\*{0,2}/` ) - | `stick_to_left` | `{ 'stick_to_left': 1, 'left_margin': 0 }` - | `stick_to_left` | `{ 'stick_to_left': 0, 'left_margin': 1 }` - | `*_margin` | `{ 'left_margin': 0, 'right_margin': 0 }` - --------+--------------------+--------------------------------------------------- - - {6} https://github.com/junegunn/vim-easy-align#alignment-options - - -< Live interactive mode >_____________________________________________________~ - *easy-align-live-interactive-mode* - *easy-align-5-4* - -If you're performing a complex alignment where multiple options should be -carefully adjusted, try "live interactive mode" where you can preview the -result of the alignment on-the-fly as you type in. - -Live interactive mode can be started with either (LiveEasyAlign) map or -`:LiveEasyAlign` command. Or you can switch to live interactive mode while in -ordinary interactive mode by pressing CTRL-P. (P for Preview) - -In live interactive mode, you have to type in the same delimiter (or CTRL-X on -regular expression) again to finalize the alignment. This allows you to -preview the result of the alignment and freely change the delimiter using -backspace key without leaving the interactive mode. - - -< Non-interactive mode >______________________________________________________~ - *easy-align-non-interactive-mode* - *easy-align-5-5* - -Instead of starting interactive mode, you can use declarative, non-interactive -`:EasyAlign` command. -> - " Using predefined alignment rules - " :EasyAlign[!] [N-th] DELIMITER_KEY [OPTIONS] - :EasyAlign : - :EasyAlign = - :EasyAlign *= - :EasyAlign 3\ - - " Using arbitrary regular expressions - " :EasyAlign[!] [N-th] /REGEXP/ [OPTIONS] - :EasyAlign /[:;]\+/ - :EasyAlign 2/[:;]\+/ - :EasyAlign */[:;]\+/ - :EasyAlign **/[:;]\+/ -< -A command can end with alignment options, {each of which will be discussed in -detail later}{6}, in Vim dictionary format. - - - `:EasyAlign * /[:;]\+/ { 'stick_to_left': 1, 'left_margin': 0 }` - -`stick_to_left` of 1 means that the matched delimiter should be positioned -right next to the preceding token, and `left_margin` of 0 removes the margin -on the left. So we get: -> - apple;: banana:: cake - data;; exchange:; format -< -Option names are fuzzy-matched, so you can write as follows: - - - `:EasyAlign * /[:;]\+/ { 'stl': 1, 'l': 0 }` - -You can even omit spaces between the arguments, so concisely (or cryptically): - - - `:EasyAlign*/[:;]\+/{'s':1,'l':0}` - -Nice. But let's make it even shorter. Option values can be written in -shorthand notation. - - - `:EasyAlign*/[:;]\+/` - `ignore_unmatched` | `iu[01]` - `ignore_groups` | `ig\[.*\]` - `align` | `a[lrc*]*` - `delimiter_align` | `d[lrc]` - `indentation` | `i[ksdn]` - -------------------+----------- - -For your information, the same operation can be done in interactive mode as -follows: - - - - - `*` - - - - CTRL-X - - `[:;]\+` - - {6} https://github.com/junegunn/vim-easy-align#alignment-options - - -< Partial alignment in blockwise-visual mode >________________________________~ - *easy-align-partial-alignment-in-blockwise-visual-mode* - *easy-align-5-6* - -In blockwise-visual mode (CTRL-V), EasyAlign command aligns only the selected -text in the block, instead of the whole lines in the range. - -Consider the following case where you want to align text around `=>` -operators. -> - my_hash = { :a => 1, - :aa => 2, - :aaa => 3 } -< -In non-blockwise visual mode (`v` / `V`), = won't work since the -assignment operator in the first line gets in the way. So we instead enter -blockwise-visual mode (CTRL-V), and select the text around`=>` operators, then -press =. -> - my_hash = { :a => 1, - :aa => 2, - :aaa => 3 } -< -However, in this case, we don't really need blockwise visual mode since the -same can be easily done using the negative N-th parameter: -= - - - *easy-align-6* -ALIGNMENT OPTIONS *easy-align-alignment-options* -============================================================================== - - -< List of options >___________________________________________________________~ - *easy-align-list-of-options* - *easy-align-6-1* - - -------------------+---------+-----------------------+-------------------------------------------------------- - Option | Type | Default | Description ~ - -------------------+---------+-----------------------+-------------------------------------------------------- - `filter` | string | | Line filtering expression: `g/../` or `v/../` - `left_margin` | number | 1 | Number of spaces to attach before delimiter - `left_margin` | string | `' '` | String to attach before delimiter - `right_margin` | number | 1 | Number of spaces to attach after delimiter - `right_margin` | string | `' '` | String to attach after delimiter - `stick_to_left` | boolean | 0 | Whether to position delimiter on the left-side - `ignore_groups` | list | ["String', "Comment'] | Delimiters in these syntax highlight groups are ignored - `ignore_unmatched` | boolean | 1 | Whether to ignore lines without matching delimiter - `indentation` | string | `k` | Indentation method (keep, deep, shallow, none) - `delimiter_align` | string | `r` | Determines how to align delimiters of different lengths - `align` | string | `l` | Alignment modes for multiple occurrences of delimiters - -------------------+---------+-----------------------+-------------------------------------------------------- - -There are 4 ways to set alignment options (from lowest precedence to highest): - - 1. Some option values can be set with corresponding global variables - 2. Option values can be specified in the definition of each alignment rule - 3. Option values can be given as arguments to `:EasyAlign` command - 4. Option values can be set in interactive mode using special shortcut keys - - *g:easy_align_ignore_groups* *g:easy_align_ignore_unmatched* - *g:easy_align_indentation* *g:easy_align_delimiter_align* - - -------------------+-----------------+-------------+-------------------------------- - Option name | Shortcut key | Abbreviated | Global variable ~ - -------------------+-----------------+-------------+-------------------------------- - `filter` | CTRL-F | `[gv]/.*/` | - `left_margin` | CTRL-L | `l[0-9]+` | - `right_margin` | CTRL-R | `r[0-9]+` | - `stick_to_left` | , | `<` or `>` | - `ignore_groups` | CTRL-G | `ig\[.*\]` | `g:easy_align_ignore_groups` - `ignore_unmatched` | CTRL-U | `iu[01]` | `g:easy_align_ignore_unmatched` - `indentation` | CTRL-I | `i[ksdn]` | `g:easy_align_indentation` - `delimiter_align` | CTRL-D | `d[lrc]` | `g:easy_align_delimiter_align` - `align` | CTRL-A | `a[lrc*]*` | - -------------------+-----------------+-------------+-------------------------------- - - -< Filtering lines >___________________________________________________________~ - *easy-align-filtering-lines* - *easy-align-6-2* - -With `filter` option, you can align lines that only match or do not match a -given pattern. There are several ways to set the pattern. - - 1. Press CTRL-F in interactive mode and type in `g/pat/` or `v/pat/` - 2. In command-line, it can be written in dictionary format: `{'filter': - 'g/pat/'}` - 3. Or in shorthand notation: `g/pat/` or `v/pat/` - -(You don't need to escape "/'s in the regular expression) - - -Examples~ - - *easy-align-6-2-1* -> - " Start interactive mode with filter option set to g/hello/ - EasyAlign g/hello/ - - " Start live interactive mode with filter option set to v/goodbye/ - LiveEasyAlign v/goodbye/ - - " Align the lines with 'hi' around the first colons - EasyAlign:g/hi/ -< - -< Ignoring delimiters in comments or strings >________________________________~ - *easy-align-ignoring-delimiters-in-comments-or-strings* - *easy-align-6-3* - -EasyAlign can be configured to ignore delimiters in certain syntax highlight -groups, such as code comments or strings. By default, delimiters that are -highlighted as code comments or strings are ignored. -> - " Default: - " If a delimiter is in a highlight group whose name matches - " any of the followings, it will be ignored. - let g:easy_align_ignore_groups = ['Comment', 'String'] -< -For example, the following paragraph -> - { - # Quantity of apples: 1 - apple: 1, - # Quantity of bananas: 2 - bananas: 2, - # Quantity of grape:fruits: 3 - 'grape:fruits': 3 - } -< -becomes as follows on : (or `:EasyAlign:`) -> - { - # Quantity of apples: 1 - apple: 1, - # Quantity of bananas: 2 - bananas: 2, - # Quantity of grape:fruits: 3 - 'grape:fruits': 3 - } -< -Naturally, this feature only works when syntax highlighting is enabled. - -You can change the default rule by using one of these 4 methods. - - 1. Press CTRL-G in interactive mode to switch groups - 2. Define global `g:easy_align_ignore_groups` list - 3. Define a custom rule in `g:easy_align_delimiters` with `ignore_groups` option - 4. Provide `ignore_groups` option to `:EasyAlign` command. e.g. `:EasyAlign:ig[]` - -For example if you set `ignore_groups` option to be an empty list, you get -> - { - # Quantity of apples: 1 - apple: 1, - # Quantity of bananas: 2 - bananas: 2, - # Quantity of grape: fruits: 3 - 'grape: fruits': 3 - } -< -If a pattern in `ignore_groups` is prepended by a `!`, it will have the -opposite meaning. For instance, if `ignore_groups` is given as `['!Comment']`, -delimiters that are not highlighted as Comment will be ignored during the -alignment. - - -< Ignoring unmatched lines >__________________________________________________~ - *easy-align-ignoring-unmatched-lines* - *easy-align-6-4* - -`ignore_unmatched` option determines how EasyAlign command processes lines -that do not have N-th delimiter. - - 1. In left-alignment mode, they are ignored - 2. In right or center-alignment mode, they are not ignored, and the last tokens - from those lines are aligned as well as if there is an invisible trailing - delimiter at the end of each line - 3. If `ignore_unmatched` is 1, they are ignored regardless of the alignment mode - 4. If `ignore_unmatched` is 0, they are not ignored regardless of the mode - -Let's take an example. When we align the following code block around the (1st) -colons, -> - { - apple: proc { - this_line_does_not_have_a_colon - }, - bananas: 2, - grapefruits: 3 - } -< -this is usually what we want. -> - { - apple: proc { - this_line_does_not_have_a_colon - }, - bananas: 2, - grapefruits: 3 - } -< -However, we can override this default behavior by setting `ignore_unmatched` -option to zero using one of the following methods. - - 1. Press CTRL-U in interactive mode to toggle `ignore_unmatched` option - 2. Set the global `g:easy_align_ignore_unmatched` variable to 0 - 3. Define a custom alignment rule with `ignore_unmatched` option set to 0 - 4. Provide `ignore_unmatched` option to `:EasyAlign` command. e.g. - `:EasyAlign:iu0` - -Then we get, -> - { - apple: proc { - this_line_does_not_have_a_colon - }, - bananas: 2, - grapefruits: 3 - } -< - -< Aligning delimiters of different lengths >__________________________________~ - *easy-align-aligning-delimiters-of-different-lengths* - *easy-align-6-5* - -Global `g:easy_align_delimiter_align` option and rule-wise/command-wise -`delimiter_align` option determines how matched delimiters of different -lengths are aligned. -> - apple = 1 - banana += apple - cake ||= banana -< -By default, delimiters are right-aligned as follows. -> - apple = 1 - banana += apple - cake ||= banana -< -However, with `:EasyAlign=dl`, delimiters are left-aligned. -> - apple = 1 - banana += apple - cake ||= banana -< -And on `:EasyAlign=dc`, center-aligned. -> - apple = 1 - banana += apple - cake ||= banana -< -In interactive mode, you can change the option value with CTRL-D key. - - -< Adjusting indentation >_____________________________________________________~ - *easy-align-adjusting-indentation* - *easy-align-6-6* - -By default :EasyAlign command keeps the original indentation of the lines. But -then again we have `indentation` option. See the following example. -> - # Lines with different indentation - apple = 1 - banana = 2 - cake = 3 - daisy = 4 - eggplant = 5 - - # Default: _k_eep the original indentation - # :EasyAlign= - apple = 1 - banana = 2 - cake = 3 - daisy = 4 - eggplant = 5 - - # Use the _s_hallowest indentation among the lines - # :EasyAlign=is - apple = 1 - banana = 2 - cake = 3 - daisy = 4 - eggplant = 5 - - # Use the _d_eepest indentation among the lines - # :EasyAlign=id - apple = 1 - banana = 2 - cake = 3 - daisy = 4 - eggplant = 5 - - # Indentation: _n_one - # :EasyAlign=in - apple = 1 - banana = 2 - cake = 3 - daisy = 4 - eggplant = 5 -< -In interactive mode, you can change the option value with CTRL-I key. - - -< Alignments over multiple occurrences of delimiters >________________________~ - *easy-align-alignments-over-multiple-occurrences-of-delimiters* - *easy-align-6-7* - -As stated above, "N-th" parameter is used to target specific occurrences of -the delimiter when it appears multiple times in each line. - -To recap: -> - " Left-alignment around the FIRST occurrences of delimiters - :EasyAlign = - - " Left-alignment around the SECOND occurrences of delimiters - :EasyAlign 2= - - " Left-alignment around the LAST occurrences of delimiters - :EasyAlign -= - - " Left-alignment around ALL occurrences of delimiters - :EasyAlign *= - - " Left-right ALTERNATING alignment around all occurrences of delimiters - :EasyAlign **= - - " Right-left ALTERNATING alignment around all occurrences of delimiters - :EasyAlign! **= -< -In addition to these, you can fine-tune alignments over multiple occurrences -of the delimiters with "align' option. (The option can also be set in -interactive mode with the special key CTRL-A) -> - " Left alignment over the first two occurrences of delimiters - :EasyAlign = { 'align': 'll' } - - " Right, left, center alignment over the 1st to 3rd occurrences of delimiters - :EasyAlign = { 'a': 'rlc' } - - " Using shorthand notation - :EasyAlign = arlc - - " Right, left, center alignment over the 2nd to 4th occurrences of delimiters - :EasyAlign 2=arlc - - " (*) Repeating alignments (default: l, r, or c) - " Right, left, center, center, center, center, ... - :EasyAlign *=arlc - - " (**) Alternating alignments (default: lr or rl) - " Right, left, center, right, left, center, ... - :EasyAlign **=arlc - - " Right, left, center, center, center, ... repeating alignment - " over the 3rd to the last occurrences of delimiters - :EasyAlign 3=arlc* - - " Right, left, center, right, left, center, ... alternating alignment - " over the 3rd to the last occurrences of delimiters - :EasyAlign 3=arlc** -< - -< Extending alignment rules >_________________________________________________~ - *easy-align-extending-alignment-rules* - *easy-align-6-8* - -Although the default rules should cover the most of the use cases, you can -extend the rules by setting a dictionary named `g:easy_align_delimiters`. - -You may refer to the definitions of the default alignment rules {here}{7}. - -{7} https://github.com/junegunn/vim-easy-align/blob/2.9.6/autoload/easy_align.vim#L32-L46 - - -Examples~ - - *easy-align-6-8-1* -> - let g:easy_align_delimiters = { - \ '>': { 'pattern': '>>\|=>\|>' }, - \ '/': { - \ 'pattern': '//\+\|/\*\|\*/', - \ 'delimiter_align': 'l', - \ 'ignore_groups': ['!Comment'] }, - \ ']': { - \ 'pattern': '[[\]]', - \ 'left_margin': 0, - \ 'right_margin': 0, - \ 'stick_to_left': 0 - \ }, - \ ')': { - \ 'pattern': '[()]', - \ 'left_margin': 0, - \ 'right_margin': 0, - \ 'stick_to_left': 0 - \ }, - \ 'd': { - \ 'pattern': ' \(\S\+\s*[;=]\)\@=', - \ 'left_margin': 0, - \ 'right_margin': 0 - \ } - \ } -< - - *easy-align-7* -OTHER OPTIONS *easy-align-other-options* -============================================================================== - - -< Disabling &foldmethod during alignment >____________________________________~ - *easy-align-disabling-foldmethod-during-alignment* - *easy-align-7-1* - - *g:easy_align_bypass_fold* - -{It is reported}{8} that 'foldmethod' value of `expr` or `syntax` can -significantly slow down the alignment when editing a large, complex file with -many folds. To alleviate this issue, EasyAlign provides an option to -temporarily set 'foldmethod' to `manual` during the alignment task. In order -to enable this feature, set `g:easy_align_bypass_fold` switch to 1. -> - let g:easy_align_bypass_fold = 1 -< - {8} https://github.com/junegunn/vim-easy-align/issues/14 - - -< Left/right/center mode switch in interactive mode >_________________________~ - *easy-align-left-right-center-mode-switch-in-interactive-mode* - *easy-align-7-2* - -In interactive mode, you can choose the alignment mode you want by pressing -enter keys. The non-bang command, `:EasyAlign` starts in left-alignment mode -and changes to right and center mode as you press enter keys, while the bang -version first starts in right-alignment mode. - - - `:EasyAlign` - - Left, Right, Center - - `:EasyAlign!` - - Right, Left, Center - -If you do not prefer this default mode transition, you can define your own -settings as follows. - - *g:easy_align_interactive_modes* *g:easy_align_bang_interactive_modes* -> - let g:easy_align_interactive_modes = ['l', 'r'] - let g:easy_align_bang_interactive_modes = ['c', 'r'] -< - - *easy-align-8* -ADVANCED EXAMPLES AND USE CASES *easy-align-advanced-examples-and-use-cases* -============================================================================== - -See {EXAMPLES.md}{9} for more examples. - - {9} https://github.com/junegunn/vim-easy-align/blob/master/EXAMPLES.md - - - *easy-align-9* -RELATED WORK *easy-align-related-work* -============================================================================== - - - {DrChip's Alignment Tool for Vim}{10} - - {Tabular}{11} - - {10} http://www.drchip.org/astronaut/vim/align.html - {11} https://github.com/godlygeek/tabular - - - *easy-align-10* -AUTHOR *easy-align-author* -============================================================================== - -{Junegunn Choi}{12} - - {12} https://github.com/junegunn - - - *easy-align-11* -LICENSE *easy-align-license* -============================================================================== - -MIT - -============================================================================== -vim:tw=78:sw=2:ts=2:ft=help:norl:nowrap: diff --git a/.vim/pack/plugins/start/vim-easy-align/doc/tags b/.vim/pack/plugins/start/vim-easy-align/doc/tags deleted file mode 100644 index 0411c5f..0000000 --- a/.vim/pack/plugins/start/vim-easy-align/doc/tags +++ /dev/null @@ -1,84 +0,0 @@ -:EasyAlign easy_align.txt /*:EasyAlign* -:LiveEasyAlign easy_align.txt /*:LiveEasyAlign* -(EasyAlign) easy_align.txt /*(EasyAlign)* -(LiveEasyAlign) easy_align.txt /*(LiveEasyAlign)* -easy-align easy_align.txt /*easy-align* -easy-align-1 easy_align.txt /*easy-align-1* -easy-align-1-using-plug-mappings easy_align.txt /*easy-align-1-using-plug-mappings* -easy-align-10 easy_align.txt /*easy-align-10* -easy-align-11 easy_align.txt /*easy-align-11* -easy-align-2 easy_align.txt /*easy-align-2* -easy-align-2-using-easyalign-command easy_align.txt /*easy-align-2-using-easyalign-command* -easy-align-3 easy_align.txt /*easy-align-3* -easy-align-4 easy_align.txt /*easy-align-4* -easy-align-5 easy_align.txt /*easy-align-5* -easy-align-5-1 easy_align.txt /*easy-align-5-1* -easy-align-5-2 easy_align.txt /*easy-align-5-2* -easy-align-5-2-1 easy_align.txt /*easy-align-5-2-1* -easy-align-5-2-2 easy_align.txt /*easy-align-5-2-2* -easy-align-5-3 easy_align.txt /*easy-align-5-3* -easy-align-5-3-1 easy_align.txt /*easy-align-5-3-1* -easy-align-5-3-2 easy_align.txt /*easy-align-5-3-2* -easy-align-5-3-3 easy_align.txt /*easy-align-5-3-3* -easy-align-5-3-4 easy_align.txt /*easy-align-5-3-4* -easy-align-5-4 easy_align.txt /*easy-align-5-4* -easy-align-5-5 easy_align.txt /*easy-align-5-5* -easy-align-5-6 easy_align.txt /*easy-align-5-6* -easy-align-6 easy_align.txt /*easy-align-6* -easy-align-6-1 easy_align.txt /*easy-align-6-1* -easy-align-6-2 easy_align.txt /*easy-align-6-2* -easy-align-6-2-1 easy_align.txt /*easy-align-6-2-1* -easy-align-6-3 easy_align.txt /*easy-align-6-3* -easy-align-6-4 easy_align.txt /*easy-align-6-4* -easy-align-6-5 easy_align.txt /*easy-align-6-5* -easy-align-6-6 easy_align.txt /*easy-align-6-6* -easy-align-6-7 easy_align.txt /*easy-align-6-7* -easy-align-6-8 easy_align.txt /*easy-align-6-8* -easy-align-6-8-1 easy_align.txt /*easy-align-6-8-1* -easy-align-7 easy_align.txt /*easy-align-7* -easy-align-7-1 easy_align.txt /*easy-align-7-1* -easy-align-7-2 easy_align.txt /*easy-align-7-2* -easy-align-8 easy_align.txt /*easy-align-8* -easy-align-9 easy_align.txt /*easy-align-9* -easy-align-adjusting-indentation easy_align.txt /*easy-align-adjusting-indentation* -easy-align-advanced-examples-and-use-cases easy_align.txt /*easy-align-advanced-examples-and-use-cases* -easy-align-aligning-delimiters-of-different-lengths easy_align.txt /*easy-align-aligning-delimiters-of-different-lengths* -easy-align-alignment-options easy_align.txt /*easy-align-alignment-options* -easy-align-alignment-options-in-interactive-mode easy_align.txt /*easy-align-alignment-options-in-interactive-mode* -easy-align-alignments-over-multiple-occurrences-of-delimiters easy_align.txt /*easy-align-alignments-over-multiple-occurrences-of-delimiters* -easy-align-author easy_align.txt /*easy-align-author* -easy-align-concept-of-alignment-rule easy_align.txt /*easy-align-concept-of-alignment-rule* -easy-align-demo easy_align.txt /*easy-align-demo* -easy-align-disabling-foldmethod-during-alignment easy_align.txt /*easy-align-disabling-foldmethod-during-alignment* -easy-align-examples easy_align.txt /*easy-align-examples* -easy-align-execution-models easy_align.txt /*easy-align-execution-models* -easy-align-extending-alignment-rules easy_align.txt /*easy-align-extending-alignment-rules* -easy-align-features easy_align.txt /*easy-align-features* -easy-align-filtering-lines easy_align.txt /*easy-align-filtering-lines* -easy-align-ignoring-delimiters-in-comments-or-strings easy_align.txt /*easy-align-ignoring-delimiters-in-comments-or-strings* -easy-align-ignoring-unmatched-lines easy_align.txt /*easy-align-ignoring-unmatched-lines* -easy-align-installation easy_align.txt /*easy-align-installation* -easy-align-interactive-mode easy_align.txt /*easy-align-interactive-mode* -easy-align-left-right-center-mode-switch-in-interactive-mode easy_align.txt /*easy-align-left-right-center-mode-switch-in-interactive-mode* -easy-align-license easy_align.txt /*easy-align-license* -easy-align-list-of-options easy_align.txt /*easy-align-list-of-options* -easy-align-live-interactive-mode easy_align.txt /*easy-align-live-interactive-mode* -easy-align-non-interactive-mode easy_align.txt /*easy-align-non-interactive-mode* -easy-align-other-options easy_align.txt /*easy-align-other-options* -easy-align-partial-alignment-in-blockwise-visual-mode easy_align.txt /*easy-align-partial-alignment-in-blockwise-visual-mode* -easy-align-predefined-alignment-rules easy_align.txt /*easy-align-predefined-alignment-rules* -easy-align-related-work easy_align.txt /*easy-align-related-work* -easy-align-tldr-one-minute-guide easy_align.txt /*easy-align-tldr-one-minute-guide* -easy-align-toc easy_align.txt /*easy-align-toc* -easy-align-usage easy_align.txt /*easy-align-usage* -easy-align-using-regular-expressions easy_align.txt /*easy-align-using-regular-expressions* -easyalign easy_align.txt /*easyalign* -g:easy_align_bang_interactive_modes easy_align.txt /*g:easy_align_bang_interactive_modes* -g:easy_align_bypass_fold easy_align.txt /*g:easy_align_bypass_fold* -g:easy_align_delimiter_align easy_align.txt /*g:easy_align_delimiter_align* -g:easy_align_delimiters easy_align.txt /*g:easy_align_delimiters* -g:easy_align_ignore_groups easy_align.txt /*g:easy_align_ignore_groups* -g:easy_align_ignore_unmatched easy_align.txt /*g:easy_align_ignore_unmatched* -g:easy_align_indentation easy_align.txt /*g:easy_align_indentation* -g:easy_align_interactive_modes easy_align.txt /*g:easy_align_interactive_modes* -vim-easy-align easy_align.txt /*vim-easy-align* diff --git a/.vim/pack/plugins/start/vim-easy-align/plugin/easy_align.vim b/.vim/pack/plugins/start/vim-easy-align/plugin/easy_align.vim deleted file mode 100644 index c71af4e..0000000 --- a/.vim/pack/plugins/start/vim-easy-align/plugin/easy_align.vim +++ /dev/null @@ -1,142 +0,0 @@ -" Copyright (c) 2014 Junegunn Choi -" -" MIT License -" -" Permission is hereby granted, free of charge, to any person obtaining -" a copy of this software and associated documentation files (the -" "Software"), to deal in the Software without restriction, including -" without limitation the rights to use, copy, modify, merge, publish, -" distribute, sublicense, and/or sell copies of the Software, and to -" permit persons to whom the Software is furnished to do so, subject to -" the following conditions: -" -" The above copyright notice and this permission notice shall be -" included in all copies or substantial portions of the Software. -" -" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -" EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -" NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -" LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -" OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -" WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -if exists("g:loaded_easy_align_plugin") - finish -endif -let g:loaded_easy_align_plugin = 1 - -command! -nargs=* -range -bang EasyAlign ,call easy_align#align(0, 0, 'command', ) -command! -nargs=* -range -bang LiveEasyAlign ,call easy_align#align(0, 1, 'command', ) - -let s:last_command = 'EasyAlign' - -function! s:abs(v) - return a:v >= 0 ? a:v : - a:v -endfunction - -function! s:remember_visual(mode) - let s:last_visual = [a:mode, s:abs(line("'>") - line("'<")), s:abs(col("'>") - col("'<"))] -endfunction - -function! s:repeat_visual() - let [mode, ldiff, cdiff] = s:last_visual - let cmd = 'normal! '.mode - if ldiff > 0 - let cmd .= ldiff . 'j' - endif - - let ve_save = &virtualedit - try - if mode == "\" - if cdiff > 0 - let cmd .= cdiff . 'l' - endif - set virtualedit+=block - endif - execute cmd.":\=g:easy_align_last_command\\" - call s:set_repeat() - finally - if ve_save != &virtualedit - let &virtualedit = ve_save - endif - endtry -endfunction - -function! s:repeat_in_visual() - if exists('g:easy_align_last_command') - call s:remember_visual(visualmode()) - call s:repeat_visual() - endif -endfunction - -function! s:set_repeat() - silent! call repeat#set("\(EasyAlignRepeat)") -endfunction - -function! s:generic_easy_align_op(type, vmode, live) - if !&modifiable - if a:vmode - normal! gv - endif - return - endif - let sel_save = &selection - let &selection = "inclusive" - - if a:vmode - let vmode = a:type - let [l1, l2] = ["'<", "'>"] - call s:remember_visual(vmode) - else - let vmode = '' - let [l1, l2] = [line("'["), line("']")] - unlet! s:last_visual - endif - - try - let range = l1.','.l2 - if get(g:, 'easy_align_need_repeat', 0) - execute range . g:easy_align_last_command - else - execute range . "call easy_align#align(0, a:live, vmode, '')" - end - call s:set_repeat() - finally - let &selection = sel_save - endtry -endfunction - -function! s:easy_align_op(type, ...) - call s:generic_easy_align_op(a:type, a:0, 0) -endfunction - -function! s:live_easy_align_op(type, ...) - call s:generic_easy_align_op(a:type, a:0, 1) -endfunction - -function! s:easy_align_repeat() - if exists('s:last_visual') - call s:repeat_visual() - else - try - let g:easy_align_need_repeat = 1 - normal! . - finally - unlet! g:easy_align_need_repeat - endtry - endif -endfunction - -nnoremap (EasyAlign) :set opfunc=easy_align_opg@ -vnoremap (EasyAlign) :call easy_align_op(visualmode(), 1) -nnoremap (LiveEasyAlign) :set opfunc=live_easy_align_opg@ -vnoremap (LiveEasyAlign) :call live_easy_align_op(visualmode(), 1) - -" vim-repeat support -nnoremap (EasyAlignRepeat) :call easy_align_repeat() -vnoremap (EasyAlignRepeat) :call repeat_in_visual() - -" Backward-compatibility (deprecated) -nnoremap (EasyAlignOperator) :set opfunc=easy_align_opg@ - diff --git a/.vim/vimrc b/.vim/vimrc index 882dc60..bac0cbe 100644 --- a/.vim/vimrc +++ b/.vim/vimrc @@ -1,179 +1,13 @@ -packadd termdebug - - +" ########################################### +" # CORE BEHAVIOR +" ########################################### set nocompatible - -" mouse support set mouse= - -" real backspace, please set backspace=indent,eol,start -" disable welcome screen -set shm+=I - -" don't complain about $( ) -let g:is_posix=1 - -set number -set cursorline - -"set cursorline -set scrolloff=3 -set spelllang=de,en - -syntax on -filetype plugin on -set omnifunc=syntaxcomplete#Complete - -" colors -set t_Co=257 -set background=dark -colorscheme candle-grey-transparent -hi CursorLineNr ctermbg=NONE ctermfg=30 cterm=NONE -hi CursorLine ctermbg=NONE ctermfg=NONE cterm=NONE - -" SEARCH -set hlsearch -set ignorecase -set smartcase - -" SPACES (TABS) -set tabstop=8 -set shiftwidth=4 -let &softtabstop=&shiftwidth - -set expandtab -set smarttab - -set textwidth=72 -" set colorcolumn=72 -set formatprg=par\ -w72q - -set list -set listchars=tab:>_,trail:> -set fillchars=vert:\|,eob:\ - -" disable annoances -set noshowcmd -set noshowmode -let html_no_rendering=1 - - -let g:currentmode={ - \ 'n' : 'NORMAL', - \ 'v' : 'VISUAL', - \ 'V' : 'V·Line', - \ '^V' : 'V·Block', - \ 'i' : 'INSERT', - \ 'R' : 'R', - \ 'Rv' : 'V·Replace', - \ 'c' : 'Command', - \} - -set statusline=%#Comment# -set statusline+=[%{toupper(g:currentmode[mode()])}] -set statusline+=\ [%f] -set statusline+=%m%r%h%w%q -set statusline+=%= -set statusline+=\ [BUF:%n] -set statusline+=\ [%{&fileencoding?&fileencoding:&encoding}] -set statusline+=\ [%{&fileformat}] -set statusline+=\ [CHAR:%b/0x%B] -set statusline+=\ [ROW:%l\ COL:%c] -set statusline+=\ [%p%%] - -set laststatus=2 - -" " autocomplete -" set wildmenu -" set wildmode=longest:full,full -" -" function! CleverTab() -" if strpart( getline('.'), 0, col('.')-1 ) =~ '^\s*$' -" return "\" -" else -" return "\" -" endif -" endfunction -" inoremap =CleverTab() - -function! s:build_quickfix_list(lines) - call setqflist(map(copy(a:lines), '{ "filename": v:val, "lnum": 1 }')) - copen - cc -endfunction - -let g:fzf_layout = { 'down': '60%' } -nnoremap :Files -nnoremap :Buffers - -let g:fzf_action = { - \ 'ctrl-t': 'tab split', - \ 'ctrl-x': 'vsplit' } - -let g:fzf_vim = {} -let g:fzf_vim.tags_command = 'ksh -ic mktags' - -command! MyFiles call fzf#run(fzf#wrap({ - \ 'source': 'list-myfiles', - \ 'sink': 'edit', - \ 'options': ['--multi', '--pointer', '→', '--marker', '♡', '--preview', 'cat {}'] - \ })) - -let g:mapleader = "," -nnoremap f :Files -nnoremap b :Buffers -nnoremap l :Lines -nnoremap t :Tags -nnoremap m :MyFiles -nnoremap h :History - -let g:tagbar_ctags_bin = "ectags" -noremap tt :TagbarToggle - -" TAGS FILE -set tags=./tags;/ -"nnoremap gt :cs find 1 =expand("") -"nnoremap gs :cs find 4 =expand("") -nnoremap gb -"nnoremap gh :FSHere -nnoremap gs :call Cscope('0', expand(''), 0) -nnoremap gc :call Cscope('3', expand(''), 0) -nnoremap ge :call Cscope('6', expand(''), 0) - - -let g:fzf_tags_prompt = "Gd " -noreabbrev ts getcmdtype() == ":" && getcmdline() == 'ts' ? 'FZFTselect' : 'ts' -nmap gt (fzf_tags) - -let g:autotagTagsFile = ".tags" -let g:autotagCtagsCmd = "ectags" - - -let g:termdebugger = "egdb" - -" HIGHLIGHT SPECIAL WORDS -match ErrorMsg '\(TODO:\|FIXME\|XXX\|workaround\|WTF\|: error:.*\|\s\+$\| \+\ze\t\)' - -" DIFF -set formatoptions=crolj - -" VIMDIFF COLORS -hi DiffAdd ctermbg=22 ctermfg=NONE cterm=NONE -hi DiffDelete ctermbg=234 ctermfg=NONE cterm=NONE -hi DiffChange ctermbg=236 ctermfg=NONE cterm=NONE -hi DiffText ctermbg=red ctermfg=NONE cterm=NONE - -" SPLIT AND FOLD COLORS -hi VertSplit ctermbg=NONE ctermfg=246 cterm=NONE -hi FoldColumn ctermbg=NONE ctermfg=251 cterm=NONE -hi Folded ctermbg=233 ctermfg=251 cterm=NONE - -" SPELL COLOR -hi SpellBad ctermbg=NONE ctermfg=124 - -" TEMPORARY FILES +" ########################################### +" # TEMPORARY FILES +" ########################################### set undofile set undodir=~/.local/vim/undo// set backup @@ -182,11 +16,138 @@ set backupdir=~/.local/vim/backup// set directory=~/.local/vim/swapfiles// silent execute '!mkdir -p ~/.local/vim/backup ~/.local/vim/undo ~/.local/vim/swapfiles' +" ########################################### +" # VISUAL CHANGES +" ########################################### +set shm+=I +set noshowcmd +set noshowmode -" PLUGIN: EASY ALIGN -xmap ga (EasyAlign) -nmap ga (EasyAlign) +syntax on +filetype plugin on +set t_Co=256 +set background=dark +colorscheme candle-grey-transparent + +hi CursorLineNr ctermbg=NONE ctermfg=30 cterm=NONE +hi CursorLine ctermbg=NONE ctermfg=NONE cterm=NONE +hi SpellBad ctermbg=NONE ctermfg=124 + +match ErrorMsg '\(TODO:\|FIXME\|XXX\|workaround\|WTF\|: error:.*\|\s\+$\| \+\ze\t\)' + +" ########################################### +" # VIMDIFF +" ########################################### +set formatoptions=crolj +hi DiffAdd ctermbg=22 ctermfg=NONE cterm=NONE +hi DiffDelete ctermbg=234 ctermfg=NONE cterm=NONE +hi DiffChange ctermbg=236 ctermfg=NONE cterm=NONE +hi DiffText ctermbg=red ctermfg=NONE cterm=NONE +hi VertSplit ctermbg=NONE ctermfg=246 cterm=NONE +hi FoldColumn ctermbg=NONE ctermfg=251 cterm=NONE +hi Folded ctermbg=233 ctermfg=251 cterm=NONE + +" ########################################### +" # TOGGLES / SETTINGS +" ########################################### + +let g:is_posix=1 +let g:mapleader = "," + +set scrolloff=3 +set spelllang=de,en + +set hlsearch +set ignorecase +set smartcase + +set tabstop=8 +set shiftwidth=4 +let &softtabstop=&shiftwidth + +set expandtab +set smarttab + +set textwidth=72 +set formatprg=par\ -w72q + +"set list +"set number +"set listchars=tab:\ ,trail: +"set fillchars=vert:\|,eob:\ + +" ########################################### +" # STATUS BAR +" ########################################### + +function BufInfo() +endfunction + +set laststatus=2 +set statusline=%#Comment# +set statusline+=[%{toupper(mode())}] +set statusline+=\ <%n/%{g:bufno}> +set statusline+=%= +set statusline+=\ %f:%l:%c +set statusline+=\ %{&fileencoding?&fileencoding:&encoding}\ %{&fileformat} +set statusline+=\ 0x%B +set statusline+=\ %p%% + +" ########################################### +" # OMNI COMPLETE +" ########################################### +set omnifunc=syntaxcomplete#Complete +set wildmenu +set wildmode=longest:full,full +function! CleverTab() + if strpart( getline('.'), 0, col('.')-1 ) =~ '^\s*$' + return "\" + else + return "\" + endif +endfunction +inoremap =CleverTab() + +" ########################################### +" # TERMINAL DEBUGGER +" ########################################### +packadd termdebug +let g:termdebugger = "egdb" + +" ########################################### +" # VIM FZF +" ########################################### +let g:fzf_layout = { 'down': '60%' } +let g:fzf_action = { 'ctrl-t': 'tab split', 'ctrl-x': 'vsplit' } + +noreabbrev ts getcmdtype() == ":" && getcmdline() == 'ts' ? 'FZFTselect' : 'ts' +nmap gt (fzf_tags) + +nnoremap g :RG =expand("") +nnoremap f :Files +nnoremap b :Buffers +nnoremap t :Tags +nnoremap h :History + +" ########################################### +" # TAGBAR +" ########################################### +let g:tagbar_ctags_bin = "ectags" +noremap :TagbarToggle + +" ########################################### +" # TAGS FILE +" ########################################### +set tags=./tags;/ +nnoremap gb +nnoremap gs :call Cscope('0', expand(''), 0) +nnoremap gc :call Cscope('3', expand(''), 0) +nnoremap ge :call Cscope('6', expand(''), 0) + +" ########################################### +" # CSCOPE +" ########################################### function! LoadCscope() let db = findfile("cscope.out", ".;") if (!empty(db)) @@ -200,8 +161,21 @@ function! LoadCscope() endif endfunction + + +" ########################################### +" # EASY ALIGN +" ########################################### +xmap ga (EasyAlign) +nmap ga (EasyAlign) + +" ########################################### +" # AUTORUN +" ########################################### augroup mystuff au! + au VimResized * wincmd = + au BufEnter * let g:bufno=len(getbufinfo({'buflisted':1})) au BufEnter * call LoadCscope() au BufReadPost * if line("'\"") > 0 && line("'\"") <= line("$") | exe "normal! g'\"" | endif au BufRead,BufNewFile *.h,*.c set filetype=c.doxygen