From 0f08d04698c814955116b6bae50752e64b774d8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Romain=20Gon=C3=A7alves?= Date: Thu, 23 Dec 2021 18:28:03 +0000 Subject: Thu Dec 23 06:28:03 PM UTC 2021 --- .bin/.requirements.txt | 7 + .bin/ag-audio | 55 + .bin/ag-autorandr | 14 + .bin/ag-light | 14 + .bin/ag-lock | 21 + .bin/ag-status | 56 + .bin/ag-term | 9 + .bin/cheat | 3 + .bin/dot-bootstrap | 17 + .bin/dot-clean | 7 + .bin/dot-pkgs | 76 + .bin/dot-sync | 25 + .bin/draw-logo | 23 + .bin/dwm-start | 17 + .bin/get-mailbox-imap | 77 + .bin/get-pass | 11 + .bin/music | 70 + .bin/nmutt | 19 + .bin/nwsflux | 192 ++ .bin/oak | 180 ++ .bin/password-gen | 28 + .bin/pinentry-common | 3 + .bin/pipx-sync | 12 + .bin/qb | 130 + .bin/resume-to-pdf | 17 + .bin/screen-copy | 22 + .bin/show-pass | 22 + .bin/start-org | 25 + .bin/sync-public-dotfiles | 52 + .bin/synchronize-ereader | 21 + .bin/tenv | 87 + .bin/term-color | 36 + .bin/unlock-key | 5 + .bin/wchat | 4 + .bin/wttr | 3 + .bin/x11-config | 39 + .bin/x11-screen | 27 + .bin/yubikey-reset | 20 + .config/alacritty/alacritty.yml | 45 + .config/alacritty/hidpi.yml | 16 + .config/calcurse/conf | 32 + .config/calcurse/keys | 55 + .config/cmus/classic.theme | 48 + .config/cmus/rc | 170 ++ .config/dot/term-color-dark | 1 + .config/dot/term-color-light | 1 + .config/gopass/config.yml | 10 + .config/i3/config | 177 ++ .config/mimeapps.list | 12 + .config/neomutt/neomuttrc | 128 + .config/newsboat/config | 38 + .config/nvim/.netrwhist | 12 + .config/nvim/.nvim/autoload/plug.vim | 2526 ++++++++++++++++++++ .config/nvim/after/ftplugin/dhall.lua | 1 + .config/nvim/after/ftplugin/dockerfile.lua | 4 + .config/nvim/after/ftplugin/gitcommit.lua | 1 + .config/nvim/after/ftplugin/javascript.lua | 3 + .config/nvim/after/ftplugin/lua.lua | 6 + .config/nvim/after/ftplugin/mail.lua | 4 + .config/nvim/after/ftplugin/markdown.lua | 8 + .config/nvim/after/ftplugin/nix.lua | 6 + .config/nvim/after/ftplugin/python.lua | 1 + .config/nvim/after/ftplugin/sh.lua | 1 + .config/nvim/after/ftplugin/shell.lua | 0 .config/nvim/after/ftplugin/terraform.lua | 1 + .config/nvim/after/ftplugin/typescript.lua | 2 + .config/nvim/after/ftplugin/typescriptreact.lua | 2 + .config/nvim/after/ftplugin/yaml.lua | 6 + .config/nvim/after/indent/sass.vim | 4 + .config/nvim/colors/colorscheme.vim | 208 ++ .config/nvim/init.lua | 10 + .config/nvim/init.old.vim | 218 ++ .config/nvim/lua/ftplugin/common-markup.lua | 3 + .config/nvim/lua/ftplugin/common-space.lua | 5 + .config/nvim/lua/ftplugin/init.lua | 2 + .config/nvim/lua/keymaps.lua | 24 + .config/nvim/lua/lsp.lua | 17 + .config/nvim/lua/plugins.lua | 145 ++ .config/nvim/lua/settings.lua | 30 + .config/nvim/lua/statusline.lua | 54 + .config/nvim/lua/utils.lua | 46 + .config/qutebrowser/config.py | 111 + .config/qutebrowser/greasemonkey/boursorama-css.js | 18 + .config/qutebrowser/greasemonkey/duckduckgo.js | 12 + .config/qutebrowser/greasemonkey/github-css.js | 12 + .config/qutebrowser/greasemonkey/imgur-to-imgin.js | 8 + .../greasemonkey/instagram-to-bibliogram.js | 8 + .../qutebrowser/greasemonkey/medium-to-scribe.js | 8 + .config/qutebrowser/greasemonkey/miniflux.js | 83 + .config/qutebrowser/greasemonkey/minimal-css.js | 16 + .../qutebrowser/greasemonkey/no-sticky-headers.js | 15 + .../qutebrowser/greasemonkey/reddit-to-teddit.js | 9 + .config/qutebrowser/greasemonkey/scaleway-css.js | 11 + .config/qutebrowser/greasemonkey/scribe-css.js | 16 + .../qutebrowser/greasemonkey/stackoverflow-css.js | 15 + .../qutebrowser/greasemonkey/twitter-to-nitter.js | 9 + .../qutebrowser/greasemonkey/youtube-to-yewtube.js | 9 + .config/sway/config | 166 ++ .config/tmux/tmux.conf | 14 + .config/user-dirs.dirs | 15 + .config/user-dirs.locale | 1 + .gnupg/gpg-agent.conf | 3 + .kshrc | 13 + .public-keys/0xF85CD02DB419D68C | 109 + .weechat/buflist.conf | 41 + .weechat/fset.conf | 96 + .weechat/logger.conf | 36 + .weechat/weechat.conf | 704 ++++++ .xinitrc.dwm | 2 + .zshrc | 62 + 110 files changed, 7151 insertions(+) create mode 100755 .bin/.requirements.txt create mode 100755 .bin/ag-audio create mode 100755 .bin/ag-autorandr create mode 100755 .bin/ag-light create mode 100755 .bin/ag-lock create mode 100755 .bin/ag-status create mode 100755 .bin/ag-term create mode 100755 .bin/cheat create mode 100755 .bin/dot-bootstrap create mode 100755 .bin/dot-clean create mode 100755 .bin/dot-pkgs create mode 100755 .bin/dot-sync create mode 100755 .bin/draw-logo create mode 100755 .bin/dwm-start create mode 100755 .bin/get-mailbox-imap create mode 100755 .bin/get-pass create mode 100755 .bin/music create mode 100755 .bin/nmutt create mode 100755 .bin/nwsflux create mode 100755 .bin/oak create mode 100755 .bin/password-gen create mode 100755 .bin/pinentry-common create mode 100755 .bin/pipx-sync create mode 100755 .bin/qb create mode 100755 .bin/resume-to-pdf create mode 100755 .bin/screen-copy create mode 100755 .bin/show-pass create mode 100755 .bin/start-org create mode 100755 .bin/sync-public-dotfiles create mode 100755 .bin/synchronize-ereader create mode 100755 .bin/tenv create mode 100755 .bin/term-color create mode 100755 .bin/unlock-key create mode 100755 .bin/wchat create mode 100755 .bin/wttr create mode 100755 .bin/x11-config create mode 100755 .bin/x11-screen create mode 100755 .bin/yubikey-reset create mode 100755 .config/alacritty/alacritty.yml create mode 100755 .config/alacritty/hidpi.yml create mode 100755 .config/calcurse/conf create mode 100755 .config/calcurse/keys create mode 100755 .config/cmus/classic.theme create mode 100755 .config/cmus/rc create mode 100755 .config/dot/term-color-dark create mode 100755 .config/dot/term-color-light create mode 100755 .config/gopass/config.yml create mode 100755 .config/i3/config create mode 100755 .config/mimeapps.list create mode 100755 .config/neomutt/neomuttrc create mode 100755 .config/newsboat/config create mode 100755 .config/nvim/.netrwhist create mode 100755 .config/nvim/.nvim/autoload/plug.vim create mode 100755 .config/nvim/after/ftplugin/dhall.lua create mode 100755 .config/nvim/after/ftplugin/dockerfile.lua create mode 100755 .config/nvim/after/ftplugin/gitcommit.lua create mode 100755 .config/nvim/after/ftplugin/javascript.lua create mode 100755 .config/nvim/after/ftplugin/lua.lua create mode 100755 .config/nvim/after/ftplugin/mail.lua create mode 100755 .config/nvim/after/ftplugin/markdown.lua create mode 100755 .config/nvim/after/ftplugin/nix.lua create mode 100755 .config/nvim/after/ftplugin/python.lua create mode 100755 .config/nvim/after/ftplugin/sh.lua create mode 100755 .config/nvim/after/ftplugin/shell.lua create mode 100755 .config/nvim/after/ftplugin/terraform.lua create mode 100755 .config/nvim/after/ftplugin/typescript.lua create mode 100755 .config/nvim/after/ftplugin/typescriptreact.lua create mode 100755 .config/nvim/after/ftplugin/yaml.lua create mode 100755 .config/nvim/after/indent/sass.vim create mode 100755 .config/nvim/colors/colorscheme.vim create mode 100755 .config/nvim/init.lua create mode 100755 .config/nvim/init.old.vim create mode 100755 .config/nvim/lua/ftplugin/common-markup.lua create mode 100755 .config/nvim/lua/ftplugin/common-space.lua create mode 100755 .config/nvim/lua/ftplugin/init.lua create mode 100755 .config/nvim/lua/keymaps.lua create mode 100755 .config/nvim/lua/lsp.lua create mode 100755 .config/nvim/lua/plugins.lua create mode 100755 .config/nvim/lua/settings.lua create mode 100755 .config/nvim/lua/statusline.lua create mode 100755 .config/nvim/lua/utils.lua create mode 100755 .config/qutebrowser/config.py create mode 100755 .config/qutebrowser/greasemonkey/boursorama-css.js create mode 100755 .config/qutebrowser/greasemonkey/duckduckgo.js create mode 100755 .config/qutebrowser/greasemonkey/github-css.js create mode 100755 .config/qutebrowser/greasemonkey/imgur-to-imgin.js create mode 100755 .config/qutebrowser/greasemonkey/instagram-to-bibliogram.js create mode 100755 .config/qutebrowser/greasemonkey/medium-to-scribe.js create mode 100755 .config/qutebrowser/greasemonkey/miniflux.js create mode 100755 .config/qutebrowser/greasemonkey/minimal-css.js create mode 100755 .config/qutebrowser/greasemonkey/no-sticky-headers.js create mode 100755 .config/qutebrowser/greasemonkey/reddit-to-teddit.js create mode 100755 .config/qutebrowser/greasemonkey/scaleway-css.js create mode 100755 .config/qutebrowser/greasemonkey/scribe-css.js create mode 100755 .config/qutebrowser/greasemonkey/stackoverflow-css.js create mode 100755 .config/qutebrowser/greasemonkey/twitter-to-nitter.js create mode 100755 .config/qutebrowser/greasemonkey/youtube-to-yewtube.js create mode 100755 .config/sway/config create mode 100755 .config/tmux/tmux.conf create mode 100755 .config/user-dirs.dirs create mode 100755 .config/user-dirs.locale create mode 100755 .gnupg/gpg-agent.conf create mode 100755 .kshrc create mode 100755 .public-keys/0xF85CD02DB419D68C create mode 100755 .weechat/buflist.conf create mode 100755 .weechat/fset.conf create mode 100755 .weechat/logger.conf create mode 100755 .weechat/weechat.conf create mode 100755 .xinitrc.dwm create mode 100755 .zshrc diff --git a/.bin/.requirements.txt b/.bin/.requirements.txt new file mode 100755 index 0000000..3e69fba --- /dev/null +++ b/.bin/.requirements.txt @@ -0,0 +1,7 @@ + +# ~/.bin/.requirements.txt +# dotfiles requirements for python packages + +requests +miniflux +ansible_runner diff --git a/.bin/ag-audio b/.bin/ag-audio new file mode 100755 index 0000000..f39522f --- /dev/null +++ b/.bin/ag-audio @@ -0,0 +1,55 @@ +#!/bin/sh + +__increase() { + pamixer -i "${1:-10}" +} + +__decrease() { + pamixer -d "${1:-10}" +} + +__mic_toggle() { + pamixer --default-source -t +} + +__toggle() { + pamixer -t +} + +__next() { + cmus-remote -n +} + +__prev() { + cmus-remote -r +} + +__play() { + cmus-remote -u +} + +case "${1}" in + i*) + __increase "${2}" + ;; + d*) + __decrease "${2}" + ;; + mic-t*) + __mic_toggle + ;; + t*) + __toggle + ;; + n*) + __next + ;; + pr*) + __prev + ;; + pl*) + __play + ;; +esac + +ag-status &>/dev/null diff --git a/.bin/ag-autorandr b/.bin/ag-autorandr new file mode 100755 index 0000000..0a75819 --- /dev/null +++ b/.bin/ag-autorandr @@ -0,0 +1,14 @@ +#!/bin/sh + +screens=$(xrandr --listmonitors | tail -n +2 | rev | cut -d " " -f 1 | rev) +screen_master=$(echo "${screens}" | cut -d " " -f 1) + +logger -s reset xrandr size +xrandr -s 0 +xrandr --output "${screen_master}" --auto + +for screen in $(echo ${screens} | cut -d " " -f 2); do + xrandr --output "${screen}" --auto --right-of "${screen_master}" + echo --output "${screen}" --auto --right-of "${screen_master}" + screen_master=${screen} +done diff --git a/.bin/ag-light b/.bin/ag-light new file mode 100755 index 0000000..0d15722 --- /dev/null +++ b/.bin/ag-light @@ -0,0 +1,14 @@ +#!/bin/sh + +light -N 1 + +case "${1}" in + i*) + light -A 10 + ;; + d*) + light -U 10 + ;; +esac + +ag-status &>/dev/null diff --git a/.bin/ag-lock b/.bin/ag-lock new file mode 100755 index 0000000..e340245 --- /dev/null +++ b/.bin/ag-lock @@ -0,0 +1,21 @@ +#!/bin/sh + +set -xe + +if pgrep xidle >/dev/null; then + pkill -USR1 xidle & +elif command -v xsecurelock >/dev/null; then + xsecurelock & +fi + +if [ ! "${1}" = "-s" ]; then + exit 0 +fi + +sleep 1 + +if command -v systemctl; then + systemctl suspend +elif command -v zzz; then + ! doas -n zzz && zzz +fi diff --git a/.bin/ag-status b/.bin/ag-status new file mode 100755 index 0000000..150b9db --- /dev/null +++ b/.bin/ag-status @@ -0,0 +1,56 @@ +#!/bin/sh + +__cleanup_value() { + cat /dev/stdin | sed 's/%//g' +} + +uname=$(uname) + +battery="" +battery_status="" +time="" +volume="" + +while true; do + case "${uname}" in + OpenBSD) + battery=$(apm -l) + battery_status=$(apm | + grep "A/C" | + cut -d ":" -f 2 | + tr -d " ") + volume=$(sndioctl -n output.level | + cut -c 3-4) + ;; + Linux) + battery=$(acpi -b | + cut -d " " -f 4 | + __cleanup_value) + battery_status=$(acpi -a | + tr -s " " | + cut -d " " -f 3) + volume=$(pamixer --get-volume | + __cleanup_value) + + if $(pamixer --get-mute); then + volume_status="__mute__" + fi + ;; + esac + + time=$(date +%Y-%m-%dT%H:%M:%S) + status="VOL: ${volume}%" + + if [ -n "${battery}" ]; then + status="${status} | BATTERY ${battery}%" + fi + + status="${status} | DATE: ${time}" + + echo "${status}" + xsetroot -name " ${status}" + + [ "${1}" != "-l" ] && exit 0 + + sleep 5 +done diff --git a/.bin/ag-term b/.bin/ag-term new file mode 100755 index 0000000..2d0c6b1 --- /dev/null +++ b/.bin/ag-term @@ -0,0 +1,9 @@ +#!/bin/sh + +set -xe + +terms="alacritty st xterm" + +for term in ${terms}; do + command -v "${term}" && exec "${term}" +done diff --git a/.bin/cheat b/.bin/cheat new file mode 100755 index 0000000..cb6f4aa --- /dev/null +++ b/.bin/cheat @@ -0,0 +1,3 @@ +#!/bin/sh + +curl -s "cheat.sh/${1}" diff --git a/.bin/dot-bootstrap b/.bin/dot-bootstrap new file mode 100755 index 0000000..56840dc --- /dev/null +++ b/.bin/dot-bootstrap @@ -0,0 +1,17 @@ +#!/bin/sh + +set -x -e + +directories="git \ + downloads \ + .cache/dot \ + .cache/neomutt \ + .local/bin \ + .local/share/dot" + +remote=$(yadm remote | head -n 1) +yadm branch --set-upstream-to="${remote}/trunk" trunk + +for directory in ${directories}; do + [ ! -d "${HOME}/${directory}" ] && mkdir -p "${HOME}/${directory}" +done diff --git a/.bin/dot-clean b/.bin/dot-clean new file mode 100755 index 0000000..5b326ea --- /dev/null +++ b/.bin/dot-clean @@ -0,0 +1,7 @@ +#!/bin/sh + +clean_files="*.core" + +for file in ${clean_files}; do + find "${HOME}" -maxdepth 2 -iname "*.core" -exec rm {} \; +done diff --git a/.bin/dot-pkgs b/.bin/dot-pkgs new file mode 100755 index 0000000..f5c80ee --- /dev/null +++ b/.bin/dot-pkgs @@ -0,0 +1,76 @@ +#!/usr/bin/env python3 + +import subprocess +import os + +ENV = { + 'path': f'{os.environ["HOME"]}/.cache/dot-pkgs', + 'bin_path': f'{os.environ["HOME"]}/.local/bin' +} + +PKGS = [ + { + 'src': 'git://git.suckless.org/dwm', + 'path': f'{ENV["path"]}/dwm', + 'bin': 'dwm', + 'type': 'git' + }, + { + 'src': 'git://git.suckless.org/st', + 'path': f'{ENV["path"]}/st', + 'bin': 'st', + 'type': 'git' + }, + { + 'src': 'git@st0dev1:_suckless/dwm', + 'path': f'{os.environ["HOME"]}/git.rgoncalves.se/_suckless/dwm', + 'bin': 'st', + 'type': 'git' + }, + { + 'src': '', + 'type': '' + } +] + + +def copy_executable_file(src, dst): + pass + + +def merge_mappings(pkgs, env): + """ + Merge two dict in the first one. + """ + for index, pkg in enumerate(pkgs): + pkgs[index] = {**env, **pkg} + + +def handle_git(pkg): + """ + Clone and update git repo. + """ + commands = [ + ['git', 'clone', pkg['src'], pkg['path']], + ['git', 'pull'] + ] + + for command in commands: + subprocess.run(command, cwd=pkg['path']) + + +def handle_make(pkg): + subprocess.run(['make'], cwd=pkg['path']) + + +def main(): + merge_mappings(PKGS, ENV) + + for pkg in [pkg for pkg in PKGS if pkg['type'] == 'git']: + os.makedirs(pkg['path'], exist_ok=True) + handle_git(pkg) + handle_make(pkg) + + +if __name__ == '__main__': + main() diff --git a/.bin/dot-sync b/.bin/dot-sync new file mode 100755 index 0000000..7f4d490 --- /dev/null +++ b/.bin/dot-sync @@ -0,0 +1,25 @@ +#!/bin/sh + +set -x -e + +export GIT_SSH_COMMAND="ssh -o ConnectTimeout=1 -o ConnectionAttempts=1" + +yadm pull + +yadm add -u +yadm add \ + $HOME/.bin \ + $HOME/.config/i3 \ + $HOME/.config/neomutt \ + $HOME/.config/newsboat \ + $HOME/.config/nvim \ + $HOME/.config/qutebrowser/{*.py,greasemonkey} \ + $HOME/.config/sway \ + $HOME/.config/yadm \ + $HOME/.config/waybar \ + $HOME/.public-keys + +yadm push + +yadm commit -m "$(date +%Y-%m-%dT%H:%M:%S)" +yadm push diff --git a/.bin/draw-logo b/.bin/draw-logo new file mode 100755 index 0000000..d65bf8f --- /dev/null +++ b/.bin/draw-logo @@ -0,0 +1,23 @@ +#!/bin/sh + +set -xe + +circle_coordinates="256,256,256" +background_color="white" +foreground_color="black" + +convert -size 512x512 \ + "xc:${backgrond_color}" \ + -fill "${foreground_color}" \ + -draw "circle ${circle_coordinates},32" \ + -fill "${background_color}" \ + -draw "circle ${circle_coordinates},96" \ + "${1}.png" + +convert "${1}.png" -resize "50%" "${1}-medium.png" +convert "${1}.png" -resize "25%" "${1}-small.png" + +convert "${1}-small.png" \ + -level -10%,12% \ + -ordered-dither o8x8 \ + "${1}-dithered.png" diff --git a/.bin/dwm-start b/.bin/dwm-start new file mode 100755 index 0000000..e411db5 --- /dev/null +++ b/.bin/dwm-start @@ -0,0 +1,17 @@ +#!/bin/sh + +kill -9 xidle +xidle & + +while true; do + # status + pkill -9 -f "ag-status" + ag-status -l >/dev/null & + + # x11 configuration + x11-config + . ~/.bin/x11-screen + + # dwm + dwm 2> ~/.dwm.log +done diff --git a/.bin/get-mailbox-imap b/.bin/get-mailbox-imap new file mode 100755 index 0000000..fad7e21 --- /dev/null +++ b/.bin/get-mailbox-imap @@ -0,0 +1,77 @@ +#!/usr/bin/env python3 + +import imaplib +import sys + + +def get_boxes(list): + """ + Retrieve and decode all mailboxes. + """ + return [box.decode('utf-8').rsplit(' ')[-1] for box in list] + + +def flatten_output(list): + """ + Print all boxes with a flattened output, + primarily for neomutt usage. + """ + print(''.join([f"+'{box}' " for box in list]), end=' ') + + +def sort_boxes(bxs): + """ + Sort boxes list, + according to a predefined order + """ + + order = [ + "INBOX", + "Unread", + "Drafts", + "Sent", + "Spam", + "Trash", + "Junk", + "Archive" + ] + + bxs_orig = sorted(bxs) + + # sort based on predefined order + bxs = [] + for exp in order: + matching = [s for s in bxs_orig if exp in s] + bxs.extend(matching) + + # ensure all retrieved boxes are present + for bx in bxs_orig: + if bx not in bxs: + bxs.append(bx) + + return bxs + + +def main(): + """ + Retrieve, sort, and pretty print for neomutt + """ + + # user information + remote = sys.argv[1] + username = sys.argv[2] + password = sys.argv[3] + + # connection + mail = imaplib.IMAP4_SSL(remote) + mail.login(username, password) + + # parse folders output + bxs = sort_boxes(get_boxes(mail.list()[1])) + + # oneline pretty-print for neomutt + flatten_output(bxs) + + +if __name__ == "__main__": + main() diff --git a/.bin/get-pass b/.bin/get-pass new file mode 100755 index 0000000..4cdeafd --- /dev/null +++ b/.bin/get-pass @@ -0,0 +1,11 @@ +#!/bin/sh + +set -e + +[ ${#} -ne 0 ] + +password_file=$(gopass ls --flat | grep "${@}" | head -n 1) +[ "${password_file}" ] + +echo "+ password: ${password_file}" >&2 +exec gopass show -o "${password_file}" diff --git a/.bin/music b/.bin/music new file mode 100755 index 0000000..5498dc0 --- /dev/null +++ b/.bin/music @@ -0,0 +1,70 @@ +#!/bin/sh + + +MUSIC_DIR="${HOME}/music" +MUSIC_LIST= +MUSIC_FILE= +MUSIC_YT_OPTIONS= + +log() { + echo "[${0} ] ${@}" +} + +main() { + # arguments + while getopts "c:" arg; do + case "${arg}" in + c) + MUSIC_FILE="${OPTARG}" + ;; + h) + exit 0 + ;; + esac + done + + # ensure parameters are correct + [ ! -f "${MUSIC_FILE}" ] && exit 1 + + + while read -r line; do + + # skip comments + line=$(echo ${line} | grep -v -e "^$" -e "^#") + [ -z "${line}" ] && continue + + # retrieve playlist params + url=$(echo "${line}" | cut -d " " -f 1) + dir=$(echo "${line}" | cut -d " " -f 2) + + dir="${MUSIC_DIR}/${dir}" + + [ -d "${dir}" ] && + log "${dir}: directory already exists" && + continue + + mkdir "${dir}" + log "${dir} ${url}: download" + + youtube-dl --rm-cache-dir >/dev/null + youtube-dl \ + --extract-audio \ + --audio-format mp3 \ + --prefer-ffmpeg \ + --audio-quality 0 \ + --embed-thumbnail \ + --metadata-from-title "%(artist)s - %(title)s" \ + --no-warnings \ + --ignore-errors \ + --no-overwrites \ + --continue \ + --add-metadata \ + --user-agent "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" \ + --output "${dir}/'%(title)s.%(ext)s'" \ + "${url}" + + + done < "${MUSIC_FILE}" +} + +main ${@} diff --git a/.bin/nmutt b/.bin/nmutt new file mode 100755 index 0000000..9a2bb28 --- /dev/null +++ b/.bin/nmutt @@ -0,0 +1,19 @@ +#!/bin/sh + +NMUTT_CONFIGURATION_FILE="${HOME}/.config/neomutt/personal" + +get_param() { + grep "${2}" "${1}" | + head -n 1 | + rev | + cut -d " " -f 1 | + rev | + tr -d '"' +} + +# export server/username for get-mailbox-imap script +export MAIL_SERVER=$(get_param "${NMUTT_CONFIGURATION_FILE}" "my_server") +export MAIL_USERNAME=$(get_param "${NMUTT_CONFIGURATION_FILE}" "my_user") + +export MAIL_PASSWORD=$(get-pass "mailbox") +exec neomutt ${@} diff --git a/.bin/nwsflux b/.bin/nwsflux new file mode 100755 index 0000000..3e725b0 --- /dev/null +++ b/.bin/nwsflux @@ -0,0 +1,192 @@ +#!/usr/bin/env python3 +# +# nwsflux + +import miniflux +import urllib3 +import logging +import os +import re +import shlex +import argparse + + +def get_local_feed(line: str) -> dict: + """ + Parse a line and return a constructed dict like miniflux's API. + """ + feed_url = shlex.split(line)[0] + title = shlex.split(line)[-1] + tag = shlex.split(line)[1] + if tag == title: + tag = 'all' + + return { + 'feed_url': feed_url, + 'title': title, + 'category': { + 'title': tag + } + } + + +def get_local_feeds(filename: str) -> list: + """ + Read feeds from a newsboat url file. + """ + + with open(filename, 'r') as f: + content = f.readlines() + + r = re.compile('^http.*://') + content = list(filter(r.match, content)) + + return [get_local_feed(line) for line in content] + + +def delete_categories(client: miniflux.Client, local_cats: dict, remote_cats: dict): + """ + Remove remote categories that are absent in local file. + + . Useless for now, miniflux's API return non-empty categories only! + """ + for remote in remote_cats: + if any(local['title'] == remote['title'] for local in local_cats): + continue + try: + logging.info(f'remove category: {remote["title"]}') + client.delete_category(remote['id']) + # ignores categories that are empty on remote + except miniflux.ClientError as e: + logging.error('can not remove non-empty category:' + f'{remote["title"]} {e}') + + +def create_categories(client: miniflux.Client, local_cats: dict, remote_cats: dict): + """ + Create categories present in local file and absent on remote. + """ + for local in local_cats: + if any(remote['title'] == local['title'] for remote in remote_cats): + continue + try: + logging.info(f'create category: {local["title"]}') + client.create_category(local['title']) + # ignores categories that are empty on remote + except miniflux.ClientError as e: + logging.error(f'remote category empty: {local["title"]} {e}') + + +def sync_categories(client: miniflux.Client, local_feeds: dict, remote_feeds: dict) -> dict: + local_cats = get_uniq_categories(local_feeds) + remote_cats = get_uniq_categories(remote_feeds) + + delete_categories(client, local_cats, remote_cats) + create_categories(client, local_cats, remote_cats) + return client.get_categories() + + +def get_uniq_categories(buffer: list) -> list: + return list(map(dict, frozenset( + frozenset(x['category'].items()) for x in buffer + ))) + + +def delete_feeds(client: miniflux.Client, local_feeds: dict, remote_feeds: dict): + """ + Remove remote feeds that are absent in local file. + """ + for remote in remote_feeds: + if any(local['feed_url'] == remote['feed_url'] for local in local_feeds): + continue + logging.info(f'remove feed: {remote["feed_url"]}') + client.delete_feed(remote['id']) + + +def create_feeds(client: miniflux.Client, local_feeds: dict, remote_feeds: dict): + """ + Create feeds that are present in local file and absent on remote. + """ + categories = client.get_categories() + + for local in local_feeds: + if any(remote['feed_url'] == local['feed_url'] for remote in remote_feeds): + continue + logging.info(f'create feed: {local}') + category_id = next((x['id'] for x in categories if x['title'] == local['category']['title']), None) + try: + client.create_feed(local['feed_url'], category_id) + except miniflux.ClientError as e: + logging.error(e) + + +def sync_feeds(client: miniflux.Client, local_feeds: dict, remote_feeds: dict) -> dict: + """ + Synchronize all given feeds. + """ + delete_feeds(client, local_feeds, remote_feeds) + create_feeds(client, local_feeds, remote_feeds) + return client.get_feeds() + + +def parse(): + """ + Parse command-line arguments. + """ + parser = argparse.ArgumentParser(description='Synchronize RSS feeds from' + 'newsboat to an miniflux instance.') + + parser.add_argument('-c', dest='config', type=str, required=True, + help='Newsboat url file') + parser.add_argument('-k', dest='key', type=str, required=True, + help='Miniflux API key') + parser.add_argument('-u', dest='url', type=str, required=True, + help='Miniflux url') + parser.add_argument('-d', dest='debug', action='store_true', + help='Enable debugging output') + parser.add_argument('-e', dest='export', action='store_true', + help='Export Miniflux OPML config to stdout') + + return parser.parse_args() + + +def main(): + + """ + SSL verify. + """ + os.environ["CURL_CA_BUNDLE"] = "" + urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) + + """ + Arguments. + """ + args = parse() + + """ + Debugging. + """ + logging.basicConfig(level=logging.INFO) + if not args.debug: + logging.level = logging.NOTSET + + """ + Synchronization. + """ + client = miniflux.Client(args.url, api_key=args.key) + + local_feeds = get_local_feeds(args.config) + remote_feeds = client.get_feeds() + + sync_categories(client, local_feeds, remote_feeds) + sync_feeds(client, local_feeds, remote_feeds) + + """ + Export Miniflux to OPML. + """ + if args.export: + print(client.export_feeds()) + + +if __name__ == '__main__': + main() diff --git a/.bin/oak b/.bin/oak new file mode 100755 index 0000000..4ea560e --- /dev/null +++ b/.bin/oak @@ -0,0 +1,180 @@ +#!/bin/sh +# _ +# | | +# __ __, | | +# / \_/ | |/_) +# \__/ \_/|_/| \_/ +# +# ~/.bin/oak +# +# manage multiple dotfiles repo in same work tree +# +# Example: +# dotfiles.d/ +# |_ config +# |_ secret +# +# ~ rgoncalves.se + +usage() { + cat <<- EOF + USAGE ${0} : git_dirname git_action [arguments...] + -b: enable bootstraping for absent repository + -d: oak directory to work on + works in batch mode if no directory is provided + -f: force all operations + use with caution + -m: commit message when using -s option + commits_msg_have_to_be_written_like_this + -r: git remote with full path to parent directory + -h: show usage of ${0} + EOF +} + +log() { + echo "[OAK ] ${@}" +} + +git_chroot() { + log ">> ${1}" + git --git-dir="${OAK_ROOT}/${1}" --work-tree="${HOME}" ${2} +} + +git_bootstrap() { + # directory url remote + git_chroot "${1}" "clone --bare git@${2}/${1} ${OAK_ROOT}/${1}" + [ "${?}" -ne 0 ] && log "Failed to bootstrap ${1}" && exit 1 + git_chroot "${1}" "checkout trunk" >/dev/null 2>&1 + git_chroot "${1}" "branch --set-upstream-to trunk origin/trunk" >/dev/null 2>&1 + git_chroot "${1}" "push -u origin trunk" >/dev/null 2>&1 +} + +git_sync() { + # actions + git_sane_all + pull_out=$(git_chroot "${1}" "pull") + if [ "${?}" -ne 0 ]; then + log "error while doing git pull" + exit 1 + fi + echo "${pull_out}" 2>&1 | grep " ." + git_chroot "${1}" "add -u" >/dev/null + git_chroot "${1}" "commit -m ${OAK_MSG}" + git_chroot "${1}" "push --set-upstream origin trunk" + # cleanup + unset pull_out push_out +} + +git_list() { + log "Available repositories : " + for dir in ${OAK_DIRS}; do + log " - ${dir}" + done +} + +git_sane() { + if [ "${1}" = "${2}" ]; then + return 1 + fi + git_chroot "${1}" "ls-files" > ~/.cache/oak_a + git_chroot "${2}" "ls-files" > ~/.cache/oak_b + out=$(grep -F -x -f ~/.cache/oak_a ~/.cache/oak_b) + if [ -n "${out}" ]; then + log "detected similar files for directories: ${repo_a}, ${repo_b}" + echo "${out}" + return 1 + fi + return 0 +} + +git_sane_all() { + for repo_a in ${DOT_DIRS}; do + for repo_b in ${DOT_DIRS}; do + if [ "${repo_a}" = "${repo_b}" ]; then + continue + fi + git_sane "${DOT_ROOT}/${repo_a}" "${DOT_ROOT}/${repo_b}" + if [ "${?}" -ne 0 ]; then + log "aborting" + exit 1 + fi + done + done +} + +main() { + + OAK_ROOT="${HOME}/.dotfiles.d" + OAK_DIRS=$(ls "${OAK_ROOT}") + OAK_DIR="" + OAK_REMOTE="" + OAK_CMD="" + OAK_MSG="" + + # Retrieve oak params + while getopts "bd:hlm:r:s" arg; do + case "${arg}" in + b) + OAK_BOOTSTRAP=1 + ;; + d) + OAK_DIR="${OPTARG}" + ;; + f) + OAK_FORCE=1 + ;; + h) + usage && exit 0 + ;; + m) + OAK_MSG="$(echo ${OPTARG} | tr -s '_' ' ')" + ;; + l) + git_list + exit 0 + ;; + r) + OAK_REMOTE="${OPTARG}" + ;; + s) + OAK_SYNC=1 + ;; + esac + done + + [ -z "${OAK_MSG}" ] && OAK_MSG=$(date +%j_%H_%M_%S) + + # Bootstrap non-present repositories + if [ -n "${OAK_DIR}" ] && [ ! -d "${OAK_ROOT}/${OAK_DIR}" ]; then + git_bootstrap "${OAK_DIR}" "${OAK_REMOTE}" + if [ "${?}" -ne 0 ]; then + log "Git repository does not exist. Error" + exit 1 + fi + log "Successfully bootstraped git repository" + fi + + # Retrieve oak command for git + shift $(expr "${OPTIND}" - 1) + for cmd in "${@}"; do + OAK_CMD="${OAK_CMD}${cmd} " + done + + # Git synchronization in each repository + if [ -n "${OAK_SYNC}" ]; then + for dir in ${OAK_DIR:-$OAK_DIRS}; do + log "synchronize ${dir}" + git_sync "${dir}" + done + fi + + # Raw command in each git repository + if [ -n "${OAK_CMD}" ]; then + for dir in ${OAK_DIR:-$OAK_DIRS}; do + git_chroot "${dir}" "${OAK_CMD}" + done + fi + +} + +main $@ diff --git a/.bin/password-gen b/.bin/password-gen new file mode 100755 index 0000000..e29dcb5 --- /dev/null +++ b/.bin/password-gen @@ -0,0 +1,28 @@ +#!/bin/sh + +pass_length="24" + +usage() { + cat <<-EOF + usage: pagen [-l pass_length] + EOF +} + +main() { + while getopts "l:" arg; do + case "${arg}" in + l) + pass_length="${OPTARG-$pass_length}" + ;; + *) + usage + exit 1 + ;; + esac + done + + # generate and display password + openssl rand -base64 "${pass_length}" +} + +main $@ diff --git a/.bin/pinentry-common b/.bin/pinentry-common new file mode 100755 index 0000000..c97af72 --- /dev/null +++ b/.bin/pinentry-common @@ -0,0 +1,3 @@ +#!/bin/sh + +exec pinentry-curses diff --git a/.bin/pipx-sync b/.bin/pipx-sync new file mode 100755 index 0000000..181768e --- /dev/null +++ b/.bin/pipx-sync @@ -0,0 +1,12 @@ +#!/bin/sh + +set -x -e + +packages="pywal + ipython" + +pipx upgrade-all + +for package in ${packages}; do + pipx install "${package}" || true +done diff --git a/.bin/qb b/.bin/qb new file mode 100755 index 0000000..3caf57e --- /dev/null +++ b/.bin/qb @@ -0,0 +1,130 @@ +#!/usr/bin/env python3 + +import os +import sys +import yaml + + +def bypass_file_exists(func, *args): + """ + Exceptions for existing files are ignored. + """ + try: + func(*args) + except FileExistsError as e: + print(e) + + +def start_qutebrowser(args): + """ + Replace the current process with qutebrowser. + """ + os.execvp('qutebrowser', args) + + +def generate_tab(url): + full_url = f'https://{url}' + + return { + 'active': True, + 'history': [{ + 'active': True, + 'pinned': True, + 'last_visited': '2021-09-16T12:22:57', + 'scroll-pos': {'x': 0, 'y': 0}, + 'zoom': 1.0, + 'title': url, + 'original-url': full_url, + 'url': full_url + }] + } + + +def restore_default_tabs(profile, path=None): + """ + Declarative way to enforce opened/favorite tabs. + """ + mapping = { + 'default': [ + 'mailbox.org', + 'news.ycombinator.com', + 'miniflux.rgoncalves.se', + 'status.rgoncalves.se' + ], + 'work': [ + 'mail.zoho.eu', + 'cliq.zoho.eu', + 'gitlab.viperdev.io', + 'projects.zoho.eu', + 'kb.viperdev.io', + ] + } + + assert mapping[profile] + + # Open file an cleanup + with open(path, 'r') as file: + data = yaml.safe_load(file) + + # Scrap existing tabs, + # then filter pinned tabs + original_tabs = data['windows'][0]['tabs'] + tabs = [tab['history'][-1] for tab in original_tabs + if len(tab['history']) != 0] + tabs = [tab for tab in tabs if tab['pinned']] + + missing_urls = [url for url in mapping[profile] + if not any(url in tab['url'] for tab in tabs)] + + for url in missing_urls: + original_tabs.append(generate_tab(url)) + + original_tabs.sort(reverse=True, key=lambda k: k['history'][-1]['pinned']) + + # Persist tabs in yaml file + with open(path, 'w') as file: + yaml.dump(data, file) + + +def main(): + try: + QB_PROFILE = f'{sys.argv[1]}' + except IndexError: + QB_PROFILE = 'default' + + """ + restore_default_tabs( + QB_PROFILE, + path=f'{os.environ["HOME"]}/' + + '.local/share/qutebrowser/sessions/default.yml' + ) + """ + start_qutebrowser([' ']) + sys.exit(0) + + QB_DIR = f'{os.environ["HOME"]}/.config/qutebrowser' + QB_PROFILES_DIR = f'{QB_DIR}/_profiles' + QB_PROFILE_DIR = f'{QB_PROFILES_DIR}/{QB_PROFILE}' + QB_PROFILE_DIR_CONFIG = f'{QB_PROFILE_DIR}/config' + QB_PROFILE_TAG = QB_PROFILE[0].lower() + + # Ensure directory existence + for dir in [QB_PROFILES_DIR, QB_PROFILE_DIR, QB_PROFILE_DIR_CONFIG]: + bypass_file_exists(os.mkdir, dir) + + # Ensure common files are shared with other profiles + for file in ['config.py', 'bookmarks', 'greasemonkey']: + bypass_file_exists(os.symlink, + f'{QB_DIR}/{file}', + f'{QB_PROFILE_DIR_CONFIG}/{file}') + + start_qutebrowser([ + ' ', '--basedir', QB_PROFILE_DIR, + '--set', 'window.title_format', f'[{QB_PROFILE_TAG}]', + '--set', 'tabs.title.format', + f'[{QB_PROFILE_TAG}] {{audio}}{{index}}: {{current_title}}' + ]) + + +if __name__ == '__main__': + main() diff --git a/.bin/resume-to-pdf b/.bin/resume-to-pdf new file mode 100755 index 0000000..04dfba8 --- /dev/null +++ b/.bin/resume-to-pdf @@ -0,0 +1,17 @@ +#!/bin/sh + +src="https://rgoncalves.se/a/resume.html" +out="resume.pdf" +margin="2cm" + +wkhtmltopdf --page-size A4 \ + --orientation portrait \ + --dpi 300 \ + --image-dpi 300 \ + --image-quality 100 \ + --margin-top "${margin}" \ + --margin-right "${margin}" \ + --margin-bottom "${margin}" \ + --margin-left "${margin}" \ + "${src}" \ + "${out}" diff --git a/.bin/screen-copy b/.bin/screen-copy new file mode 100755 index 0000000..9078dfb --- /dev/null +++ b/.bin/screen-copy @@ -0,0 +1,22 @@ +#!/bin/sh +# +# Copy screen area to clipboard + +. ~/.bin/tenv + +main() { + filename="/tmp/screenshot-$(date +%F_%T).png" + + case "${_DISPLAY_SERVER}" in + xorg) + scrot -s "${filename}" + xclip -selection clip -t image/png "${filename}" + ;; + *) + echo " display server not supported" >&2 + ;; + esac + +} + +main $@ diff --git a/.bin/show-pass b/.bin/show-pass new file mode 100755 index 0000000..568570e --- /dev/null +++ b/.bin/show-pass @@ -0,0 +1,22 @@ +#!/bin/sh + +usage () { + cat >&2 <<-EOF + usage: ${0} password_regexp + EOF +} + +log () { + echo ["${0}"] $@ >&2 +} + +main() { + # verify arguments + [ "${#}" -ne 1 ] && usage && exit 1 + + # retrieve password + log "retrieving password for : ${1}" + gopass show --password $(gopass ls --flat | grep "${1}" | head -n 1) +} + +main $@ diff --git a/.bin/start-org b/.bin/start-org new file mode 100755 index 0000000..c32b99e --- /dev/null +++ b/.bin/start-org @@ -0,0 +1,25 @@ +#!/bin/sh + +set -xe + +session_name="org" +windows="wchat:weechat + nmutt:neomutt + calcurse:calcurse" + +if [ "${1}" = "-f" ]; then + tmux kill-session -t "${session_name}" +fi + +tmux new-session -s "${session_name}" -d + +for window in ${windows}; do + window_cmd=$(echo "${window}" | cut -d ":" -f 1) + window_name=$(echo "${window}" | cut -d ":" -f 2) + + tmux new-window -n "${window_name}" + tmux send-keys -t "${session_name}:${window_name}" \ + "${window_cmd} " +done + +tmux a -t "${session_name}" diff --git a/.bin/sync-public-dotfiles b/.bin/sync-public-dotfiles new file mode 100755 index 0000000..7bff64f --- /dev/null +++ b/.bin/sync-public-dotfiles @@ -0,0 +1,52 @@ +#!/bin/sh + +set -e + +command -v yadm git + +allowed_patterns="-e ^.bin + -e ^.config/alacritty/ + -e ^.config/calcurse/ + -e ^.config/cmus/classic.theme + -e ^.config/cmus/rc + -e ^.config/dot/term-color-* + -e ^.config/gopass/config.yml + -e ^.config/i3*/config + -e ^.config/tmux/ + -e ^.config/mimeapps.list + -e ^.config/neomutt/neomuttrc + -e ^.config/newsboat/config + -e ^.config/nvim/ + -e ^.config/qutebrowser/config.py + -e ^.config/qutebrowser/greasemonkey/ + -e ^.config/sway/config + -e ^.config/systemd/*.service + -e ^.config/user-dirs.dir + -e ^.config/user-dirs.locale + -e ^.gnupg/gpg-agent.conf + -e ^.public-keys/ + -e ^.kshrc + -e ^.weechat/buflist.conf + -e ^.weechat/fset.conf + -e ^.weechat/logger.conf + -e ^.weechat/weechat.conf + -e ^.xinitrc + -e ^.zshrc + " + +[ "$(yadm rev-parse --show-toplevel)" != "$(git rev-parse --show-toplevel)" ] + +# retrieve existing files +upstream_files=$(cd "${HOME}" && yadm ls-files) +local_files=$(find . -not -path "./.git*" -not -path ".") + +echo "${local_files}" | xargs rm -rf + +allowed_files=$(echo "${upstream_files}" | grep ${allowed_patterns}) +for allowed_file in ${allowed_files}; do + echo "${allowed_file}" + install -D "${HOME}/${allowed_file}" "${allowed_file}" +done + +git add . +git commit -m "$(date)" diff --git a/.bin/synchronize-ereader b/.bin/synchronize-ereader new file mode 100755 index 0000000..482a846 --- /dev/null +++ b/.bin/synchronize-ereader @@ -0,0 +1,21 @@ +#!/bin/sh + +set -xe + +src_dir=$(readlink -f "${1}") +out_dir=$(readlink -f "${2}") + +[ -d "${src_dir}" ] +[ -d "${out_dir}" ] + +rsync -hvrPt \ + --delete-after \ + --fuzzy \ + --prune-empty-dirs \ + --include "*.pdf" \ + --include "*.epub" \ + --include "*.png" \ + --include "*.jpg" \ + --include "*/" \ + --exclude "*" \ + "${src_dir}/" "${out_dir}/" diff --git a/.bin/tenv b/.bin/tenv new file mode 100755 index 0000000..7718d89 --- /dev/null +++ b/.bin/tenv @@ -0,0 +1,87 @@ +#!/bin/sh +# +# o +# _|_ _ _ _ _ _ +# | | / |/ | | | |/ / |/ | | |_ +# |_/|_/ | |_/ \_/|/ |__/ | |_/ \/ +# /| +# \| +# +# tiny env +# scraps system and user's configuration, +# providing unified env. variables accross exotic setup. +# +# ~ rgoncalves.se + +log() { + echo [] "${@}" +} + +usage() { + cat <<-EOF + usage: tinyenv [-d] + EOF +} + +get_os_distribution() { + # tmp + os=$(uname | tr "[:upper:]" "[:lower:]") + distribution=$(uname -r) + # logic + case "${os}" in + linux) + distribution=$(uname -r) + ;; + esac + # return + export _OS_DISTRIBUTION="${os}_${distribution}" + unset -v os distribution +} + +get_display() { + # tmp + list="wayland Xorg" + # logic + for display in ${list}; do + # search display and skip export if not found + pgrep "${display}" >/dev/null + [ "${?}" -ne 0 ] && display="none" && continue + # found display server + break + done + # return + export _DISPLAY_SERVER=$(echo "${display}" | tr "[:upper:]" "[:lower:]") + unset -v list display +} + +get_screens() { + # tmp + screens="1" + # logic + [ "${_DISPLAY_SERVER}" = "xorg" ] && \ + screens=$(xrandr | grep " connected" | wc -l | tr -d " ") + # return + export _SCREENS="${screens}" + unset screens +} + +show_env() { + list=$(env | grep "^_.*" | sort -n) + for el in ${list}; do + log "${el}" + done + unset -v list el +} + +main() { + + # must be first + get_os_distribution + # alpha/numeric ordered + get_display + get_screens + + [ -n "${DEBUG}" ] && show_env +} + +main $@ diff --git a/.bin/term-color b/.bin/term-color new file mode 100755 index 0000000..45a2dcc --- /dev/null +++ b/.bin/term-color @@ -0,0 +1,36 @@ +#!/bin/sh + +set -xe + +sequences="${HOME}/.config/dot/term-color" +cache_file="${HOME}/.cache/dot/sequences" + +if [ "${1}" = "-l" ]; then + sequences="${sequences}-light" +else + sequences="${sequences}-dark" +fi + +[ -f "${sequences}" ] + +case $(uname) in + OpenBSD) + ttys=$(ps | + tail -n +2 | + tr -s " " | + sed 's/^ //g' | + cut -d " " -f 2 | + sed 's/-$//g' | + uniq | + sed 's/^/\/dev\/tty/g') + ;; + Linux) + ttys=$(find /dev/pts -iname "[0-9]*") + ;; +esac + +for tty in $ttys; do + [ -c "${tty}" ] && cat "${sequences}" > $tty +done + +cp "${sequences}" "${cache_file}" diff --git a/.bin/unlock-key b/.bin/unlock-key new file mode 100755 index 0000000..d0bebbf --- /dev/null +++ b/.bin/unlock-key @@ -0,0 +1,5 @@ +#!/bin/sh + +set -xe + +gopass show -c .buffer 2>/dev/null diff --git a/.bin/wchat b/.bin/wchat new file mode 100755 index 0000000..83f13a3 --- /dev/null +++ b/.bin/wchat @@ -0,0 +1,4 @@ +#!/bin/sh + +export WEECHAT_PASSPHRASE="$(get-pass weechat)" +exec weechat $@ diff --git a/.bin/wttr b/.bin/wttr new file mode 100755 index 0000000..c06c825 --- /dev/null +++ b/.bin/wttr @@ -0,0 +1,3 @@ +#!/bin/sh + +curl -s "wttr.in/${1}?m" diff --git a/.bin/x11-config b/.bin/x11-config new file mode 100755 index 0000000..5230c13 --- /dev/null +++ b/.bin/x11-config @@ -0,0 +1,39 @@ +#!/bin/sh + +set -xe + +wallpaper_file="${HOME}/.local/share/dot/wallpaper" +synclient_options="TapButton1=1 \ + TapButton2=3 \ + TapButton3=2 \ + PalmDetect=1 \ + TouchpadOff=0" + +# synaptic +if command -v syndaemon; then + pkill syndaemon && syndaemon -RKd -i 0.2 + synclient ${synclient_options} +fi + +# keyboard +xset r rate 250 75 +setxkbmap -option compose:ralt + +# screen saving +xset s off +xset s noblank +xset -dpms + +if [ $(uname -s) = "OpenBSD" ]; then + xinput set-prop "/dev/wsmouse" "WS Pointer Wheel Emulation" 1 + xinput set-prop "/dev/wsmouse" "WS Pointer Wheel Emulation Button" 2 + xinput set-prop "/dev/wsmouse" "WS Pointer Wheel Emulation Axes" 6 7 4 5 +fi + +# background +xsetroot -mod 2 2 -fg white -bg black +xsetroot -grey + +if [ -f "${wallpaper_file}" ]; then + feh --bg-scale "${wallpaper_file}" +fi diff --git a/.bin/x11-screen b/.bin/x11-screen new file mode 100755 index 0000000..ccccda7 --- /dev/null +++ b/.bin/x11-screen @@ -0,0 +1,27 @@ +#!/bin/sh + +__hidpi() { + xrdb -merge ~/.Xresources.hidpi + + export GDK_SCALE=2 + export GDK_DPI_SCALE=0.5 + export GDK_SCALE=2 + export QT_SCREEN_SCALE_FACTORS=2 + export QT_AUTO_SCREEN_SCALE_FACTOR=1 + export QT_QPA_PLATFORMTHEME=qt5ct +} + +hostname=$(uname -n) + +xrandr -s 0 +xrdb ~/.Xresources + +if [ "${hostname}" = "ws-bare01" ]; then + xrandr --output HDMI-0 --left-of DVI-D-0 +fi + +if [ "${hostname}" = "ws-xps01" ]; then + xrandr --output eDP1 --mode 3200x1800 + echo a + __hidpi +fi diff --git a/.bin/yubikey-reset b/.bin/yubikey-reset new file mode 100755 index 0000000..4824bc8 --- /dev/null +++ b/.bin/yubikey-reset @@ -0,0 +1,20 @@ +echo "DESTRUCTIVE !!!" + +sleep 60 + +gpg-connect-agent < +raise-priority + +lower-priority - diff --git a/.config/cmus/classic.theme b/.config/cmus/classic.theme new file mode 100755 index 0000000..9976fcb --- /dev/null +++ b/.config/cmus/classic.theme @@ -0,0 +1,48 @@ + +# ~ rgoncalves.se +# cmus colorscheme + +# common +set color_win_fg=15 +set color_win_bg=0 + +# command line +set color_cmdline_bg=default +set color_cmdline_fg=default +set color_error=1 +set color_info=2 +set color_separator=15 + +# bottom status line +set color_statusline_bg=4 +set color_statusline_fg=15 + +# bottom title line +set color_titleline_bg=15 +set color_titleline_fg=4 + +# top title line +set color_win_title_bg=4 +set color_win_title_fg=15 + +# playing: unselected +set color_win_cur=4 + +# playing: active selection +set color_win_cur_sel_bg=7 +set color_win_cur_sel_fg=4 + +# playing: inactive selection +set color_win_inactive_cur_sel_bg=7 +set color_win_inactive_cur_sel_fg=0 + +# collection: active selection +set color_win_sel_bg=7 +set color_win_sel_fg=0 + +# collection: inactive selection +set color_win_inactive_sel_bg=0 +set color_win_inactive_sel_fg=7 + +# directories +set color_win_dir=7 diff --git a/.config/cmus/rc b/.config/cmus/rc new file mode 100755 index 0000000..5654b7a --- /dev/null +++ b/.config/cmus/rc @@ -0,0 +1,170 @@ +set aaa_mode=all +set altformat_current= %F +set altformat_playlist= %f%= %d +set altformat_title=%f +set altformat_trackwin= %f%= %d + +set auto_expand_albums_follow=true +set auto_expand_albums_search=true +set auto_expand_albums_selcur=true +set auto_reshuffle=true +set buffer_seconds=10 + +set confirm_run=true +set continue=true +set continue_album=true +set display_artist_sort_name=false +set follow=false + +# format +set format_current= %a - %l -%3n. %t%= %y +set format_playlist= %-21%a %3n. %t%= %y %d %{?X!=0?%3X ? } +set format_playlist_va= %-21%A %3n. %t (%a)%= %y %d %{?X!=0?%3X ? } +set format_statusline= %{status} %{?show_playback_position?%{position} %{?duration?/ %{duration} }?%{?duration?%{duration} }}- %{total} %{?bpm>0?at %{bpm} BPM }%{?volume>=0?vol: %{?lvolume!=rvolume?%{lvolume},%{rvolume} ?%{volume} }}%{?stream?buf: %{buffer} }%{?show_current_bitrate & bitrate>=0? %{bitrate} kbps }%=%{?repeat_current?repeat current?%{?play_library?%{playlist_mode} from %{?play_sorted?sorted }library?playlist}} | %1{continue}%1{follow}%1{repeat}%1{shuffle} +set format_title=%a - %l - %t (%y) +set format_trackwin=%3n. %t%= %y %d +set format_trackwin_album= %l %= %{albumduration} +set format_trackwin_va=%3n. %t (%a)%= %y %d +set format_treewin= %l +set format_treewin_artist=%a + +# charset +set icecast_default_charset=ISO-8859-1 +set id3_default_charset=ISO-8859-1 + +# input +set input.cdio.priority=50 +set input.cue.priority=50 +set input.flac.priority=50 +set input.mad.priority=55 +set input.wav.priority=50 + +set lib_add_filter= +set lib_sort=albumartist date album discnumber tracknumber title filename play_count + +set mouse=true +set mpris=true + +set pl_sort= +set play_library=true +set play_sorted=false +set repeat=true +set repeat_current=false +set replaygain=disabled +set replaygain_limit=true +set replaygain_preamp=0.000000 +set resume=false +set rewind_offset=5 +set scroll_offset=2 +set set_term_title=true +set show_all_tracks=true +set show_current_bitrate=false +set show_hidden=false +set show_playback_position=true +set show_remaining_time=false +set shuffle=true +set skip_track_info=false +set smart_artist_sort=true +set softvol=true +#set softvol_state=0 0 +set start_view=tree +set status_display_program= +set stop_after_queue=false +set time_show_leading_zero=true +set tree_width_max=0 +set tree_width_percent=33 +set wrap_search=true + +# bind +bind -f browser backspace browser-up +bind -f browser i toggle show_hidden +bind -f browser space win-activate +bind -f browser u win-update +bind -f common ! push shell +bind -f common + vol +10% +bind -f common , seek -1m +bind -f common - vol -10% +bind -f common . seek +1m +bind -f common / search-start +bind -f common 1 view tree +bind -f common 2 view sorted +bind -f common 3 view playlist +bind -f common 4 view queue +bind -f common 5 view browser +bind -f common 6 view filters +bind -f common 7 view settings +bind -f common = vol +10% +bind -f common ? search-b-start +bind -f common C toggle continue +bind -f common D win-remove +bind -f common E win-add-Q +bind -f common F push filter +bind -f common G win-bottom +bind -f common I echo {} +bind -f common L push live-filter +bind -f common M toggle play_library +bind -f common N search-prev +bind -f common P win-mv-before +bind -f common U win-update-cache +bind -f common [ vol +1% +0 +bind -f common ] vol +0 +1% +bind -f common ^B win-page-up +bind -f common ^C echo Type :quit to exit cmus. +bind -f common ^D win-half-page-down +bind -f common ^E win-scroll-down +bind -f common ^F win-page-down +bind -f common ^L refresh +bind -f common ^R toggle repeat_current +bind -f common ^U win-half-page-up +bind -f common ^Y win-scroll-up +bind -f common a win-add-l +bind -f common b player-next +bind -f common c player-pause +bind -f common delete win-remove +bind -f common down win-down +bind -f common e win-add-q +bind -f common end win-bottom +bind -f common enter win-activate +bind -f common f toggle follow +bind -f common g win-top +bind -f common h seek -5 +bind -f common home win-top +bind -f common i win-sel-cur +bind -f common j win-down +bind -f common k win-up +bind -f common l seek +5 +bind -f common left seek -5 +bind -f common m toggle aaa_mode +bind -f common mlb_click_selected win-activate +bind -f common mouse_scroll_down win-down +bind -f common mouse_scroll_up win-up +bind -f common n search-next +bind -f common o toggle play_sorted +bind -f common p win-mv-after +bind -f common page_down win-page-down +bind -f common page_up win-page-up +bind -f common q quit -i +bind -f common r toggle repeat +bind -f common right seek +5 +bind -f common s toggle shuffle +bind -f common space win-toggle +bind -f common t toggle show_remaining_time +bind -f common tab win-next +bind -f common u update-cache +bind -f common up win-up +bind -f common v player-stop +bind -f common x player-play +bind -f common y win-add-p +bind -f common z player-prev +bind -f common { vol -1% -0 +bind -f common } vol -0 -1% + +# fset +fset 90s=date>=1990&date<2000 +fset classical=genre="Classical" +fset missing-tag=!stream&(artist=""|album=""|title=""|tracknumber=-1|date=-1) +fset mp3=filename="*.mp3" +fset ogg=filename="*.ogg" +fset ogg-or-mp3=ogg|mp3 +fset unheard=play_count=0 +factivate diff --git a/.config/dot/term-color-dark b/.config/dot/term-color-dark new file mode 100755 index 0000000..3f1a1d2 --- /dev/null +++ b/.config/dot/term-color-dark @@ -0,0 +1 @@ +]4;0;#000000\]4;1;#af0000\]4;2;#00af00\]4;3;#afd700\]4;4;#005fff\]4;5;#af00af\]4;6;#00d7af\]4;7;#c0c0c0\]4;8;#808080\]4;9;#ff0000\]4;10;#00ff00\]4;11;#ffff00\]4;12;#0000ff\]4;13;#ff00ff\]4;14;#00ffff\]4;15;#ffffff\]10;#ffffff\]11;#000000\]12;#ffffff\]13;#ffffff\]17;#ffffff\]19;#000000\]4;232;#000000\]4;256;#ffffff\]708;#000000\ \ No newline at end of file diff --git a/.config/dot/term-color-light b/.config/dot/term-color-light new file mode 100755 index 0000000..96ad2e1 --- /dev/null +++ b/.config/dot/term-color-light @@ -0,0 +1 @@ +]4;0;#eeeeee\]4;1;#ff0000\]4;2;#00dd00\]4;3;#dddd00\]4;4;#0000ff\]4;5;#dd00dd\]4;6;#00dddd\]4;7;#808080\]4;8;#c0c0c0\]4;9;#af0000\]4;10;#00af00\]4;11;#afd700\]4;12;#005fff\]4;13;#af00af\]4;14;#00d7af\]4;15;#000000\]10;#000000\]11;#eeeeee\]12;#eeeeee\]13;#000000\]17;#000000\]19;#eeeeee\]4;232;#eeeeee\]4;256;#000000\]708;#eeeeee\ diff --git a/.config/gopass/config.yml b/.config/gopass/config.yml new file mode 100755 index 0000000..dea9ee4 --- /dev/null +++ b/.config/gopass/config.yml @@ -0,0 +1,10 @@ +autoclip: true +autoimport: true +cliptimeout: 15 +exportkeys: true +nopager: false +notifications: false +parsing: true +path: /home/qwd/.password-store +safecontent: false +mounts: {} diff --git a/.config/i3/config b/.config/i3/config new file mode 100755 index 0000000..dbdb03f --- /dev/null +++ b/.config/i3/config @@ -0,0 +1,177 @@ + +# ~/.config/i3/config + +set $mod Mod1 +set $refresh_i3status killall -SIGUSR1 i3status +set $launcher ~/.config/common.d/bemenu.sh +font pango:TerminessTTF Nerd Font 8 + +floating_modifier $mod +focus_follows_mouse no + +# workspaces +set $ws1 "1: one " +set $ws2 "2: two " +set $ws3 "3: UwU " +set $ws4 "4: four " +set $ws5 "5: five " +set $wss1 "11: one " +set $wss2 "12: two " +set $wss3 "13: three " +set $wss4 "14: four " +set $wss5 "15: five " + +# keybinds +bindsym $mod+Shift+q kill +bindsym $mod+Return exec alacritty +bindsym $mod+d exec "$launcher run" +bindsym $mod+Shift+d exec "$launcher pass" +bindsym $mod+Shift+s exec "$launcher colorscheme" + +bindsym $mod+h focus left +bindsym $mod+k focus up +bindsym $mod+j focus down +bindsym $mod+l focus right +bindsym $mod+Left focus left +bindsym $mod+Down focus down +bindsym $mod+Up focus up +bindsym $mod+Right focus right +bindsym $mod+Shift+h move left +bindsym $mod+Shift+j move down +bindsym $mod+Shift+k move up +bindsym $mod+Shift+l move right +bindsym $mod+Shift+Left move left +bindsym $mod+Shift+Down move down +bindsym $mod+Shift+Up move up +bindsym $mod+Shift+Right move right +#bindsym $mod+h split h +bindsym $mod+v split v +bindsym $mod+f fullscreen toggle +bindsym $mod+s layout stacking +bindsym $mod+w layout tabbed +bindsym $mod+e layout toggle split +bindsym $mod+Shift+space floating toggle +bindsym $mod+space focus mode_toggle +bindsym $mod+a focus parent +bindsym $mod+Tab workspace back_and_forth +bindsym $mod+1 workspace number $ws1 +bindsym $mod+2 workspace number $ws2 +bindsym $mod+3 workspace number $ws3 +bindsym $mod+4 workspace number $ws4 +bindsym $mod+5 workspace number $ws5 +bindsym $mod+F1 workspace number $wss1 +bindsym $mod+F2 workspace number $wss2 +bindsym $mod+F3 workspace number $wss3 +bindsym $mod+F4 workspace number $wss4 +bindsym $mod+F5 workspace number $wss5 +bindsym $mod+Shift+1 move container to workspace number $ws1 +bindsym $mod+Shift+2 move container to workspace number $ws2 +bindsym $mod+Shift+3 move container to workspace number $ws3 +bindsym $mod+Shift+4 move container to workspace number $ws4 +bindsym $mod+Shift+5 move container to workspace number $ws5 +bindsym $mod+Shift+F1 move container to workspace number $wss1 +bindsym $mod+Shift+F2 move container to workspace number $wss2 +bindsym $mod+Shift+F3 move container to workspace number $wss3 +bindsym $mod+Shift+F4 move container to workspace number $wss4 +bindsym $mod+Shift+F5 move container to workspace number $wss5 +bindsym $mod+Shift+c reload +bindsym $mod+Shift+r restart +bindsym $mod+Shift+e exec "i3-nagbar -t warning -m 'You pressed the exit shortcut. Do you really want to exit i3? This will end your X session.' -B 'Yes, exit i3' 'i3-msg exit'" +bindsym $mod+r mode "resize" +mode "resize" { + bindsym j resize shrink width 10 px or 10 ppt + bindsym k resize grow height 10 px or 10 ppt + bindsym l resize shrink height 10 px or 10 ppt + bindsym semicolon resize grow width 10 px or 10 ppt + bindsym Left resize shrink width 10 px or 10 ppt + bindsym Down resize grow height 10 px or 10 ppt + bindsym Up resize shrink height 10 px or 10 ppt + bindsym Right resize grow width 10 px or 10 ppt + bindsym Return mode "default" + bindsym Escape mode "default" + bindsym $mod+r mode "default" +} +bindsym XF86AudioRaiseVolume exec --no-startup-id pactl set-sink-volume @DEFAULT_SINK@ +10% && $refresh_i3status +bindsym XF86AudioLowerVolume exec --no-startup-id pactl set-sink-volume @DEFAULT_SINK@ -10% && $refresh_i3status +bindsym XF86AudioMute exec --no-startup-id pactl set-sink-mute @DEFAULT_SINK@ toggle && $refresh_i3status +bindsym XF86AudioMicMute exec --no-startup-id pactl set-source-mute @DEFAULT_SOURCE@ toggle && $refresh_i3status +bindsym XF86MonBrightnessUp exec --no-startup-id "light -A 5" +bindsym XF86MonBrightnessDown exec --no-startup-id "light -U 5" +bindsym XF86AudioPlay exec --no-startup-id "cmus-remote -u" +bindsym XF86AudioNext exec --no-startup-id "cmus-remote -n" +bindsym XF86AudioPrev exec --no-startup-id "cmus-remote -r" + +# i3bar +bar { + status_command ~/.config/common.d/i3status_ext.sh + position top + strip_workspace_numbers yes + font TerminessTTF Nerd Font + colors { + statusline $wh + separator $wh + background $bg + # colorclass + focused_workspace $bg $fg #FFFFFF + active_workspace $bg $fg #FFFFFF + inactive_workspace $bg $bg $fg + } +} + +# dual-monitor +exec_always ~/.config/i3/screen_config.sh + +workspace $ws1 output DVI-D-0 +workspace $ws2 output DVI-D-0 +workspace $ws3 output DVI-D-0 +workspace $ws4 output DVI-D-0 +workspace $ws5 output DVI-D-0 +workspace $wss1 output HDMI-0 +workspace $wss2 output HDMI-0 +workspace $wss3 output HDMI-0 +workspace $wss4 output HDMI-0 +workspace $wss5 output HDMI-0 + +# default workspaces +assign [class="qutebrowser"] $wss1 +assign [class="discord"] $wss2 +assign [title="discord"] $wss2 +assign [class="Steam"] $wss3 +assign [title="Steam"] $wss3 +assign [class="p4v"] $wss4 +assign [class="p4v"] $wss4 + +# default window settings +for_window [class="Steam"] floating enable +for_window [title="Steam"] floating disable +for_window [title="win0"] floating enable +for_window [class="Tor Browser"] floating enable +for_window [class=".*"] title_format "%title" + +# colorscheme +set_from_resource $bg color0 #000000 +set_from_resource $rd color1 #FF0000 +set_from_resource $fg color4 #FF0000 +set_from_resource $gr color8 #8F8F8F +set_from_resource $gl color7 #8F8F8F +set_from_resource $wh color15 #FFFFFF + +# class border backgr. text indicator child_border + +client.focused $fg $fg $wh $fg $fg +client.focused_inactive $gl $gr $wh $gr $gl +client.unfocused $gl $gr $wh $gr $gl +client.urgent $rd $rd $wh $rd $rd +client.placeholder $bg $bg $fg $bg $bg + +# lockscreen +bindsym mod1+F12 exec ~/.config/common.d/lock_screen.sh +bindsym mod1+Shift+F12 exec ~/.config/common.d/lock_screen.sh -s + +# autoexec +exec_always xset s off +exec_always xset -dpms +exec_always xset s noblank +exec_always xset r rate 250 45 +exec_always setxkbmap -option compose:ralt + diff --git a/.config/mimeapps.list b/.config/mimeapps.list new file mode 100755 index 0000000..fd7ac3e --- /dev/null +++ b/.config/mimeapps.list @@ -0,0 +1,12 @@ +[Default Applications] +x-scheme-handler/jetbrains=jetbrains-toolbox.desktop +text/html=org.qutebrowser.qutebrowser.desktop +x-scheme-handler/http=org.qutebrowser.qutebrowser.desktop +x-scheme-handler/https=org.qutebrowser.qutebrowser.desktop +x-scheme-handler/about=org.qutebrowser.qutebrowser.desktop +x-scheme-handler/unknown=org.qutebrowser.qutebrowser.desktop +x-scheme-handler/postman=Postman.desktop +x-scheme-handler/discord-396515353498484736=discord-396515353498484736.desktop + +[Added Associations] +application/vnd.oasis.opendocument.text=libreoffice-writer.desktop; diff --git a/.config/neomutt/neomuttrc b/.config/neomutt/neomuttrc new file mode 100755 index 0000000..baea9d8 --- /dev/null +++ b/.config/neomutt/neomuttrc @@ -0,0 +1,128 @@ + +# rgoncalves.se + +# personal informations +set my_server = "" +set my_user = "" +set my_password = "" +source "~/.config/neomutt/personal" + +# IMAP +set imap_user = "$my_user@$my_server" +set imap_pass = "$my_password" +set hostname = "imap.$my_server" +set folder = "imaps://imap.$my_server:993" + +# SMTP +set smtp_url = "smtps://$my_user@$my_server:$my_password@smtp.$my_server" +set smtp_pass = "$my_password" + +# force tls +set ssl_force_tls = yes +set ssl_verify_host = yes + +# mailboxes +set spoolfile = "+INBOX" +set mbox = "+INBOX" +set record = "+Sent" +set trash = "+Trash" +set postponed = "+Drafts" +set mail_check_stats = yes +set imap_delim_chars = "aa" + +# environment variables required! +#set imap_check_subscribed +mailboxes `python3 ~/.bin/get-mailbox-imap \ +imap.$MAIL_SERVER \ +$MAIL_USERNAME@$MAIL_SERVER \ +$MAIL_PASSWORD` + +# dl +set mail_check = 90 +set sleep_time = 0 +set timeout = 15 +set beep = no +set postpone = no +set recall = no +set signature = "~/.signature" +set charset = "utf-8" +set date_format = "%d.%m.%Y-%H:%M" +set sort_re = yes" +set reverse_name = yes +set index_format = "%4C %Z %{$date_format} %-15.15L (%?l?%4l&%4c?) %s" +set send_charset = "utf-8:iso-8859-1:us-ascii" +set reply_regexp = "^(([Rr][Ee]?(\[[0-9]+\])?: *)?(\[[^]]+\] *)?)*" +set quote_regexp = "^( {0,4}[>|:#%]| {0,4}[a-z0-9]+[>|]+)+" +set reflow_space_quotes = yes +auto_view text/html +alternative_order text/plain text/html + +set reply_to = yes +set fast_reply = yes +set sig_dashes = no +set include = yes +set forward_quote = yes +set edit_headers = yes +set reverse_name = yes +set pipe_decode = yes + +set header_cache = "~/.cache/neomutt" +set message_cachedir = "$header_cache" + +# headers +ignore * +unignore from date subject to cc +unignore organization organisation x-mailer: x-newsreader: x-mailing-list: +unignore posted-to: list-id: + +# threads +set sort ="threads" +set sort_aux = "reverse-date" +#set sort_aux = "last-date-received" +set strict_threads ="yes" +set collapse_unread = no + +# sidebar +set sidebar_visible = yes +set sidebar_short_path = yes +set sidebar_sort_method = "unsorted" +set sidebar_delim_chars = "/" +set sidebar_format = "%D %?F?[%F]?%* %4N|%4S" +set sidebar_folder_indent = yes +set sidebar_indent_string = " " + +# keybinds +bind editor noop +bind editor "> " quote-char +bind pager c imap-fetch-mail +bind index G last-entry +bind index \CR imap-fetch-mail +bind index g noop +bind index gg first-entry +bind index - collapse-thread +bind index _ collapse-all +bind pager,attach h exit +bind attach view-mailcap +bind attach l view-mailcap +bind pager j next-line +bind pager k previous-line +bind pager l view-attachments +bind index D delete-message +bind index U undelete-message +bind index h noop +bind index l display-message +bind browser h goto-parent +bind browser l select-entry +bind index \CL limit +bind pager,browser gg top-page +bind pager,browser G bottom-page +bind index,pager R group-reply +bind index,pager K sidebar-prev +bind index,pager J sidebar-next +bind index,pager O sidebar-open +bind index,pager,browser d half-down +bind index,pager,browser u half-up + +# colors +# color quoted color08 default +# color hdrdefault color07 default diff --git a/.config/newsboat/config b/.config/newsboat/config new file mode 100755 index 0000000..0e8c120 --- /dev/null +++ b/.config/newsboat/config @@ -0,0 +1,38 @@ + +# rgoncalves.se ~~ ~/.newsboat/config +# newsboat configuration + + +max-items 100 +reload-threads 100 +auto-reload yes +reload-time 30 +text-width 80 +ssl-verifyhost no +ssl-verifypeer no + +# vim +unbind-key j +unbind-key k +unbind-key J +unbind-key K +bind-key j down +bind-key k up +bind-key l open +bind-key h quit + +# colors +color background color15 color0 +color listnormal color8 color0 +color listfocus color0 color15 +color listnormal_unread color15 color0 +color listfocus_unread color0 color15 +color info color0 color15 +color article color15 color0 + +# multimedia +browser "qutebrowser %u" +macro y set browser "mpv %u" ; open-in-browser ; set browser "qutebrowser %u" + +# format +feedlist-format "%4i %n %8u %24T | %t" diff --git a/.config/nvim/.netrwhist b/.config/nvim/.netrwhist new file mode 100755 index 0000000..038dc78 --- /dev/null +++ b/.config/nvim/.netrwhist @@ -0,0 +1,12 @@ +let g:netrw_dirhistmax =10 +let g:netrw_dirhistcnt =5 +let g:netrw_dirhist_5='/home/qwd/.config/nvim/after' +let g:netrw_dirhist_4='/home/qwd/.config/nvim/colors' +let g:netrw_dirhist_3='/home/qwd/.config/nvim' +let g:netrw_dirhist_2='/home/qwd/gitlab.viperdev.io/mcanism/backend' +let g:netrw_dirhist_1='/home/qwd/gitlab.viperdev.io/mcanism/backend/mcanism_finance/management/commands' +let g:netrw_dirhist_0='/home/qwd/gitlab.viperdev.io/mcanism/backend/mcanism_finance/management' +let g:netrw_dirhist_9='/home/qwd/gitlab.viperdev.io/mcanism/backend/mcanism_finance' +let g:netrw_dirhist_8='/home/qwd/gitlab.viperdev.io/mcanism/backend' +let g:netrw_dirhist_7='/home/qwd/gitlab.viperdev.io/mcanism/backend/mcanism_finance' +let g:netrw_dirhist_6='/home/qwd/.config/nvim/after/indent' diff --git a/.config/nvim/.nvim/autoload/plug.vim b/.config/nvim/.nvim/autoload/plug.vim new file mode 100755 index 0000000..bfafbfb --- /dev/null +++ b/.config/nvim/.nvim/autoload/plug.vim @@ -0,0 +1,2526 @@ +" vim-plug: Vim plugin manager +" ============================ +" +" Download plug.vim and put it in ~/.vim/autoload +" +" curl -fLo ~/.vim/autoload/plug.vim --create-dirs \ +" https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim +" +" Edit your .vimrc +" +" call plug#begin('~/.vim/plugged') +" +" " Make sure you use single quotes +" +" " Shorthand notation; fetches https://github.com/junegunn/vim-easy-align +" Plug 'junegunn/vim-easy-align' +" +" " Any valid git URL is allowed +" Plug 'https://github.com/junegunn/vim-github-dashboard.git' +" +" " Multiple Plug commands can be written in a single line using | separators +" Plug 'SirVer/ultisnips' | Plug 'honza/vim-snippets' +" +" " On-demand loading +" Plug 'scrooloose/nerdtree', { 'on': 'NERDTreeToggle' } +" Plug 'tpope/vim-fireplace', { 'for': 'clojure' } +" +" " Using a non-master branch +" Plug 'rdnetto/YCM-Generator', { 'branch': 'stable' } +" +" " Using a tagged release; wildcard allowed (requires git 1.9.2 or above) +" Plug 'fatih/vim-go', { 'tag': '*' } +" +" " Plugin options +" Plug 'nsf/gocode', { 'tag': 'v.20150303', 'rtp': 'vim' } +" +" " Plugin outside ~/.vim/plugged with post-update hook +" Plug 'junegunn/fzf', { 'dir': '~/.fzf', 'do': './install --all' } +" +" " Unmanaged plugin (manually installed and updated) +" Plug '~/my-prototype-plugin' +" +" " Initialize plugin system +" call plug#end() +" +" Then reload .vimrc and :PlugInstall to install plugins. +" +" Plug options: +" +"| Option | Description | +"| ----------------------- | ------------------------------------------------ | +"| `branch`/`tag`/`commit` | Branch/tag/commit of the repository to use | +"| `rtp` | Subdirectory that contains Vim plugin | +"| `dir` | Custom directory for the plugin | +"| `as` | Use different name for the plugin | +"| `do` | Post-update hook (string or funcref) | +"| `on` | On-demand loading: Commands or ``-mappings | +"| `for` | On-demand loading: File types | +"| `frozen` | Do not update unless explicitly specified | +" +" More information: https://github.com/junegunn/vim-plug +" +" +" Copyright (c) 2017 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_plug') + finish +endif +let g:loaded_plug = 1 + +let s:cpo_save = &cpo +set cpo&vim + +let s:plug_src = 'https://github.com/junegunn/vim-plug.git' +let s:plug_tab = get(s:, 'plug_tab', -1) +let s:plug_buf = get(s:, 'plug_buf', -1) +let s:mac_gui = has('gui_macvim') && has('gui_running') +let s:is_win = has('win32') +let s:nvim = has('nvim-0.2') || (has('nvim') && exists('*jobwait') && !s:is_win) +let s:vim8 = has('patch-8.0.0039') && exists('*job_start') +let s:me = resolve(expand(':p')) +let s:base_spec = { 'branch': 'master', 'frozen': 0 } +let s:TYPE = { +\ 'string': type(''), +\ 'list': type([]), +\ 'dict': type({}), +\ 'funcref': type(function('call')) +\ } +let s:loaded = get(s:, 'loaded', {}) +let s:triggers = get(s:, 'triggers', {}) + +function! plug#begin(...) + if a:0 > 0 + let s:plug_home_org = a:1 + let home = s:path(fnamemodify(expand(a:1), ':p')) + elseif exists('g:plug_home') + let home = s:path(g:plug_home) + elseif !empty(&rtp) + let home = s:path(split(&rtp, ',')[0]) . '/plugged' + else + return s:err('Unable to determine plug home. Try calling plug#begin() with a path argument.') + endif + if fnamemodify(home, ':t') ==# 'plugin' && fnamemodify(home, ':h') ==# s:first_rtp + return s:err('Invalid plug home. '.home.' is a standard Vim runtime path and is not allowed.') + endif + + let g:plug_home = home + let g:plugs = {} + let g:plugs_order = [] + let s:triggers = {} + + call s:define_commands() + return 1 +endfunction + +function! s:define_commands() + command! -nargs=+ -bar Plug call plug#() + if !executable('git') + return s:err('`git` executable not found. Most commands will not be available. To suppress this message, prepend `silent!` to `call plug#begin(...)`.') + endif + command! -nargs=* -bar -bang -complete=customlist,s:names PlugInstall call s:install(0, []) + command! -nargs=* -bar -bang -complete=customlist,s:names PlugUpdate call s:update(0, []) + command! -nargs=0 -bar -bang PlugClean call s:clean(0) + command! -nargs=0 -bar PlugUpgrade if s:upgrade() | execute 'source' s:esc(s:me) | endif + command! -nargs=0 -bar PlugStatus call s:status() + command! -nargs=0 -bar PlugDiff call s:diff() + command! -nargs=? -bar -bang -complete=file PlugSnapshot call s:snapshot(0, ) +endfunction + +function! s:to_a(v) + return type(a:v) == s:TYPE.list ? a:v : [a:v] +endfunction + +function! s:to_s(v) + return type(a:v) == s:TYPE.string ? a:v : join(a:v, "\n") . "\n" +endfunction + +function! s:glob(from, pattern) + return s:lines(globpath(a:from, a:pattern)) +endfunction + +function! s:source(from, ...) + let found = 0 + for pattern in a:000 + for vim in s:glob(a:from, pattern) + execute 'source' s:esc(vim) + let found = 1 + endfor + endfor + return found +endfunction + +function! s:assoc(dict, key, val) + let a:dict[a:key] = add(get(a:dict, a:key, []), a:val) +endfunction + +function! s:ask(message, ...) + call inputsave() + echohl WarningMsg + let answer = input(a:message.(a:0 ? ' (y/N/a) ' : ' (y/N) ')) + echohl None + call inputrestore() + echo "\r" + return (a:0 && answer =~? '^a') ? 2 : (answer =~? '^y') ? 1 : 0 +endfunction + +function! s:ask_no_interrupt(...) + try + return call('s:ask', a:000) + catch + return 0 + endtry +endfunction + +function! s:lazy(plug, opt) + return has_key(a:plug, a:opt) && + \ (empty(s:to_a(a:plug[a:opt])) || + \ !isdirectory(a:plug.dir) || + \ len(s:glob(s:rtp(a:plug), 'plugin')) || + \ len(s:glob(s:rtp(a:plug), 'after/plugin'))) +endfunction + +function! plug#end() + if !exists('g:plugs') + return s:err('Call plug#begin() first') + endif + + if exists('#PlugLOD') + augroup PlugLOD + autocmd! + augroup END + augroup! PlugLOD + endif + let lod = { 'ft': {}, 'map': {}, 'cmd': {} } + + if exists('g:did_load_filetypes') + filetype off + endif + for name in g:plugs_order + if !has_key(g:plugs, name) + continue + endif + let plug = g:plugs[name] + if get(s:loaded, name, 0) || !s:lazy(plug, 'on') && !s:lazy(plug, 'for') + let s:loaded[name] = 1 + continue + endif + + if has_key(plug, 'on') + let s:triggers[name] = { 'map': [], 'cmd': [] } + for cmd in s:to_a(plug.on) + if cmd =~? '^.\+' + if empty(mapcheck(cmd)) && empty(mapcheck(cmd, 'i')) + call s:assoc(lod.map, cmd, name) + endif + call add(s:triggers[name].map, cmd) + elseif cmd =~# '^[A-Z]' + let cmd = substitute(cmd, '!*$', '', '') + if exists(':'.cmd) != 2 + call s:assoc(lod.cmd, cmd, name) + endif + call add(s:triggers[name].cmd, cmd) + else + call s:err('Invalid `on` option: '.cmd. + \ '. Should start with an uppercase letter or ``.') + endif + endfor + endif + + if has_key(plug, 'for') + let types = s:to_a(plug.for) + if !empty(types) + augroup filetypedetect + call s:source(s:rtp(plug), 'ftdetect/**/*.vim', 'after/ftdetect/**/*.vim') + augroup END + endif + for type in types + call s:assoc(lod.ft, type, name) + endfor + endif + endfor + + for [cmd, names] in items(lod.cmd) + execute printf( + \ 'command! -nargs=* -range -bang -complete=file %s call s:lod_cmd(%s, "", , , , %s)', + \ cmd, string(cmd), string(names)) + endfor + + for [map, names] in items(lod.map) + for [mode, map_prefix, key_prefix] in + \ [['i', '', ''], ['n', '', ''], ['v', '', 'gv'], ['o', '', '']] + execute printf( + \ '%snoremap %s %s:call lod_map(%s, %s, %s, "%s")', + \ mode, map, map_prefix, string(map), string(names), mode != 'i', key_prefix) + endfor + endfor + + for [ft, names] in items(lod.ft) + augroup PlugLOD + execute printf('autocmd FileType %s call lod_ft(%s, %s)', + \ ft, string(ft), string(names)) + augroup END + endfor + + call s:reorg_rtp() + filetype plugin indent on + if has('vim_starting') + if has('syntax') && !exists('g:syntax_on') + syntax enable + end + else + call s:reload_plugins() + endif +endfunction + +function! s:loaded_names() + return filter(copy(g:plugs_order), 'get(s:loaded, v:val, 0)') +endfunction + +function! s:load_plugin(spec) + call s:source(s:rtp(a:spec), 'plugin/**/*.vim', 'after/plugin/**/*.vim') +endfunction + +function! s:reload_plugins() + for name in s:loaded_names() + call s:load_plugin(g:plugs[name]) + endfor +endfunction + +function! s:trim(str) + return substitute(a:str, '[\/]\+$', '', '') +endfunction + +function! s:version_requirement(val, min) + for idx in range(0, len(a:min) - 1) + let v = get(a:val, idx, 0) + if v < a:min[idx] | return 0 + elseif v > a:min[idx] | return 1 + endif + endfor + return 1 +endfunction + +function! s:git_version_requirement(...) + if !exists('s:git_version') + let s:git_version = map(split(split(s:system('git --version'))[2], '\.'), 'str2nr(v:val)') + endif + return s:version_requirement(s:git_version, a:000) +endfunction + +function! s:progress_opt(base) + return a:base && !s:is_win && + \ s:git_version_requirement(1, 7, 1) ? '--progress' : '' +endfunction + +if s:is_win + function! s:rtp(spec) + return s:path(a:spec.dir . get(a:spec, 'rtp', '')) + endfunction + + function! s:path(path) + return s:trim(substitute(a:path, '/', '\', 'g')) + endfunction + + function! s:dirpath(path) + return s:path(a:path) . '\' + endfunction + + function! s:is_local_plug(repo) + return a:repo =~? '^[a-z]:\|^[%~]' + endfunction +else + function! s:rtp(spec) + return s:dirpath(a:spec.dir . get(a:spec, 'rtp', '')) + endfunction + + function! s:path(path) + return s:trim(a:path) + endfunction + + function! s:dirpath(path) + return substitute(a:path, '[/\\]*$', '/', '') + endfunction + + function! s:is_local_plug(repo) + return a:repo[0] =~ '[/$~]' + endfunction +endif + +function! s:err(msg) + echohl ErrorMsg + echom '[vim-plug] '.a:msg + echohl None +endfunction + +function! s:warn(cmd, msg) + echohl WarningMsg + execute a:cmd 'a:msg' + echohl None +endfunction + +function! s:esc(path) + return escape(a:path, ' ') +endfunction + +function! s:escrtp(path) + return escape(a:path, ' ,') +endfunction + +function! s:remove_rtp() + for name in s:loaded_names() + let rtp = s:rtp(g:plugs[name]) + execute 'set rtp-='.s:escrtp(rtp) + let after = globpath(rtp, 'after') + if isdirectory(after) + execute 'set rtp-='.s:escrtp(after) + endif + endfor +endfunction + +function! s:reorg_rtp() + if !empty(s:first_rtp) + execute 'set rtp-='.s:first_rtp + execute 'set rtp-='.s:last_rtp + endif + + " &rtp is modified from outside + if exists('s:prtp') && s:prtp !=# &rtp + call s:remove_rtp() + unlet! s:middle + endif + + let s:middle = get(s:, 'middle', &rtp) + let rtps = map(s:loaded_names(), 's:rtp(g:plugs[v:val])') + let afters = filter(map(copy(rtps), 'globpath(v:val, "after")'), '!empty(v:val)') + let rtp = join(map(rtps, 'escape(v:val, ",")'), ',') + \ . ','.s:middle.',' + \ . join(map(afters, 'escape(v:val, ",")'), ',') + let &rtp = substitute(substitute(rtp, ',,*', ',', 'g'), '^,\|,$', '', 'g') + let s:prtp = &rtp + + if !empty(s:first_rtp) + execute 'set rtp^='.s:first_rtp + execute 'set rtp+='.s:last_rtp + endif +endfunction + +function! s:doautocmd(...) + if exists('#'.join(a:000, '#')) + execute 'doautocmd' ((v:version > 703 || has('patch442')) ? '' : '') join(a:000) + endif +endfunction + +function! s:dobufread(names) + for name in a:names + let path = s:rtp(g:plugs[name]) + for dir in ['ftdetect', 'ftplugin', 'after/ftdetect', 'after/ftplugin'] + if len(finddir(dir, path)) + if exists('#BufRead') + doautocmd BufRead + endif + return + endif + endfor + endfor +endfunction + +function! plug#load(...) + if a:0 == 0 + return s:err('Argument missing: plugin name(s) required') + endif + if !exists('g:plugs') + return s:err('plug#begin was not called') + endif + let names = a:0 == 1 && type(a:1) == s:TYPE.list ? a:1 : a:000 + let unknowns = filter(copy(names), '!has_key(g:plugs, v:val)') + if !empty(unknowns) + let s = len(unknowns) > 1 ? 's' : '' + return s:err(printf('Unknown plugin%s: %s', s, join(unknowns, ', '))) + end + let unloaded = filter(copy(names), '!get(s:loaded, v:val, 0)') + if !empty(unloaded) + for name in unloaded + call s:lod([name], ['ftdetect', 'after/ftdetect', 'plugin', 'after/plugin']) + endfor + call s:dobufread(unloaded) + return 1 + end + return 0 +endfunction + +function! s:remove_triggers(name) + if !has_key(s:triggers, a:name) + return + endif + for cmd in s:triggers[a:name].cmd + execute 'silent! delc' cmd + endfor + for map in s:triggers[a:name].map + execute 'silent! unmap' map + execute 'silent! iunmap' map + endfor + call remove(s:triggers, a:name) +endfunction + +function! s:lod(names, types, ...) + for name in a:names + call s:remove_triggers(name) + let s:loaded[name] = 1 + endfor + call s:reorg_rtp() + + for name in a:names + let rtp = s:rtp(g:plugs[name]) + for dir in a:types + call s:source(rtp, dir.'/**/*.vim') + endfor + if a:0 + if !s:source(rtp, a:1) && !empty(s:glob(rtp, a:2)) + execute 'runtime' a:1 + endif + call s:source(rtp, a:2) + endif + call s:doautocmd('User', name) + endfor +endfunction + +function! s:lod_ft(pat, names) + let syn = 'syntax/'.a:pat.'.vim' + call s:lod(a:names, ['plugin', 'after/plugin'], syn, 'after/'.syn) + execute 'autocmd! PlugLOD FileType' a:pat + call s:doautocmd('filetypeplugin', 'FileType') + call s:doautocmd('filetypeindent', 'FileType') +endfunction + +function! s:lod_cmd(cmd, bang, l1, l2, args, names) + call s:lod(a:names, ['ftdetect', 'after/ftdetect', 'plugin', 'after/plugin']) + call s:dobufread(a:names) + execute printf('%s%s%s %s', (a:l1 == a:l2 ? '' : (a:l1.','.a:l2)), a:cmd, a:bang, a:args) +endfunction + +function! s:lod_map(map, names, with_prefix, prefix) + call s:lod(a:names, ['ftdetect', 'after/ftdetect', 'plugin', 'after/plugin']) + call s:dobufread(a:names) + let extra = '' + while 1 + let c = getchar(0) + if c == 0 + break + endif + let extra .= nr2char(c) + endwhile + + if a:with_prefix + let prefix = v:count ? v:count : '' + let prefix .= '"'.v:register.a:prefix + if mode(1) == 'no' + if v:operator == 'c' + let prefix = "\" . prefix + endif + let prefix .= v:operator + endif + call feedkeys(prefix, 'n') + endif + call feedkeys(substitute(a:map, '^', "\", '') . extra) +endfunction + +function! plug#(repo, ...) + if a:0 > 1 + return s:err('Invalid number of arguments (1..2)') + endif + + try + let repo = s:trim(a:repo) + let opts = a:0 == 1 ? s:parse_options(a:1) : s:base_spec + let name = get(opts, 'as', fnamemodify(repo, ':t:s?\.git$??')) + let spec = extend(s:infer_properties(name, repo), opts) + if !has_key(g:plugs, name) + call add(g:plugs_order, name) + endif + let g:plugs[name] = spec + let s:loaded[name] = get(s:loaded, name, 0) + catch + return s:err(v:exception) + endtry +endfunction + +function! s:parse_options(arg) + let opts = copy(s:base_spec) + let type = type(a:arg) + if type == s:TYPE.string + let opts.tag = a:arg + elseif type == s:TYPE.dict + call extend(opts, a:arg) + if has_key(opts, 'dir') + let opts.dir = s:dirpath(expand(opts.dir)) + endif + else + throw 'Invalid argument type (expected: string or dictionary)' + endif + return opts +endfunction + +function! s:infer_properties(name, repo) + let repo = a:repo + if s:is_local_plug(repo) + return { 'dir': s:dirpath(expand(repo)) } + else + if repo =~ ':' + let uri = repo + else + if repo !~ '/' + throw printf('Invalid argument: %s (implicit `vim-scripts'' expansion is deprecated)', repo) + endif + let fmt = get(g:, 'plug_url_format', 'https://git::@github.com/%s.git') + let uri = printf(fmt, repo) + endif + return { 'dir': s:dirpath(g:plug_home.'/'.a:name), 'uri': uri } + endif +endfunction + +function! s:install(force, names) + call s:update_impl(0, a:force, a:names) +endfunction + +function! s:update(force, names) + call s:update_impl(1, a:force, a:names) +endfunction + +function! plug#helptags() + if !exists('g:plugs') + return s:err('plug#begin was not called') + endif + for spec in values(g:plugs) + let docd = join([s:rtp(spec), 'doc'], '/') + if isdirectory(docd) + silent! execute 'helptags' s:esc(docd) + endif + endfor + return 1 +endfunction + +function! s:syntax() + syntax clear + syntax region plug1 start=/\%1l/ end=/\%2l/ contains=plugNumber + syntax region plug2 start=/\%2l/ end=/\%3l/ contains=plugBracket,plugX + syn match plugNumber /[0-9]\+[0-9.]*/ contained + syn match plugBracket /[[\]]/ contained + syn match plugX /x/ contained + syn match plugDash /^-/ + syn match plugPlus /^+/ + syn match plugStar /^*/ + syn match plugMessage /\(^- \)\@<=.*/ + syn match plugName /\(^- \)\@<=[^ ]*:/ + syn match plugSha /\%(: \)\@<=[0-9a-f]\{4,}$/ + syn match plugTag /(tag: [^)]\+)/ + syn match plugInstall /\(^+ \)\@<=[^:]*/ + syn match plugUpdate /\(^* \)\@<=[^:]*/ + syn match plugCommit /^ \X*[0-9a-f]\{7,9} .*/ contains=plugRelDate,plugEdge,plugTag + syn match plugEdge /^ \X\+$/ + syn match plugEdge /^ \X*/ contained nextgroup=plugSha + syn match plugSha /[0-9a-f]\{7,9}/ contained + syn match plugRelDate /([^)]*)$/ contained + syn match plugNotLoaded /(not loaded)$/ + syn match plugError /^x.*/ + syn region plugDeleted start=/^\~ .*/ end=/^\ze\S/ + syn match plugH2 /^.*:\n-\+$/ + syn keyword Function PlugInstall PlugStatus PlugUpdate PlugClean + hi def link plug1 Title + hi def link plug2 Repeat + hi def link plugH2 Type + hi def link plugX Exception + hi def link plugBracket Structure + hi def link plugNumber Number + + hi def link plugDash Special + hi def link plugPlus Constant + hi def link plugStar Boolean + + hi def link plugMessage Function + hi def link plugName Label + hi def link plugInstall Function + hi def link plugUpdate Type + + hi def link plugError Error + hi def link plugDeleted Ignore + hi def link plugRelDate Comment + hi def link plugEdge PreProc + hi def link plugSha Identifier + hi def link plugTag Constant + + hi def link plugNotLoaded Comment +endfunction + +function! s:lpad(str, len) + return a:str . repeat(' ', a:len - len(a:str)) +endfunction + +function! s:lines(msg) + return split(a:msg, "[\r\n]") +endfunction + +function! s:lastline(msg) + return get(s:lines(a:msg), -1, '') +endfunction + +function! s:new_window() + execute get(g:, 'plug_window', 'vertical topleft new') +endfunction + +function! s:plug_window_exists() + let buflist = tabpagebuflist(s:plug_tab) + return !empty(buflist) && index(buflist, s:plug_buf) >= 0 +endfunction + +function! s:switch_in() + if !s:plug_window_exists() + return 0 + endif + + if winbufnr(0) != s:plug_buf + let s:pos = [tabpagenr(), winnr(), winsaveview()] + execute 'normal!' s:plug_tab.'gt' + let winnr = bufwinnr(s:plug_buf) + execute winnr.'wincmd w' + call add(s:pos, winsaveview()) + else + let s:pos = [winsaveview()] + endif + + setlocal modifiable + return 1 +endfunction + +function! s:switch_out(...) + call winrestview(s:pos[-1]) + setlocal nomodifiable + if a:0 > 0 + execute a:1 + endif + + if len(s:pos) > 1 + execute 'normal!' s:pos[0].'gt' + execute s:pos[1] 'wincmd w' + call winrestview(s:pos[2]) + endif +endfunction + +function! s:finish_bindings() + nnoremap R :call retry() + nnoremap D :PlugDiff + nnoremap S :PlugStatus + nnoremap U :call status_update() + xnoremap U :call status_update() + nnoremap ]] :silent! call section('') + nnoremap [[ :silent! call section('b') +endfunction + +function! s:prepare(...) + if empty(getcwd()) + throw 'Invalid current working directory. Cannot proceed.' + endif + + for evar in ['$GIT_DIR', '$GIT_WORK_TREE'] + if exists(evar) + throw evar.' detected. Cannot proceed.' + endif + endfor + + call s:job_abort() + if s:switch_in() + if b:plug_preview == 1 + pc + endif + enew + else + call s:new_window() + endif + + nnoremap q :if b:plug_preview==1pcendifbd + if a:0 == 0 + call s:finish_bindings() + endif + let b:plug_preview = -1 + let s:plug_tab = tabpagenr() + let s:plug_buf = winbufnr(0) + call s:assign_name() + + for k in ['', 'L', 'o', 'X', 'd', 'dd'] + execute 'silent! unmap ' k + endfor + setlocal buftype=nofile bufhidden=wipe nobuflisted nolist noswapfile nowrap cursorline modifiable nospell + if exists('+colorcolumn') + setlocal colorcolumn= + endif + setf vim-plug + if exists('g:syntax_on') + call s:syntax() + endif +endfunction + +function! s:assign_name() + " Assign buffer name + let prefix = '[Plugins]' + let name = prefix + let idx = 2 + while bufexists(name) + let name = printf('%s (%s)', prefix, idx) + let idx = idx + 1 + endwhile + silent! execute 'f' fnameescape(name) +endfunction + +function! s:chsh(swap) + let prev = [&shell, &shellcmdflag, &shellredir] + if s:is_win + set shell=cmd.exe shellcmdflag=/c shellredir=>%s\ 2>&1 + elseif a:swap + set shell=sh shellredir=>%s\ 2>&1 + endif + return prev +endfunction + +function! s:bang(cmd, ...) + try + let [sh, shellcmdflag, shrd] = s:chsh(a:0) + " FIXME: Escaping is incomplete. We could use shellescape with eval, + " but it won't work on Windows. + let cmd = a:0 ? s:with_cd(a:cmd, a:1) : a:cmd + if s:is_win + let batchfile = tempname().'.bat' + call writefile(["@echo off\r", cmd . "\r"], batchfile) + let cmd = s:shellesc(batchfile) + endif + let g:_plug_bang = (s:is_win && has('gui_running') ? 'silent ' : '').'!'.escape(cmd, '#!%') + execute "normal! :execute g:_plug_bang\\" + finally + unlet g:_plug_bang + let [&shell, &shellcmdflag, &shellredir] = [sh, shellcmdflag, shrd] + if s:is_win + call delete(batchfile) + endif + endtry + return v:shell_error ? 'Exit status: ' . v:shell_error : '' +endfunction + +function! s:regress_bar() + let bar = substitute(getline(2)[1:-2], '.*\zs=', 'x', '') + call s:progress_bar(2, bar, len(bar)) +endfunction + +function! s:is_updated(dir) + return !empty(s:system_chomp('git log --pretty=format:"%h" "HEAD...HEAD@{1}"', a:dir)) +endfunction + +function! s:do(pull, force, todo) + for [name, spec] in items(a:todo) + if !isdirectory(spec.dir) + continue + endif + let installed = has_key(s:update.new, name) + let updated = installed ? 0 : + \ (a:pull && index(s:update.errors, name) < 0 && s:is_updated(spec.dir)) + if a:force || installed || updated + execute 'cd' s:esc(spec.dir) + call append(3, '- Post-update hook for '. name .' ... ') + let error = '' + let type = type(spec.do) + if type == s:TYPE.string + if spec.do[0] == ':' + if !get(s:loaded, name, 0) + let s:loaded[name] = 1 + call s:reorg_rtp() + endif + call s:load_plugin(spec) + try + execute spec.do[1:] + catch + let error = v:exception + endtry + if !s:plug_window_exists() + cd - + throw 'Warning: vim-plug was terminated by the post-update hook of '.name + endif + else + let error = s:bang(spec.do) + endif + elseif type == s:TYPE.funcref + try + let status = installed ? 'installed' : (updated ? 'updated' : 'unchanged') + call spec.do({ 'name': name, 'status': status, 'force': a:force }) + catch + let error = v:exception + endtry + else + let error = 'Invalid hook type' + endif + call s:switch_in() + call setline(4, empty(error) ? (getline(4) . 'OK') + \ : ('x' . getline(4)[1:] . error)) + if !empty(error) + call add(s:update.errors, name) + call s:regress_bar() + endif + cd - + endif + endfor +endfunction + +function! s:hash_match(a, b) + return stridx(a:a, a:b) == 0 || stridx(a:b, a:a) == 0 +endfunction + +function! s:checkout(spec) + let sha = a:spec.commit + let output = s:system('git rev-parse HEAD', a:spec.dir) + if !v:shell_error && !s:hash_match(sha, s:lines(output)[0]) + let output = s:system( + \ 'git fetch --depth 999999 && git checkout '.s:esc(sha).' --', a:spec.dir) + endif + return output +endfunction + +function! s:finish(pull) + let new_frozen = len(filter(keys(s:update.new), 'g:plugs[v:val].frozen')) + if new_frozen + let s = new_frozen > 1 ? 's' : '' + call append(3, printf('- Installed %d frozen plugin%s', new_frozen, s)) + endif + call append(3, '- Finishing ... ') | 4 + redraw + call plug#helptags() + call plug#end() + call setline(4, getline(4) . 'Done!') + redraw + let msgs = [] + if !empty(s:update.errors) + call add(msgs, "Press 'R' to retry.") + endif + if a:pull && len(s:update.new) < len(filter(getline(5, '$'), + \ "v:val =~ '^- ' && v:val !~# 'Already up.to.date'")) + call add(msgs, "Press 'D' to see the updated changes.") + endif + echo join(msgs, ' ') + call s:finish_bindings() +endfunction + +function! s:retry() + if empty(s:update.errors) + return + endif + echo + call s:update_impl(s:update.pull, s:update.force, + \ extend(copy(s:update.errors), [s:update.threads])) +endfunction + +function! s:is_managed(name) + return has_key(g:plugs[a:name], 'uri') +endfunction + +function! s:names(...) + return sort(filter(keys(g:plugs), 'stridx(v:val, a:1) == 0 && s:is_managed(v:val)')) +endfunction + +function! s:check_ruby() + silent! ruby require 'thread'; VIM::command("let g:plug_ruby = '#{RUBY_VERSION}'") + if !exists('g:plug_ruby') + redraw! + return s:warn('echom', 'Warning: Ruby interface is broken') + endif + let ruby_version = split(g:plug_ruby, '\.') + unlet g:plug_ruby + return s:version_requirement(ruby_version, [1, 8, 7]) +endfunction + +function! s:update_impl(pull, force, args) abort + let sync = index(a:args, '--sync') >= 0 || has('vim_starting') + let args = filter(copy(a:args), 'v:val != "--sync"') + let threads = (len(args) > 0 && args[-1] =~ '^[1-9][0-9]*$') ? + \ remove(args, -1) : get(g:, 'plug_threads', 16) + + let managed = filter(copy(g:plugs), 's:is_managed(v:key)') + let todo = empty(args) ? filter(managed, '!v:val.frozen || !isdirectory(v:val.dir)') : + \ filter(managed, 'index(args, v:key) >= 0') + + if empty(todo) + return s:warn('echo', 'No plugin to '. (a:pull ? 'update' : 'install')) + endif + + if !s:is_win && s:git_version_requirement(2, 3) + let s:git_terminal_prompt = exists('$GIT_TERMINAL_PROMPT') ? $GIT_TERMINAL_PROMPT : '' + let $GIT_TERMINAL_PROMPT = 0 + for plug in values(todo) + let plug.uri = substitute(plug.uri, + \ '^https://git::@github\.com', 'https://github.com', '') + endfor + endif + + if !isdirectory(g:plug_home) + try + call mkdir(g:plug_home, 'p') + catch + return s:err(printf('Invalid plug directory: %s. '. + \ 'Try to call plug#begin with a valid directory', g:plug_home)) + endtry + endif + + if has('nvim') && !exists('*jobwait') && threads > 1 + call s:warn('echom', '[vim-plug] Update Neovim for parallel installer') + endif + + let use_job = s:nvim || s:vim8 + let python = (has('python') || has('python3')) && !use_job + let ruby = has('ruby') && !use_job && (v:version >= 703 || v:version == 702 && has('patch374')) && !(s:is_win && has('gui_running')) && threads > 1 && s:check_ruby() + + let s:update = { + \ 'start': reltime(), + \ 'all': todo, + \ 'todo': copy(todo), + \ 'errors': [], + \ 'pull': a:pull, + \ 'force': a:force, + \ 'new': {}, + \ 'threads': (python || ruby || use_job) ? min([len(todo), threads]) : 1, + \ 'bar': '', + \ 'fin': 0 + \ } + + call s:prepare(1) + call append(0, ['', '']) + normal! 2G + silent! redraw + + let s:clone_opt = get(g:, 'plug_shallow', 1) ? + \ '--depth 1' . (s:git_version_requirement(1, 7, 10) ? ' --no-single-branch' : '') : '' + + if has('win32unix') + let s:clone_opt .= ' -c core.eol=lf -c core.autocrlf=input' + endif + + let s:submodule_opt = s:git_version_requirement(2, 8) ? ' --jobs='.threads : '' + + " Python version requirement (>= 2.7) + if python && !has('python3') && !ruby && !use_job && s:update.threads > 1 + redir => pyv + silent python import platform; print platform.python_version() + redir END + let python = s:version_requirement( + \ map(split(split(pyv)[0], '\.'), 'str2nr(v:val)'), [2, 6]) + endif + + if (python || ruby) && s:update.threads > 1 + try + let imd = &imd + if s:mac_gui + set noimd + endif + if ruby + call s:update_ruby() + else + call s:update_python() + endif + catch + let lines = getline(4, '$') + let printed = {} + silent! 4,$d _ + for line in lines + let name = s:extract_name(line, '.', '') + if empty(name) || !has_key(printed, name) + call append('$', line) + if !empty(name) + let printed[name] = 1 + if line[0] == 'x' && index(s:update.errors, name) < 0 + call add(s:update.errors, name) + end + endif + endif + endfor + finally + let &imd = imd + call s:update_finish() + endtry + else + call s:update_vim() + while use_job && sync + sleep 100m + if s:update.fin + break + endif + endwhile + endif +endfunction + +function! s:log4(name, msg) + call setline(4, printf('- %s (%s)', a:msg, a:name)) + redraw +endfunction + +function! s:update_finish() + if exists('s:git_terminal_prompt') + let $GIT_TERMINAL_PROMPT = s:git_terminal_prompt + endif + if s:switch_in() + call append(3, '- Updating ...') | 4 + for [name, spec] in items(filter(copy(s:update.all), 'index(s:update.errors, v:key) < 0 && (s:update.force || s:update.pull || has_key(s:update.new, v:key))')) + let [pos, _] = s:logpos(name) + if !pos + continue + endif + if has_key(spec, 'commit') + call s:log4(name, 'Checking out '.spec.commit) + let out = s:checkout(spec) + elseif has_key(spec, 'tag') + let tag = spec.tag + if tag =~ '\*' + let tags = s:lines(s:system('git tag --list '.s:shellesc(tag).' --sort -version:refname 2>&1', spec.dir)) + if !v:shell_error && !empty(tags) + let tag = tags[0] + call s:log4(name, printf('Latest tag for %s -> %s', spec.tag, tag)) + call append(3, '') + endif + endif + call s:log4(name, 'Checking out '.tag) + let out = s:system('git checkout -q '.s:esc(tag).' -- 2>&1', spec.dir) + else + let branch = s:esc(get(spec, 'branch', 'master')) + call s:log4(name, 'Merging origin/'.branch) + let out = s:system('git checkout -q '.branch.' -- 2>&1' + \. (has_key(s:update.new, name) ? '' : ('&& git merge --ff-only origin/'.branch.' 2>&1')), spec.dir) + endif + if !v:shell_error && filereadable(spec.dir.'/.gitmodules') && + \ (s:update.force || has_key(s:update.new, name) || s:is_updated(spec.dir)) + call s:log4(name, 'Updating submodules. This may take a while.') + let out .= s:bang('git submodule update --init --recursive'.s:submodule_opt.' 2>&1', spec.dir) + endif + let msg = s:format_message(v:shell_error ? 'x': '-', name, out) + if v:shell_error + call add(s:update.errors, name) + call s:regress_bar() + silent execute pos 'd _' + call append(4, msg) | 4 + elseif !empty(out) + call setline(pos, msg[0]) + endif + redraw + endfor + silent 4 d _ + try + call s:do(s:update.pull, s:update.force, filter(copy(s:update.all), 'index(s:update.errors, v:key) < 0 && has_key(v:val, "do")')) + catch + call s:warn('echom', v:exception) + call s:warn('echo', '') + return + endtry + call s:finish(s:update.pull) + call setline(1, 'Updated. Elapsed time: ' . split(reltimestr(reltime(s:update.start)))[0] . ' sec.') + call s:switch_out('normal! gg') + endif +endfunction + +function! s:job_abort() + if (!s:nvim && !s:vim8) || !exists('s:jobs') + return + endif + + for [name, j] in items(s:jobs) + if s:nvim + silent! call jobstop(j.jobid) + elseif s:vim8 + silent! call job_stop(j.jobid) + endif + if j.new + call s:system('rm -rf ' . s:shellesc(g:plugs[name].dir)) + endif + endfor + let s:jobs = {} +endfunction + +function! s:last_non_empty_line(lines) + let len = len(a:lines) + for idx in range(len) + let line = a:lines[len-idx-1] + if !empty(line) + return line + endif + endfor + return '' +endfunction + +function! s:job_out_cb(self, data) abort + let self = a:self + let data = remove(self.lines, -1) . a:data + let lines = map(split(data, "\n", 1), 'split(v:val, "\r", 1)[-1]') + call extend(self.lines, lines) + " To reduce the number of buffer updates + let self.tick = get(self, 'tick', -1) + 1 + if !self.running || self.tick % len(s:jobs) == 0 + let bullet = self.running ? (self.new ? '+' : '*') : (self.error ? 'x' : '-') + let result = self.error ? join(self.lines, "\n") : s:last_non_empty_line(self.lines) + call s:log(bullet, self.name, result) + endif +endfunction + +function! s:job_exit_cb(self, data) abort + let a:self.running = 0 + let a:self.error = a:data != 0 + call s:reap(a:self.name) + call s:tick() +endfunction + +function! s:job_cb(fn, job, ch, data) + if !s:plug_window_exists() " plug window closed + return s:job_abort() + endif + call call(a:fn, [a:job, a:data]) +endfunction + +function! s:nvim_cb(job_id, data, event) dict abort + return a:event == 'stdout' ? + \ s:job_cb('s:job_out_cb', self, 0, join(a:data, "\n")) : + \ s:job_cb('s:job_exit_cb', self, 0, a:data) +endfunction + +function! s:spawn(name, cmd, opts) + let job = { 'name': a:name, 'running': 1, 'error': 0, 'lines': [''], + \ 'batchfile': (s:is_win && (s:nvim || s:vim8)) ? tempname().'.bat' : '', + \ 'new': get(a:opts, 'new', 0) } + let s:jobs[a:name] = job + let cmd = has_key(a:opts, 'dir') ? s:with_cd(a:cmd, a:opts.dir) : a:cmd + if !empty(job.batchfile) + call writefile(["@echo off\r", cmd . "\r"], job.batchfile) + let cmd = s:shellesc(job.batchfile) + endif + let argv = add(s:is_win ? ['cmd', '/c'] : ['sh', '-c'], cmd) + + if s:nvim + call extend(job, { + \ 'on_stdout': function('s:nvim_cb'), + \ 'on_exit': function('s:nvim_cb'), + \ }) + let jid = jobstart(argv, job) + if jid > 0 + let job.jobid = jid + else + let job.running = 0 + let job.error = 1 + let job.lines = [jid < 0 ? argv[0].' is not executable' : + \ 'Invalid arguments (or job table is full)'] + endif + elseif s:vim8 + let jid = job_start(s:is_win ? join(argv, ' ') : argv, { + \ 'out_cb': function('s:job_cb', ['s:job_out_cb', job]), + \ 'exit_cb': function('s:job_cb', ['s:job_exit_cb', job]), + \ 'out_mode': 'raw' + \}) + if job_status(jid) == 'run' + let job.jobid = jid + else + let job.running = 0 + let job.error = 1 + let job.lines = ['Failed to start job'] + endif + else + let job.lines = s:lines(call('s:system', [cmd])) + let job.error = v:shell_error != 0 + let job.running = 0 + endif +endfunction + +function! s:reap(name) + let job = s:jobs[a:name] + if job.error + call add(s:update.errors, a:name) + elseif get(job, 'new', 0) + let s:update.new[a:name] = 1 + endif + let s:update.bar .= job.error ? 'x' : '=' + + let bullet = job.error ? 'x' : '-' + let result = job.error ? join(job.lines, "\n") : s:last_non_empty_line(job.lines) + call s:log(bullet, a:name, empty(result) ? 'OK' : result) + call s:bar() + + if has_key(job, 'batchfile') && !empty(job.batchfile) + call delete(job.batchfile) + endif + call remove(s:jobs, a:name) +endfunction + +function! s:bar() + if s:switch_in() + let total = len(s:update.all) + call setline(1, (s:update.pull ? 'Updating' : 'Installing'). + \ ' plugins ('.len(s:update.bar).'/'.total.')') + call s:progress_bar(2, s:update.bar, total) + call s:switch_out() + endif +endfunction + +function! s:logpos(name) + for i in range(4, line('$')) + if getline(i) =~# '^[-+x*] '.a:name.':' + for j in range(i + 1, line('$')) + if getline(j) !~ '^ ' + return [i, j - 1] + endif + endfor + return [i, i] + endif + endfor + return [0, 0] +endfunction + +function! s:log(bullet, name, lines) + if s:switch_in() + let [b, e] = s:logpos(a:name) + if b > 0 + silent execute printf('%d,%d d _', b, e) + if b > winheight('.') + let b = 4 + endif + else + let b = 4 + endif + " FIXME For some reason, nomodifiable is set after :d in vim8 + setlocal modifiable + call append(b - 1, s:format_message(a:bullet, a:name, a:lines)) + call s:switch_out() + endif +endfunction + +function! s:update_vim() + let s:jobs = {} + + call s:bar() + call s:tick() +endfunction + +function! s:tick() + let pull = s:update.pull + let prog = s:progress_opt(s:nvim || s:vim8) +while 1 " Without TCO, Vim stack is bound to explode + if empty(s:update.todo) + if empty(s:jobs) && !s:update.fin + call s:update_finish() + let s:update.fin = 1 + endif + return + endif + + let name = keys(s:update.todo)[0] + let spec = remove(s:update.todo, name) + let new = empty(globpath(spec.dir, '.git', 1)) + + call s:log(new ? '+' : '*', name, pull ? 'Updating ...' : 'Installing ...') + redraw + + let has_tag = has_key(spec, 'tag') + if !new + let [error, _] = s:git_validate(spec, 0) + if empty(error) + if pull + let fetch_opt = (has_tag && !empty(globpath(spec.dir, '.git/shallow'))) ? '--depth 99999999' : '' + call s:spawn(name, printf('git fetch %s %s 2>&1', fetch_opt, prog), { 'dir': spec.dir }) + else + let s:jobs[name] = { 'running': 0, 'lines': ['Already installed'], 'error': 0 } + endif + else + let s:jobs[name] = { 'running': 0, 'lines': s:lines(error), 'error': 1 } + endif + else + call s:spawn(name, + \ printf('git clone %s %s %s %s 2>&1', + \ has_tag ? '' : s:clone_opt, + \ prog, + \ s:shellesc(spec.uri), + \ s:shellesc(s:trim(spec.dir))), { 'new': 1 }) + endif + + if !s:jobs[name].running + call s:reap(name) + endif + if len(s:jobs) >= s:update.threads + break + endif +endwhile +endfunction + +function! s:update_python() +let py_exe = has('python') ? 'python' : 'python3' +execute py_exe "<< EOF" +import datetime +import functools +import os +try: + import queue +except ImportError: + import Queue as queue +import random +import re +import shutil +import signal +import subprocess +import tempfile +import threading as thr +import time +import traceback +import vim + +G_NVIM = vim.eval("has('nvim')") == '1' +G_PULL = vim.eval('s:update.pull') == '1' +G_RETRIES = int(vim.eval('get(g:, "plug_retries", 2)')) + 1 +G_TIMEOUT = int(vim.eval('get(g:, "plug_timeout", 60)')) +G_CLONE_OPT = vim.eval('s:clone_opt') +G_PROGRESS = vim.eval('s:progress_opt(1)') +G_LOG_PROB = 1.0 / int(vim.eval('s:update.threads')) +G_STOP = thr.Event() +G_IS_WIN = vim.eval('s:is_win') == '1' + +class PlugError(Exception): + def __init__(self, msg): + self.msg = msg +class CmdTimedOut(PlugError): + pass +class CmdFailed(PlugError): + pass +class InvalidURI(PlugError): + pass +class Action(object): + INSTALL, UPDATE, ERROR, DONE = ['+', '*', 'x', '-'] + +class Buffer(object): + def __init__(self, lock, num_plugs, is_pull): + self.bar = '' + self.event = 'Updating' if is_pull else 'Installing' + self.lock = lock + self.maxy = int(vim.eval('winheight(".")')) + self.num_plugs = num_plugs + + def __where(self, name): + """ Find first line with name in current buffer. Return line num. """ + found, lnum = False, 0 + matcher = re.compile('^[-+x*] {0}:'.format(name)) + for line in vim.current.buffer: + if matcher.search(line) is not None: + found = True + break + lnum += 1 + + if not found: + lnum = -1 + return lnum + + def header(self): + curbuf = vim.current.buffer + curbuf[0] = self.event + ' plugins ({0}/{1})'.format(len(self.bar), self.num_plugs) + + num_spaces = self.num_plugs - len(self.bar) + curbuf[1] = '[{0}{1}]'.format(self.bar, num_spaces * ' ') + + with self.lock: + vim.command('normal! 2G') + vim.command('redraw') + + def write(self, action, name, lines): + first, rest = lines[0], lines[1:] + msg = ['{0} {1}{2}{3}'.format(action, name, ': ' if first else '', first)] + msg.extend([' ' + line for line in rest]) + + try: + if action == Action.ERROR: + self.bar += 'x' + vim.command("call add(s:update.errors, '{0}')".format(name)) + elif action == Action.DONE: + self.bar += '=' + + curbuf = vim.current.buffer + lnum = self.__where(name) + if lnum != -1: # Found matching line num + del curbuf[lnum] + if lnum > self.maxy and action in set([Action.INSTALL, Action.UPDATE]): + lnum = 3 + else: + lnum = 3 + curbuf.append(msg, lnum) + + self.header() + except vim.error: + pass + +class Command(object): + CD = 'cd /d' if G_IS_WIN else 'cd' + + def __init__(self, cmd, cmd_dir=None, timeout=60, cb=None, clean=None): + self.cmd = cmd + if cmd_dir: + self.cmd = '{0} {1} && {2}'.format(Command.CD, cmd_dir, self.cmd) + self.timeout = timeout + self.callback = cb if cb else (lambda msg: None) + self.clean = clean if clean else (lambda: None) + self.proc = None + + @property + def alive(self): + """ Returns true only if command still running. """ + return self.proc and self.proc.poll() is None + + def execute(self, ntries=3): + """ Execute the command with ntries if CmdTimedOut. + Returns the output of the command if no Exception. + """ + attempt, finished, limit = 0, False, self.timeout + + while not finished: + try: + attempt += 1 + result = self.try_command() + finished = True + return result + except CmdTimedOut: + if attempt != ntries: + self.notify_retry() + self.timeout += limit + else: + raise + + def notify_retry(self): + """ Retry required for command, notify user. """ + for count in range(3, 0, -1): + if G_STOP.is_set(): + raise KeyboardInterrupt + msg = 'Timeout. Will retry in {0} second{1} ...'.format( + count, 's' if count != 1 else '') + self.callback([msg]) + time.sleep(1) + self.callback(['Retrying ...']) + + def try_command(self): + """ Execute a cmd & poll for callback. Returns list of output. + Raises CmdFailed -> return code for Popen isn't 0 + Raises CmdTimedOut -> command exceeded timeout without new output + """ + first_line = True + + try: + tfile = tempfile.NamedTemporaryFile(mode='w+b') + preexec_fn = not G_IS_WIN and os.setsid or None + self.proc = subprocess.Popen(self.cmd, stdout=tfile, + stderr=subprocess.STDOUT, + stdin=subprocess.PIPE, shell=True, + preexec_fn=preexec_fn) + thrd = thr.Thread(target=(lambda proc: proc.wait()), args=(self.proc,)) + thrd.start() + + thread_not_started = True + while thread_not_started: + try: + thrd.join(0.1) + thread_not_started = False + except RuntimeError: + pass + + while self.alive: + if G_STOP.is_set(): + raise KeyboardInterrupt + + if first_line or random.random() < G_LOG_PROB: + first_line = False + line = '' if G_IS_WIN else nonblock_read(tfile.name) + if line: + self.callback([line]) + + time_diff = time.time() - os.path.getmtime(tfile.name) + if time_diff > self.timeout: + raise CmdTimedOut(['Timeout!']) + + thrd.join(0.5) + + tfile.seek(0) + result = [line.decode('utf-8', 'replace').rstrip() for line in tfile] + + if self.proc.returncode != 0: + raise CmdFailed([''] + result) + + return result + except: + self.terminate() + raise + + def terminate(self): + """ Terminate process and cleanup. """ + if self.alive: + if G_IS_WIN: + os.kill(self.proc.pid, signal.SIGINT) + else: + os.killpg(self.proc.pid, signal.SIGTERM) + self.clean() + +class Plugin(object): + def __init__(self, name, args, buf_q, lock): + self.name = name + self.args = args + self.buf_q = buf_q + self.lock = lock + self.tag = args.get('tag', 0) + + def manage(self): + try: + if os.path.exists(self.args['dir']): + self.update() + else: + self.install() + with self.lock: + thread_vim_command("let s:update.new['{0}'] = 1".format(self.name)) + except PlugError as exc: + self.write(Action.ERROR, self.name, exc.msg) + except KeyboardInterrupt: + G_STOP.set() + self.write(Action.ERROR, self.name, ['Interrupted!']) + except: + # Any exception except those above print stack trace + msg = 'Trace:\n{0}'.format(traceback.format_exc().rstrip()) + self.write(Action.ERROR, self.name, msg.split('\n')) + raise + + def install(self): + target = self.args['dir'] + if target[-1] == '\\': + target = target[0:-1] + + def clean(target): + def _clean(): + try: + shutil.rmtree(target) + except OSError: + pass + return _clean + + self.write(Action.INSTALL, self.name, ['Installing ...']) + callback = functools.partial(self.write, Action.INSTALL, self.name) + cmd = 'git clone {0} {1} {2} {3} 2>&1'.format( + '' if self.tag else G_CLONE_OPT, G_PROGRESS, self.args['uri'], + esc(target)) + com = Command(cmd, None, G_TIMEOUT, callback, clean(target)) + result = com.execute(G_RETRIES) + self.write(Action.DONE, self.name, result[-1:]) + + def repo_uri(self): + cmd = 'git rev-parse --abbrev-ref HEAD 2>&1 && git config -f .git/config remote.origin.url' + command = Command(cmd, self.args['dir'], G_TIMEOUT,) + result = command.execute(G_RETRIES) + return result[-1] + + def update(self): + actual_uri = self.repo_uri() + expect_uri = self.args['uri'] + regex = re.compile(r'^(?:\w+://)?(?:[^@/]*@)?([^:/]*(?::[0-9]*)?)[:/](.*?)(?:\.git)?/?$') + ma = regex.match(actual_uri) + mb = regex.match(expect_uri) + if ma is None or mb is None or ma.groups() != mb.groups(): + msg = ['', + 'Invalid URI: {0}'.format(actual_uri), + 'Expected {0}'.format(expect_uri), + 'PlugClean required.'] + raise InvalidURI(msg) + + if G_PULL: + self.write(Action.UPDATE, self.name, ['Updating ...']) + callback = functools.partial(self.write, Action.UPDATE, self.name) + fetch_opt = '--depth 99999999' if self.tag and os.path.isfile(os.path.join(self.args['dir'], '.git/shallow')) else '' + cmd = 'git fetch {0} {1} 2>&1'.format(fetch_opt, G_PROGRESS) + com = Command(cmd, self.args['dir'], G_TIMEOUT, callback) + result = com.execute(G_RETRIES) + self.write(Action.DONE, self.name, result[-1:]) + else: + self.write(Action.DONE, self.name, ['Already installed']) + + def write(self, action, name, msg): + self.buf_q.put((action, name, msg)) + +class PlugThread(thr.Thread): + def __init__(self, tname, args): + super(PlugThread, self).__init__() + self.tname = tname + self.args = args + + def run(self): + thr.current_thread().name = self.tname + buf_q, work_q, lock = self.args + + try: + while not G_STOP.is_set(): + name, args = work_q.get_nowait() + plug = Plugin(name, args, buf_q, lock) + plug.manage() + work_q.task_done() + except queue.Empty: + pass + +class RefreshThread(thr.Thread): + def __init__(self, lock): + super(RefreshThread, self).__init__() + self.lock = lock + self.running = True + + def run(self): + while self.running: + with self.lock: + thread_vim_command('noautocmd normal! a') + time.sleep(0.33) + + def stop(self): + self.running = False + +if G_NVIM: + def thread_vim_command(cmd): + vim.session.threadsafe_call(lambda: vim.command(cmd)) +else: + def thread_vim_command(cmd): + vim.command(cmd) + +def esc(name): + return '"' + name.replace('"', '\"') + '"' + +def nonblock_read(fname): + """ Read a file with nonblock flag. Return the last line. """ + fread = os.open(fname, os.O_RDONLY | os.O_NONBLOCK) + buf = os.read(fread, 100000).decode('utf-8', 'replace') + os.close(fread) + + line = buf.rstrip('\r\n') + left = max(line.rfind('\r'), line.rfind('\n')) + if left != -1: + left += 1 + line = line[left:] + + return line + +def main(): + thr.current_thread().name = 'main' + nthreads = int(vim.eval('s:update.threads')) + plugs = vim.eval('s:update.todo') + mac_gui = vim.eval('s:mac_gui') == '1' + + lock = thr.Lock() + buf = Buffer(lock, len(plugs), G_PULL) + buf_q, work_q = queue.Queue(), queue.Queue() + for work in plugs.items(): + work_q.put(work) + + start_cnt = thr.active_count() + for num in range(nthreads): + tname = 'PlugT-{0:02}'.format(num) + thread = PlugThread(tname, (buf_q, work_q, lock)) + thread.start() + if mac_gui: + rthread = RefreshThread(lock) + rthread.start() + + while not buf_q.empty() or thr.active_count() != start_cnt: + try: + action, name, msg = buf_q.get(True, 0.25) + buf.write(action, name, ['OK'] if not msg else msg) + buf_q.task_done() + except queue.Empty: + pass + except KeyboardInterrupt: + G_STOP.set() + + if mac_gui: + rthread.stop() + rthread.join() + +main() +EOF +endfunction + +function! s:update_ruby() + ruby << EOF + module PlugStream + SEP = ["\r", "\n", nil] + def get_line + buffer = '' + loop do + char = readchar rescue return + if SEP.include? char.chr + buffer << $/ + break + else + buffer << char + end + end + buffer + end + end unless defined?(PlugStream) + + def esc arg + %["#{arg.gsub('"', '\"')}"] + end + + def killall pid + pids = [pid] + if /mswin|mingw|bccwin/ =~ RUBY_PLATFORM + pids.each { |pid| Process.kill 'INT', pid.to_i rescue nil } + else + unless `which pgrep 2> /dev/null`.empty? + children = pids + until children.empty? + children = children.map { |pid| + `pgrep -P #{pid}`.lines.map { |l| l.chomp } + }.flatten + pids += children + end + end + pids.each { |pid| Process.kill 'TERM', pid.to_i rescue nil } + end + end + + def compare_git_uri a, b + regex = %r{^(?:\w+://)?(?:[^@/]*@)?([^:/]*(?::[0-9]*)?)[:/](.*?)(?:\.git)?/?$} + regex.match(a).to_a.drop(1) == regex.match(b).to_a.drop(1) + end + + require 'thread' + require 'fileutils' + require 'timeout' + running = true + iswin = VIM::evaluate('s:is_win').to_i == 1 + pull = VIM::evaluate('s:update.pull').to_i == 1 + base = VIM::evaluate('g:plug_home') + all = VIM::evaluate('s:update.todo') + limit = VIM::evaluate('get(g:, "plug_timeout", 60)') + tries = VIM::evaluate('get(g:, "plug_retries", 2)') + 1 + nthr = VIM::evaluate('s:update.threads').to_i + maxy = VIM::evaluate('winheight(".")').to_i + vim7 = VIM::evaluate('v:version').to_i <= 703 && RUBY_PLATFORM =~ /darwin/ + cd = iswin ? 'cd /d' : 'cd' + tot = VIM::evaluate('len(s:update.todo)') || 0 + bar = '' + skip = 'Already installed' + mtx = Mutex.new + take1 = proc { mtx.synchronize { running && all.shift } } + logh = proc { + cnt = bar.length + $curbuf[1] = "#{pull ? 'Updating' : 'Installing'} plugins (#{cnt}/#{tot})" + $curbuf[2] = '[' + bar.ljust(tot) + ']' + VIM::command('normal! 2G') + VIM::command('redraw') + } + where = proc { |name| (1..($curbuf.length)).find { |l| $curbuf[l] =~ /^[-+x*] #{name}:/ } } + log = proc { |name, result, type| + mtx.synchronize do + ing = ![true, false].include?(type) + bar += type ? '=' : 'x' unless ing + b = case type + when :install then '+' when :update then '*' + when true, nil then '-' else + VIM::command("call add(s:update.errors, '#{name}')") + 'x' + end + result = + if type || type.nil? + ["#{b} #{name}: #{result.lines.to_a.last || 'OK'}"] + elsif result =~ /^Interrupted|^Timeout/ + ["#{b} #{name}: #{result}"] + else + ["#{b} #{name}"] + result.lines.map { |l| " " << l } + end + if lnum = where.call(name) + $curbuf.delete lnum + lnum = 4 if ing && lnum > maxy + end + result.each_with_index do |line, offset| + $curbuf.append((lnum || 4) - 1 + offset, line.gsub(/\e\[./, '').chomp) + end + logh.call + end + } + bt = proc { |cmd, name, type, cleanup| + tried = timeout = 0 + begin + tried += 1 + timeout += limit + fd = nil + data = '' + if iswin + Timeout::timeout(timeout) do + tmp = VIM::evaluate('tempname()') + system("(#{cmd}) > #{tmp}") + data = File.read(tmp).chomp + File.unlink tmp rescue nil + end + else + fd = IO.popen(cmd).extend(PlugStream) + first_line = true + log_prob = 1.0 / nthr + while line = Timeout::timeout(timeout) { fd.get_line } + data << line + log.call name, line.chomp, type if name && (first_line || rand < log_prob) + first_line = false + end + fd.close + end + [$? == 0, data.chomp] + rescue Timeout::Error, Interrupt => e + if fd && !fd.closed? + killall fd.pid + fd.close + end + cleanup.call if cleanup + if e.is_a?(Timeout::Error) && tried < tries + 3.downto(1) do |countdown| + s = countdown > 1 ? 's' : '' + log.call name, "Timeout. Will retry in #{countdown} second#{s} ...", type + sleep 1 + end + log.call name, 'Retrying ...', type + retry + end + [false, e.is_a?(Interrupt) ? "Interrupted!" : "Timeout!"] + end + } + main = Thread.current + threads = [] + watcher = Thread.new { + if vim7 + while VIM::evaluate('getchar(1)') + sleep 0.1 + end + else + require 'io/console' # >= Ruby 1.9 + nil until IO.console.getch == 3.chr + end + mtx.synchronize do + running = false + threads.each { |t| t.raise Interrupt } unless vim7 + end + threads.each { |t| t.join rescue nil } + main.kill + } + refresh = Thread.new { + while true + mtx.synchronize do + break unless running + VIM::command('noautocmd normal! a') + end + sleep 0.2 + end + } if VIM::evaluate('s:mac_gui') == 1 + + clone_opt = VIM::evaluate('s:clone_opt') + progress = VIM::evaluate('s:progress_opt(1)') + nthr.times do + mtx.synchronize do + threads << Thread.new { + while pair = take1.call + name = pair.first + dir, uri, tag = pair.last.values_at *%w[dir uri tag] + exists = File.directory? dir + ok, result = + if exists + chdir = "#{cd} #{iswin ? dir : esc(dir)}" + ret, data = bt.call "#{chdir} && git rev-parse --abbrev-ref HEAD 2>&1 && git config -f .git/config remote.origin.url", nil, nil, nil + current_uri = data.lines.to_a.last + if !ret + if data =~ /^Interrupted|^Timeout/ + [false, data] + else + [false, [data.chomp, "PlugClean required."].join($/)] + end + elsif !compare_git_uri(current_uri, uri) + [false, ["Invalid URI: #{current_uri}", + "Expected: #{uri}", + "PlugClean required."].join($/)] + else + if pull + log.call name, 'Updating ...', :update + fetch_opt = (tag && File.exist?(File.join(dir, '.git/shallow'))) ? '--depth 99999999' : '' + bt.call "#{chdir} && git fetch #{fetch_opt} #{progress} 2>&1", name, :update, nil + else + [true, skip] + end + end + else + d = esc dir.sub(%r{[\\/]+$}, '') + log.call name, 'Installing ...', :install + bt.call "git clone #{clone_opt unless tag} #{progress} #{uri} #{d} 2>&1", name, :install, proc { + FileUtils.rm_rf dir + } + end + mtx.synchronize { VIM::command("let s:update.new['#{name}'] = 1") } if !exists && ok + log.call name, result, ok + end + } if running + end + end + threads.each { |t| t.join rescue nil } + logh.call + refresh.kill if refresh + watcher.kill +EOF +endfunction + +function! s:shellesc_cmd(arg) + let escaped = substitute(a:arg, '[&|<>()@^]', '^&', 'g') + let escaped = substitute(escaped, '%', '%%', 'g') + let escaped = substitute(escaped, '"', '\\^&', 'g') + let escaped = substitute(escaped, '\(\\\+\)\(\\^\)', '\1\1\2', 'g') + return '^"'.substitute(escaped, '\(\\\+\)$', '\1\1', '').'^"' +endfunction + +function! s:shellesc(arg) + if &shell =~# 'cmd.exe$' + return s:shellesc_cmd(a:arg) + endif + return shellescape(a:arg) +endfunction + +function! s:glob_dir(path) + return map(filter(s:glob(a:path, '**'), 'isdirectory(v:val)'), 's:dirpath(v:val)') +endfunction + +function! s:progress_bar(line, bar, total) + call setline(a:line, '[' . s:lpad(a:bar, a:total) . ']') +endfunction + +function! s:compare_git_uri(a, b) + " See `git help clone' + " https:// [user@] github.com[:port] / junegunn/vim-plug [.git] + " [git@] github.com[:port] : junegunn/vim-plug [.git] + " file:// / junegunn/vim-plug [/] + " / junegunn/vim-plug [/] + let pat = '^\%(\w\+://\)\='.'\%([^@/]*@\)\='.'\([^:/]*\%(:[0-9]*\)\=\)'.'[:/]'.'\(.\{-}\)'.'\%(\.git\)\=/\?$' + let ma = matchlist(a:a, pat) + let mb = matchlist(a:b, pat) + return ma[1:2] ==# mb[1:2] +endfunction + +function! s:format_message(bullet, name, message) + if a:bullet != 'x' + return [printf('%s %s: %s', a:bullet, a:name, s:lastline(a:message))] + else + let lines = map(s:lines(a:message), '" ".v:val') + return extend([printf('x %s:', a:name)], lines) + endif +endfunction + +function! s:with_cd(cmd, dir) + return printf('cd%s %s && %s', s:is_win ? ' /d' : '', s:shellesc(a:dir), a:cmd) +endfunction + +function! s:system(cmd, ...) + try + let [sh, shellcmdflag, shrd] = s:chsh(1) + let cmd = a:0 > 0 ? s:with_cd(a:cmd, a:1) : a:cmd + if s:is_win + let batchfile = tempname().'.bat' + call writefile(["@echo off\r", cmd . "\r"], batchfile) + let cmd = s:shellesc(batchfile) + endif + return system(cmd) + finally + let [&shell, &shellcmdflag, &shellredir] = [sh, shellcmdflag, shrd] + if s:is_win + call delete(batchfile) + endif + endtry +endfunction + +function! s:system_chomp(...) + let ret = call('s:system', a:000) + return v:shell_error ? '' : substitute(ret, '\n$', '', '') +endfunction + +function! s:git_validate(spec, check_branch) + let err = '' + if isdirectory(a:spec.dir) + let result = s:lines(s:system('git rev-parse --abbrev-ref HEAD 2>&1 && git config -f .git/config remote.origin.url', a:spec.dir)) + let remote = result[-1] + if v:shell_error + let err = join([remote, 'PlugClean required.'], "\n") + elseif !s:compare_git_uri(remote, a:spec.uri) + let err = join(['Invalid URI: '.remote, + \ 'Expected: '.a:spec.uri, + \ 'PlugClean required.'], "\n") + elseif a:check_branch && has_key(a:spec, 'commit') + let result = s:lines(s:system('git rev-parse HEAD 2>&1', a:spec.dir)) + let sha = result[-1] + if v:shell_error + let err = join(add(result, 'PlugClean required.'), "\n") + elseif !s:hash_match(sha, a:spec.commit) + let err = join([printf('Invalid HEAD (expected: %s, actual: %s)', + \ a:spec.commit[:6], sha[:6]), + \ 'PlugUpdate required.'], "\n") + endif + elseif a:check_branch + let branch = result[0] + " Check tag + if has_key(a:spec, 'tag') + let tag = s:system_chomp('git describe --exact-match --tags HEAD 2>&1', a:spec.dir) + if a:spec.tag !=# tag && a:spec.tag !~ '\*' + let err = printf('Invalid tag: %s (expected: %s). Try PlugUpdate.', + \ (empty(tag) ? 'N/A' : tag), a:spec.tag) + endif + " Check branch + elseif a:spec.branch !=# branch + let err = printf('Invalid branch: %s (expected: %s). Try PlugUpdate.', + \ branch, a:spec.branch) + endif + if empty(err) + let [ahead, behind] = split(s:lastline(s:system(printf( + \ 'git rev-list --count --left-right HEAD...origin/%s', + \ a:spec.branch), a:spec.dir)), '\t') + if !v:shell_error && ahead + if behind + " Only mention PlugClean if diverged, otherwise it's likely to be + " pushable (and probably not that messed up). + let err = printf( + \ "Diverged from origin/%s (%d commit(s) ahead and %d commit(s) behind!\n" + \ .'Backup local changes and run PlugClean and PlugUpdate to reinstall it.', a:spec.branch, ahead, behind) + else + let err = printf("Ahead of origin/%s by %d commit(s).\n" + \ .'Cannot update until local changes are pushed.', + \ a:spec.branch, ahead) + endif + endif + endif + endif + else + let err = 'Not found' + endif + return [err, err =~# 'PlugClean'] +endfunction + +function! s:rm_rf(dir) + if isdirectory(a:dir) + call s:system((s:is_win ? 'rmdir /S /Q ' : 'rm -rf ') . s:shellesc(a:dir)) + endif +endfunction + +function! s:clean(force) + call s:prepare() + call append(0, 'Searching for invalid plugins in '.g:plug_home) + call append(1, '') + + " List of valid directories + let dirs = [] + let errs = {} + let [cnt, total] = [0, len(g:plugs)] + for [name, spec] in items(g:plugs) + if !s:is_managed(name) + call add(dirs, spec.dir) + else + let [err, clean] = s:git_validate(spec, 1) + if clean + let errs[spec.dir] = s:lines(err)[0] + else + call add(dirs, spec.dir) + endif + endif + let cnt += 1 + call s:progress_bar(2, repeat('=', cnt), total) + normal! 2G + redraw + endfor + + let allowed = {} + for dir in dirs + let allowed[s:dirpath(fnamemodify(dir, ':h:h'))] = 1 + let allowed[dir] = 1 + for child in s:glob_dir(dir) + let allowed[child] = 1 + endfor + endfor + + let todo = [] + let found = sort(s:glob_dir(g:plug_home)) + while !empty(found) + let f = remove(found, 0) + if !has_key(allowed, f) && isdirectory(f) + call add(todo, f) + call append(line('$'), '- ' . f) + if has_key(errs, f) + call append(line('$'), ' ' . errs[f]) + endif + let found = filter(found, 'stridx(v:val, f) != 0') + end + endwhile + + 4 + redraw + if empty(todo) + call append(line('$'), 'Already clean.') + else + let s:clean_count = 0 + call append(3, ['Directories to delete:', '']) + redraw! + if a:force || s:ask_no_interrupt('Delete all directories?') + call s:delete([6, line('$')], 1) + else + call setline(4, 'Cancelled.') + nnoremap d :set opfunc=delete_opg@ + nmap dd d_ + xnoremap d :call delete_op(visualmode(), 1) + echo 'Delete the lines (d{motion}) to delete the corresponding directories' + endif + endif + 4 + setlocal nomodifiable +endfunction + +function! s:delete_op(type, ...) + call s:delete(a:0 ? [line("'<"), line("'>")] : [line("'["), line("']")], 0) +endfunction + +function! s:delete(range, force) + let [l1, l2] = a:range + let force = a:force + while l1 <= l2 + let line = getline(l1) + if line =~ '^- ' && isdirectory(line[2:]) + execute l1 + redraw! + let answer = force ? 1 : s:ask('Delete '.line[2:].'?', 1) + let force = force || answer > 1 + if answer + call s:rm_rf(line[2:]) + setlocal modifiable + call setline(l1, '~'.line[1:]) + let s:clean_count += 1 + call setline(4, printf('Removed %d directories.', s:clean_count)) + setlocal nomodifiable + endif + endif + let l1 += 1 + endwhile +endfunction + +function! s:upgrade() + echo 'Downloading the latest version of vim-plug' + redraw + let tmp = tempname() + let new = tmp . '/plug.vim' + + try + let out = s:system(printf('git clone --depth 1 %s %s', s:shellesc(s:plug_src), s:shellesc(tmp))) + if v:shell_error + return s:err('Error upgrading vim-plug: '. out) + endif + + if readfile(s:me) ==# readfile(new) + echo 'vim-plug is already up-to-date' + return 0 + else + call rename(s:me, s:me . '.old') + call rename(new, s:me) + unlet g:loaded_plug + echo 'vim-plug has been upgraded' + return 1 + endif + finally + silent! call s:rm_rf(tmp) + endtry +endfunction + +function! s:upgrade_specs() + for spec in values(g:plugs) + let spec.frozen = get(spec, 'frozen', 0) + endfor +endfunction + +function! s:status() + call s:prepare() + call append(0, 'Checking plugins') + call append(1, '') + + let ecnt = 0 + let unloaded = 0 + let [cnt, total] = [0, len(g:plugs)] + for [name, spec] in items(g:plugs) + let is_dir = isdirectory(spec.dir) + if has_key(spec, 'uri') + if is_dir + let [err, _] = s:git_validate(spec, 1) + let [valid, msg] = [empty(err), empty(err) ? 'OK' : err] + else + let [valid, msg] = [0, 'Not found. Try PlugInstall.'] + endif + else + if is_dir + let [valid, msg] = [1, 'OK'] + else + let [valid, msg] = [0, 'Not found.'] + endif + endif + let cnt += 1 + let ecnt += !valid + " `s:loaded` entry can be missing if PlugUpgraded + if is_dir && get(s:loaded, name, -1) == 0 + let unloaded = 1 + let msg .= ' (not loaded)' + endif + call s:progress_bar(2, repeat('=', cnt), total) + call append(3, s:format_message(valid ? '-' : 'x', name, msg)) + normal! 2G + redraw + endfor + call setline(1, 'Finished. '.ecnt.' error(s).') + normal! gg + setlocal nomodifiable + if unloaded + echo "Press 'L' on each line to load plugin, or 'U' to update" + nnoremap L :call status_load(line('.')) + xnoremap L :call status_load(line('.')) + end +endfunction + +function! s:extract_name(str, prefix, suffix) + return matchstr(a:str, '^'.a:prefix.' \zs[^:]\+\ze:.*'.a:suffix.'$') +endfunction + +function! s:status_load(lnum) + let line = getline(a:lnum) + let name = s:extract_name(line, '-', '(not loaded)') + if !empty(name) + call plug#load(name) + setlocal modifiable + call setline(a:lnum, substitute(line, ' (not loaded)$', '', '')) + setlocal nomodifiable + endif +endfunction + +function! s:status_update() range + let lines = getline(a:firstline, a:lastline) + let names = filter(map(lines, 's:extract_name(v:val, "[x-]", "")'), '!empty(v:val)') + if !empty(names) + echo + execute 'PlugUpdate' join(names) + endif +endfunction + +function! s:is_preview_window_open() + silent! wincmd P + if &previewwindow + wincmd p + return 1 + endif +endfunction + +function! s:find_name(lnum) + for lnum in reverse(range(1, a:lnum)) + let line = getline(lnum) + if empty(line) + return '' + endif + let name = s:extract_name(line, '-', '') + if !empty(name) + return name + endif + endfor + return '' +endfunction + +function! s:preview_commit() + if b:plug_preview < 0 + let b:plug_preview = !s:is_preview_window_open() + endif + + let sha = matchstr(getline('.'), '^ \X*\zs[0-9a-f]\{7,9}') + if empty(sha) + return + endif + + let name = s:find_name(line('.')) + if empty(name) || !has_key(g:plugs, name) || !isdirectory(g:plugs[name].dir) + return + endif + + if exists('g:plug_pwindow') && !s:is_preview_window_open() + execute g:plug_pwindow + execute 'e' sha + else + execute 'pedit' sha + wincmd P + endif + setlocal previewwindow filetype=git buftype=nofile nobuflisted modifiable + try + let [sh, shellcmdflag, shrd] = s:chsh(1) + let cmd = 'cd '.s:shellesc(g:plugs[name].dir).' && git show --no-color --pretty=medium '.sha + if s:is_win + let batchfile = tempname().'.bat' + call writefile(["@echo off\r", cmd . "\r"], batchfile) + let cmd = batchfile + endif + execute 'silent %!' cmd + finally + let [&shell, &shellcmdflag, &shellredir] = [sh, shellcmdflag, shrd] + if s:is_win + call delete(batchfile) + endif + endtry + setlocal nomodifiable + nnoremap q :q + wincmd p +endfunction + +function! s:section(flags) + call search('\(^[x-] \)\@<=[^:]\+:', a:flags) +endfunction + +function! s:format_git_log(line) + let indent = ' ' + let tokens = split(a:line, nr2char(1)) + if len(tokens) != 5 + return indent.substitute(a:line, '\s*$', '', '') + endif + let [graph, sha, refs, subject, date] = tokens + let tag = matchstr(refs, 'tag: [^,)]\+') + let tag = empty(tag) ? ' ' : ' ('.tag.') ' + return printf('%s%s%s%s%s (%s)', indent, graph, sha, tag, subject, date) +endfunction + +function! s:append_ul(lnum, text) + call append(a:lnum, ['', a:text, repeat('-', len(a:text))]) +endfunction + +function! s:diff() + call s:prepare() + call append(0, ['Collecting changes ...', '']) + let cnts = [0, 0] + let bar = '' + let total = filter(copy(g:plugs), 's:is_managed(v:key) && isdirectory(v:val.dir)') + call s:progress_bar(2, bar, len(total)) + for origin in [1, 0] + let plugs = reverse(sort(items(filter(copy(total), (origin ? '' : '!').'(has_key(v:val, "commit") || has_key(v:val, "tag"))')))) + if empty(plugs) + continue + endif + call s:append_ul(2, origin ? 'Pending updates:' : 'Last update:') + for [k, v] in plugs + let range = origin ? '..origin/'.v.branch : 'HEAD@{1}..' + let cmd = 'git log --graph --color=never '.join(map(['--pretty=format:%x01%h%x01%d%x01%s%x01%cr', range], 's:shellesc(v:val)')) + if has_key(v, 'rtp') + let cmd .= ' -- '.s:shellesc(v.rtp) + endif + let diff = s:system_chomp(cmd, v.dir) + if !empty(diff) + let ref = has_key(v, 'tag') ? (' (tag: '.v.tag.')') : has_key(v, 'commit') ? (' '.v.commit) : '' + call append(5, extend(['', '- '.k.':'.ref], map(s:lines(diff), 's:format_git_log(v:val)'))) + let cnts[origin] += 1 + endif + let bar .= '=' + call s:progress_bar(2, bar, len(total)) + normal! 2G + redraw + endfor + if !cnts[origin] + call append(5, ['', 'N/A']) + endif + endfor + call setline(1, printf('%d plugin(s) updated.', cnts[0]) + \ . (cnts[1] ? printf(' %d plugin(s) have pending updates.', cnts[1]) : '')) + + if cnts[0] || cnts[1] + nnoremap (plug-preview) :silent! call preview_commit() + if empty(maparg("\", 'n')) + nmap (plug-preview) + endif + if empty(maparg('o', 'n')) + nmap o (plug-preview) + endif + endif + if cnts[0] + nnoremap X :call revert() + echo "Press 'X' on each block to revert the update" + endif + normal! gg + setlocal nomodifiable +endfunction + +function! s:revert() + if search('^Pending updates', 'bnW') + return + endif + + let name = s:find_name(line('.')) + if empty(name) || !has_key(g:plugs, name) || + \ input(printf('Revert the update of %s? (y/N) ', name)) !~? '^y' + return + endif + + call s:system('git reset --hard HEAD@{1} && git checkout '.s:esc(g:plugs[name].branch).' --', g:plugs[name].dir) + setlocal modifiable + normal! "_dap + setlocal nomodifiable + echo 'Reverted' +endfunction + +function! s:snapshot(force, ...) abort + call s:prepare() + setf vim + call append(0, ['" Generated by vim-plug', + \ '" '.strftime("%c"), + \ '" :source this file in vim to restore the snapshot', + \ '" or execute: vim -S snapshot.vim', + \ '', '', 'PlugUpdate!']) + 1 + let anchor = line('$') - 3 + let names = sort(keys(filter(copy(g:plugs), + \'has_key(v:val, "uri") && !has_key(v:val, "commit") && isdirectory(v:val.dir)'))) + for name in reverse(names) + let sha = s:system_chomp('git rev-parse --short HEAD', g:plugs[name].dir) + if !empty(sha) + call append(anchor, printf("silent! let g:plugs['%s'].commit = '%s'", name, sha)) + redraw + endif + endfor + + if a:0 > 0 + let fn = expand(a:1) + if filereadable(fn) && !(a:force || s:ask(a:1.' already exists. Overwrite?')) + return + endif + call writefile(getline(1, '$'), fn) + echo 'Saved as '.a:1 + silent execute 'e' s:esc(fn) + setf vim + endif +endfunction + +function! s:split_rtp() + return split(&rtp, '\\\@ texthl=semshiErrorSign diff --git a/.config/nvim/init.lua b/.config/nvim/init.lua new file mode 100755 index 0000000..eda0497 --- /dev/null +++ b/.config/nvim/init.lua @@ -0,0 +1,10 @@ +o = vim.o +bo = vim.bo +wo = vim.wo +cmd = vim.cmd + +require('settings') +require('plugins') +require('lsp') +require('statusline') +require('keymaps') diff --git a/.config/nvim/init.old.vim b/.config/nvim/init.old.vim new file mode 100755 index 0000000..35630e8 --- /dev/null +++ b/.config/nvim/init.old.vim @@ -0,0 +1,218 @@ +" nvim configuration ~~ rgoncalves.se + +" vim-plug autoinstall +if empty(glob('~/.local/share/nvim/site/autoload/plug.vim')) + silent !curl -fLo ~/.local/share/nvim/site/autoload/plug.vim --create-dirs + \ https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim + autocmd VimEnter * PlugInstall --sync | source $MYVIMRC +endif + +" system agnostic detection +let uname = system('uname')[:-2] + +" global configuration +set encoding=utf-8 +set laststatus=2 +set scrolloff=3 +set viminfo= +set mouse=a +set title +set number +set noswapfile +set shell=/bin/sh +set updatetime=2500 +set synmaxcol=300 +set lazyredraw +set ttyfast +set wildoptions= +set autochdir +let sh_minlines=100 +let sh_maxlines=600 + +" filetypes and colorschemes +syntax on +filetype on +filetype plugin on +filetype indent on +colorscheme base + +" keybindings +noremap =j :%!python -m json.tool +noremap =k :%s/-\|-/-+-/g +noremap =l :%s/-+-/-\|-/g +noremap :NERDTreeToggle +noremap :GitGutterCustomToggle +inoremap +inoremap +inoremap +inoremap +" keybindings - omnifunc +inoremap pumvisible() ? "\" : "\" +inoremap pumvisible() ? "\" : "\" +inoremap pumvisible() ? '' : + \ '=pumvisible() ? "\Down>" : ""' +inoremap pumvisible() ? '' : + \ '=pumvisible() ? "\Down>" : ""' +inoremap (pumvisible() ? (col('.') > 1 ? 'i' : 'i') : '') . + \ '=pumvisible() ? "\C-n>\C-p>\Down>" : ""' +inoremap (pumvisible() ? (col('.') > 1 ? 'i' : 'i') : '') . + \ '=pumvisible() ? "\C-n>\C-p>\Down>" : ""' + +let g:polyglot_disabled = ['autoindent', 'sensible'] + +" PLUGINS list +if !empty(glob('~/.local/share/nvim/site/autoload/plug.vim')) + call plug#begin('~/.nvim/plugged/') + " core + Plug 'scrooloose/nerdtree' + " completion + Plug 'w0rp/ale' + " Plug 'davidhalter/jedi-vim' + Plug 'maralla/completor.vim' + " fzf + Plug 'junegunn/fzf', { 'do': { -> fzf#install() } } + Plug 'junegunn/fzf.vim' + " indent + Plug 'nathanaelkane/vim-indent-guides' + Plug 'editorconfig/editorconfig-vim' + Plug 'pangloss/vim-javascript' + Plug 'pearofducks/ansible-vim' + Plug 'sheerun/vim-polyglot' + Plug 'dbeniamine/vim-mail' + Plug 'ap/vim-css-color' + " notes + Plug 'dhruvasagar/vim-table-mode' + Plug 'jceb/vim-orgmode' + " headers and source + Plug 'vim-scripts/a.vim' + Plug 'majutsushi/tagbar' + " git + Plug 'airblade/vim-gitgutter' + Plug 'tpope/vim-fugitive' + Plug 'jreybert/vimagit' + Plug 'junegunn/gv.vim' + " python + Plug 'petobens/poet-v' + call plug#end() +endif + +" indentation +set smarttab +set autoindent +set nocompatible +set tabstop=8 +set shiftwidth=8 +set softtabstop=8 +set noexpandtab +set list lcs=tab:\|\ ". +set fillchars+=vert:\ ". +set ve+=onemore +set list +set shortmess=atToOF + +" plugins settings +let g:ale_sign_error = '' +let g:ale_sign_warning = '' +let g:ale_c_clang_options='-std=gnu99 -Wall' +let g:ale_c_gcc_options='-std=gnu99 -Wall' +let g:ale_sh_shellcheck_options = '-e SC1090 SC2181 -e SC2155' +let g:ale_python_flake8_options = '--ignore=E501' +let g:ale_linters = { 'python': ['bandit', 'flake8'], } + +let g:gitgutter_max_signs = 500 +let g:gitgutter_sign_added = '+' +let g:gitgutter_sign_modified = '~' +let g:gitgutter_sign_removed = '-' +let g:gitgutter_sign_modified_removed = '-' + +let g:indent_guides_enable_on_vim_startup = 0 +let g:indent_guides_auto_colors = 0 +let g:indent_cuides_exclude_filetypes = [ + \'help', + \'terminal' + \] +let g:poetv_executables = ['poetry'] +let g:poetv_auto_activate = 1 + +let g:python_host_prog = system('which python2')[:-2] +let g:python3_host_prog = system('which python3')[:-2] +let g:jedi#auto_initialization = 1 +let g:jedi#popup_on_dot = 0 + +let g:NERDTreeAutoDeleteBuffer = 1 +let g:NERDTreeMinimalUI = 1 +let g:NERDTreeDirArrowExpandable = '+' +let g:NERDTreeDirArrowCollapsible = '-' + +let g:EditorConfig_exclude_patterns = ['fugitive://.*', 'scp://.*'] +let g:fzf_layout = { 'down': '40%'} +let g:magit_default_fold_level = 2 +let g:sql_type_default = 'pgsql' +let g:table_mode_always_active = 0 + +if uname == 'OpenBSD' + let g:ncm2_pyclang#library_path = '/usr/local/lib/libclang.so.8.1' + let g:completor_python_binary = '/usr/bin/python3' +endif + +" netrw +let g:netrw_banner = 0 +let g:netrw_browse_split = 4 +let g:netrw_liststyle = 3 +let g:netrw_altv = 1 +let g:netrw_winsize = 25 +let g:netrw_list_hide = '\(^\|\s\s\)\zs\.\S\+' + +autocmd BufNewFile,BufReadPost *.{yaml,yml} set filetype=yaml +autocmd BufNewFile,BufReadPost */*ssh/config.d/* set syntax=sshconfig +autocmd BufNewFile,BufReadPost */*ansible*/**/*.yml set filetype=yaml.ansible +autocmd BufNewFile,BufRead ~/.config/i3/config set filetype=i3config +autocmd BufNewFile,BufRead ~/.config/sway/config set filetype=i3config +autocmd BufNewFile,BufRead ~/.config/polybar/config set filetype=dosini +autocmd FileType conf let b:EditorConfig_disable = 1 +autocmd FileType gitcommit let b:EditorConfig_disable = 1 +autocmd FileType java setlocal omnifunc=javacomplete#Complete +autocmd FileType yaml let b:EditorConfig_disable = 1 + +" statusline +set statusline= +set statusline+=\ %f +set statusline+=%m +set statusline+=%= +set statusline+=\ %y +set statusline+=\ %{&fileencoding?&fileencoding:&encoding} +set statusline+=\ [%{&fileformat}\] +set statusline+=\ %p%% +set statusline+=\ %l:%c +set statusline+=\ + +" completion +set omnifunc=syntaxcomplete#Complete +set completeopt=longest,menuone + +" commands +command! PlugSync PlugClean | + \ PlugInstall | + \ UpdateRemotePlugins +command! GitGutterCustomToggle GitGutterLineHighlightsToggle | + \ GitGutterLineNrHighlightsToggle +command! Gblame Git blame + +" cnoremap :call CommandCallback() + +function! s:SyncColorcolumnColorscheme() + let l:length = '/\%' . string(&colorcolumn + 1) . 'v.\+/' + execute 'match' 'OverLength' l:length +endfunction + +function! s:CommandCallback() + let l:last_command = @: + + if l:last_command =~ 'set colorcolumn' + call s:SyncColorcolumnColorscheme() + endif +endfunction + +function! s:Init() + call s:SyncColorcolumnColorscheme() +endfunction diff --git a/.config/nvim/lua/ftplugin/common-markup.lua b/.config/nvim/lua/ftplugin/common-markup.lua new file mode 100755 index 0000000..956a163 --- /dev/null +++ b/.config/nvim/lua/ftplugin/common-markup.lua @@ -0,0 +1,3 @@ +bo.expandtab = true +bo.shiftwidth = 2 +bo.tabstop = 2 diff --git a/.config/nvim/lua/ftplugin/common-space.lua b/.config/nvim/lua/ftplugin/common-space.lua new file mode 100755 index 0000000..ccefb94 --- /dev/null +++ b/.config/nvim/lua/ftplugin/common-space.lua @@ -0,0 +1,5 @@ +bo.tabstop=4 +bo.shiftwidth=4 +bo.textwidth=0 +bo.wrapmargin=0 +bo.expandtab = true diff --git a/.config/nvim/lua/ftplugin/init.lua b/.config/nvim/lua/ftplugin/init.lua new file mode 100755 index 0000000..906b7a1 --- /dev/null +++ b/.config/nvim/lua/ftplugin/init.lua @@ -0,0 +1,2 @@ +package.path = package.path .. ';' .. vim.fn.stdpath('config') .. '/ftplugin/?.lua' +package.path = package.path .. ';' .. vim.fn.stdpath('config') .. '/after/ftplugin/?.lua' diff --git a/.config/nvim/lua/keymaps.lua b/.config/nvim/lua/keymaps.lua new file mode 100755 index 0000000..070ddc9 --- /dev/null +++ b/.config/nvim/lua/keymaps.lua @@ -0,0 +1,24 @@ +--[[ +-- Keymaps +--]] + +local map = vim.api.nvim_set_keymap +local cmd = vim.cmd + +options = {noremap=true} + +map('i', '', '', options) +map('i', '', '', options) +map('i', '', '', options) +map('i', '', '', options) +map('i', '', '', options) + +map('', '', ':NvimTreeToggle', options) + +--[[ +map('n', '', '', 'compe#complete()', options) +map('n', '', '', 'compe#confirm(\'\'', options) +map('n', '', '', 'compe#close(\'\'', options) +map('n', '', '', 'compe#scroll({\'delta\': +4}', options) +map('n', '', '', 'compe#scroll({\'delta\': -4}', options) +--]] diff --git a/.config/nvim/lua/lsp.lua b/.config/nvim/lua/lsp.lua new file mode 100755 index 0000000..95d9409 --- /dev/null +++ b/.config/nvim/lua/lsp.lua @@ -0,0 +1,17 @@ +--[[ +-- lsp +--]] + +local lsp = vim.lsp + +lsp.handlers["textDocument/publishDiagnostics"] = lsp.with( + lsp.diagnostic.on_publish_diagnostics, + { + underline = false, + virtual_text = { + prefix = "▒ ", + spacing = 8, + }, + signs = true, + } +) diff --git a/.config/nvim/lua/plugins.lua b/.config/nvim/lua/plugins.lua new file mode 100755 index 0000000..24736eb --- /dev/null +++ b/.config/nvim/lua/plugins.lua @@ -0,0 +1,145 @@ +--[[ +-- Plugins +--]] + +-- Bootstrap for Paq +local install_path = vim.fn.stdpath('data')..'/site/pack/paqs/start/paq-nvim' +if vim.fn.empty(vim.fn.glob(install_path)) > 0 then + vim.fn.system({ + 'git', 'clone', '--depth=1', + 'https://github.com/savq/paq-nvim.git', + install_path + }) + vim.cmd 'packadd paq-nvim' +end + +-- Enable Paq +vim.cmd 'packadd paq-nvim' + +-- Plugin list +require('paq') { + {'savq/paq-nvim'}; + + -- lsp + { + 'nvim-treesitter/nvim-treesitter', + run=':TSUpdate' + }; + { + 'neovim/nvim-lspconfig', + run='python3 -m pipx install python-lsp-server[all]' + }; + { + 'numirias/semshi', + run=':UpdateRemotePlugins' + }; + + -- utils + {'folke/trouble.nvim'}; + {'hrsh7th/nvim-compe'}; + + -- org + {'TimUntersberger/neogit'}; + {'kyazdani42/nvim-tree.lua'}; + + -- indent + {'lewis6991/gitsigns.nvim'}; + {'glepnir/indent-guides.nvim'}; + {'darazaki/indent-o-matic'}; + + -- dep + {'nvim-lua/plenary.nvim'}; +} + +-- Treesitter + +local parser_configs = require('nvim-treesitter.parsers').get_parser_configs() + +require('nvim-treesitter.configs').setup { + ensure_installed = 'maintained', + ignore_install = { + 'verilog', + 'kotlin' + }, + highlight = { + enable = true, + } +} + +-- completion + +require('compe').setup { + enabled = true, + source = { + path = true; + buffer = true; + calc = true; + nvim_lsp = true; + nvim_lua = true; + vsnip = true; + ultisnips = true; + luasnip = true; + neorg = true; + }; +} + +-- LSP configuration + +local lsputil = require('lspconfig/util') +local python_venv = require('utils').get_python_venv() +require('lspconfig').pylsp.setup{ + cmd = {'pylsp', '-v'}, + cmd_env = { + VIRTUAL_ENV = python_venv, + PATH = lsputil.path.join(python_venv, 'bin') .. ':' .. vim.env.PATH + }, +} + +require('lspconfig').clangd.setup{} +require('lspconfig').eslint.setup{} +require('lspconfig').terraformls.setup{} + +-- org + +require('trouble').setup{} +require('neogit').setup{} + +-- syntactic sugar + +require('indent_guides').setup{ + indent_enable=true; + exclude_filetypes={ + 'help', + 'calendar', + 'NvimTree' + }; +} + +require('indent-o-matic').setup { + max_lines = 0, + standard_widths = { 2, 4, 8 }, + + filetype_typescript = { + max_lines = 4096, + }, + + filetype_javascript = { + max_lines = 4096, + }, + + filetype_ = { + standard_widths = { 2, 4 }, + }, +} + +vim.g['semshi#update_delay_factor'] = 0.0001 + +require('gitsigns').setup{ + signs = { + add = {hl = 'GitSignsAdd' , text = '▍', numhl='GitSignsAddNr' , linehl='GitSignsAddLn'}, + change = {hl = 'GitSignsChange', text = '▍', numhl='GitSignsChangeNr', linehl='GitSignsChangeLn'}, + delete = {hl = 'GitSignsDelete', text = '▍', numhl='GitSignsDeleteNr', linehl='GitSignsDeleteLn'}, + topdelete = {hl = 'GitSignsDelete', text = '▍', numhl='GitSignsDeleteNr', linehl='GitSignsDeleteLn'}, + changedelete = {hl = 'GitSignsChange', text = '▍', numhl='GitSignsChangeNr', linehl='GitSignsChangeLn'}, + } +} diff --git a/.config/nvim/lua/settings.lua b/.config/nvim/lua/settings.lua new file mode 100755 index 0000000..2741c99 --- /dev/null +++ b/.config/nvim/lua/settings.lua @@ -0,0 +1,30 @@ +bo.expandtab = false +bo.shiftwidth = 8 +bo.softtabstop = 8 + +o.completeopt = 'longest,menuone' +o.shell = '/bin/sh' +o.encoding = 'utf-8' +o.scrolloff = 3 +o.lazyredraw = true +o.autochdir = true +o.smarttab = true +o.number = true +o.list = true + +o.swapfile = false + +-- o.foldmethod = 'expr' +-- o.foldexpr = 'nvim_treesitter#foldexpr()' + +cmd 'syntax enable' +cmd 'filetype on' +cmd 'filetype plugin on' +cmd 'filetype indent on' +cmd 'colorscheme colorscheme' + +vim.cmd([[ +au BufNewFile,BufRead *.Dockerfile,Dockerfile.* setlocal filetype=dockerfile +au BufNewFile,BufRead *.j2*,*.jinja* setlocal filetype=django +au BufNewFile,BufRead *.env* setlocal filetype=sh +]]) diff --git a/.config/nvim/lua/statusline.lua b/.config/nvim/lua/statusline.lua new file mode 100755 index 0000000..099d930 --- /dev/null +++ b/.config/nvim/lua/statusline.lua @@ -0,0 +1,54 @@ +--[[ +-- Statusline +--]] + +local api = vim.api +local cmd = vim.cmd +local utils = require('utils') + +function _(str) + return '[' .. str .. ']' +end + +function set_split() + return '%m%=' +end + +function get_separator() + return ' ' +end + +function get_file() + return '%f' +end + +function get_fileformat() + return '%{&fileformat}' +end + +function get_fileencoding() + return '%{&fileencoding?&fileencoding:&encoding}' +end + +function get_scrollposition() + return '%p%%' +end + +function get_cursorposition() + return '%l:%c' +end + +function get_statusline() + return table.concat({ + get_file(), + set_split(), + _(get_fileencoding()), + _(get_fileformat()), + _(get_scrollposition()), + _(get_cursorposition()), + }) +end + +-- Enable statusline +utils.opt('o', 'laststatus', 2) +utils.opt('o', 'statusline', get_statusline()) diff --git a/.config/nvim/lua/utils.lua b/.config/nvim/lua/utils.lua new file mode 100755 index 0000000..ae164e8 --- /dev/null +++ b/.config/nvim/lua/utils.lua @@ -0,0 +1,46 @@ +local utils = {} + +local scopes = {o = vim.o, b = vim.bo, w = vim.wo} + +--- Apply a setting with a specified scope +function utils.opt(scope, key, value) + scopes[scope][key] = value + if scope ~= 'o' then scopes['o'][key] = value end +end + +--- Apply an array of settings +function utils.opts(params) + for i, item in ipairs(params) do + utils.opt(item[1], item[2], item[3]) + end +end + +--- Key mapping +function utils.map(mode, lhs, rhs, opts) + local options = {noremap = true} + if opts then options = vim.tbl_extend('force', options, opts) end + vim.api.nvim_set_keymap(mode, lhs, rhs, options) +end + +function utils.get_python_venv() + local lsputil = require('lspconfig/util') + local match + + if vim.env.VIRTUAL_ENV then + return vim.env.VIRTUAL_ENV + end + + match = vim.fn.glob(lsputil.path.join(vim.fn.getcwd(), 'Pipfile')) + if match ~= '' then + return vim.fn.trim(vim.fn.system('PIPENV_PIPFILE=' .. match .. ' pipenv --venv')) + end + + match = vim.fn.system('test -f poetry.lock && poetry env info -p') + if vim.v.shell_error then + return vim.fn.trim(match) + end + + return '' +end + +return utils diff --git a/.config/qutebrowser/config.py b/.config/qutebrowser/config.py new file mode 100755 index 0000000..13dca3f --- /dev/null +++ b/.config/qutebrowser/config.py @@ -0,0 +1,111 @@ + +# ~/.config/qutebrowser/config.py +# rgoncalves.se + +import logging +import os +import re +import subprocess +import platform + +logging.basicConfig(level=logging.DEBUG) + +""" +Bypass flake8 warnings. +""" +try: + config +except NameError: + config = None + + +def select_rendering_method(): + """ + Select best rendering method depending on hardware and system. + """ + method = 'none' + + if platform.uname().system in 'Linux': + lspci_bin = subprocess.run(['lspci'], stdout=subprocess.PIPE) + if re.search('NVIDIA', lspci_bin.stdout.decode('utf-8')) is None: + method = 'qt-quick' + + return method + + +def select_qt_arguments(): + """ + Select best arguments for launching qutebrowser. + Empty by default, it picks lag free options for musl systems. + """ + args = [] + ls_bin = os.popen("ldd /bin/ls").read() + + if re.search('musl', ls_bin) is not None: + args.append('disable-seccomp-filter-sandbox') + + return args + + +config.load_autoconfig(False) +config.set('auto_save.session', True) +config.set('scrolling.smooth', False) +config.set('qt.highdpi', False) +config.set('qt.force_software_rendering', select_rendering_method()) +config.set('qt.args', select_qt_arguments()) + +config.bind(',m', 'spawn mpv {url}') + +config.set('content.images', True, 'chrome-devtools://*') +config.set('content.images', True, 'devtools://*') +config.set('content.javascript.enabled', True, 'chrome-devtools://*') +config.set('content.javascript.enabled', True, 'devtools://*') +config.set('content.javascript.enabled', True, 'chrome://*/*') +config.set('content.javascript.enabled', True, 'qute://*/*') + +config.set('content.notifications.enabled', False) +config.set('content.notifications.enabled', True, '*://*.zoho.eu/*') +config.set('content.notifications.enabled', True, '*://*.viperdev.io/*') +config.set('content.notifications.enabled', True, '*://*.rgoncalves.se/*') + +config.set('content.register_protocol_handler', False) +config.set('content.geolocation', False) +config.set('content.media.audio_video_capture', True, '*://*.zoho.eu/*') +config.set('content.media.audio_capture', True, '*://*.zoho.eu/*') +config.set('content.media.video_capture', True, '*://*.zoho.eu/*') + +config.set('completion.web_history.max_items', 0) +config.set('tabs.background', True) +config.set('tabs.indicator.width', 3) +config.set('tabs.indicator.padding', + {'bottom': 0, 'left': 1, 'right': 4, 'top': 0}) + +config.set('fonts.default_family', 'Terminus') +config.set('fonts.default_size', '12pt') + +config.set('colors.tabs.bar.bg', '#000000') +config.set('colors.tabs.even.bg', '#000000') +config.set('colors.tabs.even.fg', '#ffffff') +config.set('colors.tabs.odd.bg', '#000000') +config.set('colors.tabs.odd.fg', '#ffffff') +config.set('colors.tabs.indicator.system', 'none') +config.set('colors.tabs.selected.even.bg', '#ffffff') +config.set('colors.tabs.selected.even.fg', '#000000') +config.set('colors.tabs.selected.odd.bg', '#ffffff') +config.set('colors.tabs.selected.odd.fg', '#000000') +config.set('colors.tabs.pinned.selected.even.bg', '#ffffff') +config.set('colors.tabs.pinned.selected.odd.bg', '#ffffff') +config.set('colors.tabs.pinned.selected.even.fg', '#000000') +config.set('colors.tabs.pinned.selected.odd.fg', '#000000') +config.set('colors.tabs.indicator.error', '#ff0000') + +config.set('content.prefers_reduced_motion', True) +config.set('content.headers.referer', 'same-domain') +config.set('url.default_page', 'https://lite.duckduckgo.com/lite/') +config.set('url.start_pages', 'https://lite.duckduckgo.com/lite/') +config.set('url.searchengines', + {'DEFAULT': 'https://lite.duckduckgo.com/lite/?q={}'}) + +config.set('downloads.location.directory', f'{os.environ["HOME"]}/downloads') +config.set('content.autoplay', False) +config.set('content.cookies.accept', 'no-3rdparty') diff --git a/.config/qutebrowser/greasemonkey/boursorama-css.js b/.config/qutebrowser/greasemonkey/boursorama-css.js new file mode 100755 index 0000000..4d1c29e --- /dev/null +++ b/.config/qutebrowser/greasemonkey/boursorama-css.js @@ -0,0 +1,18 @@ +// ==UserScript== +// @name boursorama css +// @match *://*.boursorama.com/* +// @grant none +// ==/UserScript== + +GM_addStyle(` + .chatbot, + .c-promotional-cards-wrapper, + .c-articles-wrapper, + .c-offers__entry-card { + width: 0px !important; + height: 0px !important; + visibility: hidden; + margin: 0px; + padding: 0px; + } +`) diff --git a/.config/qutebrowser/greasemonkey/duckduckgo.js b/.config/qutebrowser/greasemonkey/duckduckgo.js new file mode 100755 index 0000000..d4d971f --- /dev/null +++ b/.config/qutebrowser/greasemonkey/duckduckgo.js @@ -0,0 +1,12 @@ +// ==UserScript== +// @name custom duckduckgo +// @match https://duckduckgo.com/* +// @grant none +// ==/UserScript== + +GM_addStyle(` + .result--ads { + visibility: hidden !important; + height: 0px !important; + } +`) diff --git a/.config/qutebrowser/greasemonkey/github-css.js b/.config/qutebrowser/greasemonkey/github-css.js new file mode 100755 index 0000000..7b32636 --- /dev/null +++ b/.config/qutebrowser/greasemonkey/github-css.js @@ -0,0 +1,12 @@ +// ==UserScript== +// @name github css +// @match *://github.com/* +// @match *://gist.github.com/* +// @grant none +// ==/UserScript== + +GM_addStyle(` + *, .BtnGroup-item { + border-radius: 0px !important; + } +`) diff --git a/.config/qutebrowser/greasemonkey/imgur-to-imgin.js b/.config/qutebrowser/greasemonkey/imgur-to-imgin.js new file mode 100755 index 0000000..d4ac434 --- /dev/null +++ b/.config/qutebrowser/greasemonkey/imgur-to-imgin.js @@ -0,0 +1,8 @@ +// ==UserScript== +// @name imgur to imgin +// @match *://imgur.com/* +// @grant none +// @run-at document-start +// ==/UserScript== + +top.location.hostname = "imgin.voidnet.tech"; diff --git a/.config/qutebrowser/greasemonkey/instagram-to-bibliogram.js b/.config/qutebrowser/greasemonkey/instagram-to-bibliogram.js new file mode 100755 index 0000000..a608059 --- /dev/null +++ b/.config/qutebrowser/greasemonkey/instagram-to-bibliogram.js @@ -0,0 +1,8 @@ +// ==UserScript== +// @name instagram to biliogram +// @match *://*.instagram.com/* +// @grant none +// @run-at document-start +// ==/UserScript== + +top.location.hostname = "bibliogram.art"; diff --git a/.config/qutebrowser/greasemonkey/medium-to-scribe.js b/.config/qutebrowser/greasemonkey/medium-to-scribe.js new file mode 100755 index 0000000..5a94ab0 --- /dev/null +++ b/.config/qutebrowser/greasemonkey/medium-to-scribe.js @@ -0,0 +1,8 @@ +// ==UserScript== +// @name medium to scribe +// @match *://*.medium.com/* +// @grant none +// @run-at document-start +// ==/UserScript== + +top.location.hostname = "scribe.rip"; diff --git a/.config/qutebrowser/greasemonkey/miniflux.js b/.config/qutebrowser/greasemonkey/miniflux.js new file mode 100755 index 0000000..4b17b17 --- /dev/null +++ b/.config/qutebrowser/greasemonkey/miniflux.js @@ -0,0 +1,83 @@ +// ==UserScript== +// @name custom miniflux +// @match *://miniflux.rgoncalves.se/*NONE +// @grant none +// ==/UserScript== + +function get_img_content(content) { + var object = document.createElement("div"); + object.innerHTML = content; + + try { + url = object.getElementsByTagName("img")[0].src; + } catch (error) { + url = undefined; + } + + return url; +} + +function add_entry_images(article) { + var article_meta = article.getElementsByClassName("item-meta")[0]; + var article_frame = document.createElement("div"); + var article_id = article.getElementsByClassName("item-title")[0] + .getElementsByTagName("a")[0] + .href + .split("/") + .splice(-1, 1); + + article_meta.appendChild(article_frame); + + fetch(`/v1/entries/${article_id}`) + .then(res => res.json()) + .then((res) => { + var url; + + try { + url = res["enclosures"][0]["url"]; + } catch (error) { + url = get_img_content(res["content"]); + } + + if (typeof url === 'undefined') { + return; + } + + console.log(url); + + img = document.createElement("img"); + img.src = url; + img.style.width = "100%"; + img.style.minHeight = "100px"; + img.loading = "lazy"; + + article_frame.appendChild(img); + }) +} + +function has_displayable_image(article) { + category = article.getElementsByClassName("category")[0] + .getElementsByTagName("a")[0] + .innerText; + + return category === "blog" + || category === "hn" + || category === "social" + || category === "yt"; +} + +details = document.getElementsByTagName("details"); + +for (let detail of details) { + detail.open = true; +} + +articles = document.getElementsByTagName("article"); + +for (let article of articles) { + if (! has_displayable_image(article)) { + continue; + } + + add_entry_images(article); +} diff --git a/.config/qutebrowser/greasemonkey/minimal-css.js b/.config/qutebrowser/greasemonkey/minimal-css.js new file mode 100755 index 0000000..1fe1414 --- /dev/null +++ b/.config/qutebrowser/greasemonkey/minimal-css.js @@ -0,0 +1,16 @@ +// ==UserScript== +// @name minimal css +// @match *://www.google.com +// @match *://www.google.com/search* +// @match *://cliq.zoho.eu/chats/* +// @match *://www.pinterest.com/* +// @grant none +// ==/UserScript== + +GM_addStyle(` + * { + border-radius: 0px !important; + transition: none !important; + animation: none !important; + } +`) diff --git a/.config/qutebrowser/greasemonkey/no-sticky-headers.js b/.config/qutebrowser/greasemonkey/no-sticky-headers.js new file mode 100755 index 0000000..e5eefa1 --- /dev/null +++ b/.config/qutebrowser/greasemonkey/no-sticky-headers.js @@ -0,0 +1,15 @@ +// ==UserScript== +// @name no sticky header +// @match *://*.substack.com/* +// @grant none +// ==/UserScript== + +(function () { + var i, elements = document.querySelectorAll('body *'); + + for (i = 0; i < elements.length; i++) { + if (getComputedStyle(elements[i]).position === 'fixed') { + elements[i].parentNode.removeChild(elements[i]); + } + } +})(); diff --git a/.config/qutebrowser/greasemonkey/reddit-to-teddit.js b/.config/qutebrowser/greasemonkey/reddit-to-teddit.js new file mode 100755 index 0000000..8c1ee6b --- /dev/null +++ b/.config/qutebrowser/greasemonkey/reddit-to-teddit.js @@ -0,0 +1,9 @@ +// ==UserScript== +// @name reddit to teddit +// @match *://*.reddit.com/* +// @match *://reddit.com/* +// @grant none +// @run-at document-start +// ==/UserScript== + +top.location.hostname = "teddit.net"; diff --git a/.config/qutebrowser/greasemonkey/scaleway-css.js b/.config/qutebrowser/greasemonkey/scaleway-css.js new file mode 100755 index 0000000..99955ca --- /dev/null +++ b/.config/qutebrowser/greasemonkey/scaleway-css.js @@ -0,0 +1,11 @@ +// ==UserScript== +// @name scaleway css +// @match *://*.scaleway.com/* +// @grant none +// ==/UserScript== + +GM_addStyle(` + #outdated { + visibility: hidden; + } +`) diff --git a/.config/qutebrowser/greasemonkey/scribe-css.js b/.config/qutebrowser/greasemonkey/scribe-css.js new file mode 100755 index 0000000..60fc0e2 --- /dev/null +++ b/.config/qutebrowser/greasemonkey/scribe-css.js @@ -0,0 +1,16 @@ +// ==UserScript== +// @name scribe css +// @match *://scribe.rip/* +// @grant none +// ==/UserScript== + +GM_addStyle(` + body { + background-color: #ffffff; + font-family: monospace, monospace; + } + img { + border: 1px solid #000000; + } +`) + diff --git a/.config/qutebrowser/greasemonkey/stackoverflow-css.js b/.config/qutebrowser/greasemonkey/stackoverflow-css.js new file mode 100755 index 0000000..6c98466 --- /dev/null +++ b/.config/qutebrowser/greasemonkey/stackoverflow-css.js @@ -0,0 +1,15 @@ +// ==UserScript== +// @name stackoverflow css +// @match *://*.stackoverflow.com/* +// @match *://*.stackexchange.com/* +// @match *://*.superuser.com/* +// @match *://*.serverfault.com/* +// @grant none +// ==/UserScript== + +GM_addStyle(` + .js-consent-banner, + .js-freemium-cta { + visibility: hidden; + } +`) diff --git a/.config/qutebrowser/greasemonkey/twitter-to-nitter.js b/.config/qutebrowser/greasemonkey/twitter-to-nitter.js new file mode 100755 index 0000000..f4c3518 --- /dev/null +++ b/.config/qutebrowser/greasemonkey/twitter-to-nitter.js @@ -0,0 +1,9 @@ +// ==UserScript== +// @name twitter to nitter +// @match *://*.twitter.com/* +// @match *://twitter.com/* +// @grant none +// @run-at document-start +// ==/UserScript== + +top.location.hostname = "nitter.net"; diff --git a/.config/qutebrowser/greasemonkey/youtube-to-yewtube.js b/.config/qutebrowser/greasemonkey/youtube-to-yewtube.js new file mode 100755 index 0000000..c8f73f1 --- /dev/null +++ b/.config/qutebrowser/greasemonkey/youtube-to-yewtube.js @@ -0,0 +1,9 @@ +// ==UserScript== +// @name youtube to yewtube +// @match *://*.youtube.com/* +// @match *://youtube.com/* +// @grant none +// @run-at document-start +// ==/UserScript== + +top.location.hostname = "yewtu.be"; diff --git a/.config/sway/config b/.config/sway/config new file mode 100755 index 0000000..1dd249e --- /dev/null +++ b/.config/sway/config @@ -0,0 +1,166 @@ + +# ~/.config/sway/config + +# variables +set $mod Mod1 +set $left h +set $down j +set $up k +set $right l +set $term alacritty --config-file ~/.config/alacritty/hidpi.yml +set $i3status ~/.config/common.d/i3status_ext.sh +set $status ~/.bin/dwmstatus -l +set $launcher ~/.config/common.d/bemenu.sh + +# input +input * { + xkb_layout us + #xkb_variant altgr-intl + xkb_variant ,nodeadkeys + xkb_options compose:ralt + repeat_delay 300 + repeat_rate 50 +} +input "1739:30383:DELL07E6:00_06CB:76AF_Touchpad" { + tap enabled +} + +# output +output eDP-1 scale 2 +output * bg #000000 solid_color +#output * bg ~/pictures/wallpaper/wallpaper_sway fill + +# workspaces +set $ws1 "1" +set $ws2 "2" +set $ws3 "3" +set $ws4 "4" +set $ws5 "5" +set $ws6 "6" + +# keybindings +floating_modifier $mod normal +bindsym $mod+Return exec $term +bindsym $mod+Shift+q kill +bindsym $mod+d exec "$launcher run" +bindsym $mod+Shift+d exec "$launcher pass" +bindsym $mod+Shift+s exec "$launcher colorscheme" +bindsym $mod+Shift+r reload +bindsym $mod+Shift+e exec swaynag -t warning -m "" -b "EXIT SWAY" "swaymsg exit" +bindsym $mod+$left focus left +bindsym $mod+$down focus down +bindsym $mod+$up focus up +bindsym $mod+$right focus right +bindsym $mod+Shift+$left move left +bindsym $mod+Shift+$down move down +bindsym $mod+Shift+$up move up +bindsym $mod+Shift+$right move right +bindsym $mod+1 workspace $ws1 +bindsym $mod+2 workspace $ws2 +bindsym $mod+3 workspace $ws3 +bindsym $mod+4 workspace $ws4 +bindsym $mod+5 workspace $ws5 +bindsym $mod+6 workspace $ws6 +bindsym $mod+Shift+1 move container to workspace $ws1 +bindsym $mod+Shift+2 move container to workspace $ws2 +bindsym $mod+Shift+3 move container to workspace $ws3 +bindsym $mod+Shift+4 move container to workspace $ws4 +bindsym $mod+Shift+5 move container to workspace $ws5 +bindsym $mod+Shift+6 move container to workspace $ws6 +bindsym $mod+Tab workspace back_and_forth +bindsym $mod+b splith +bindsym $mod+v splitv +bindsym $mod+s layout stacking +bindsym $mod+w layout tabbed +bindsym $mod+e layout toggle split +bindsym $mod+f fullscreen +bindsym $mod+Shift+space floating toggle +bindsym $mod+space focus mode_toggle +bindsym $mod+a focus parent +bindsym $mod+Shift+minus move scratchpad +bindsym $mod+minus scratchpad show +bindsym $mod+r mode "resize" +# keybidings mutlimeda keys +bindsym XF86AudioMute exec "pamixer --toggle-mute" +bindsym XF86AudioRaiseVolume exec "pamixer -i 5 -u" +bindsym XF86AudioLowerVolume exec "pamixer -d 5 -u" +bindsym XF86MonBrightnessUp exec "light -A 10" +bindsym XF86MonBrightnessDown exec "light -U 10" +bindsym XF86AudioPlay exec "~/bin/audio toggle" +bindsym XF86AudioNext exec "~/.bin/audio next" +bindsym XF86AudioPrev exec "~/.bin/audio prev" +mode "resize" { + bindsym $left resize shrink width 10px + bindsym $down resize grow height 10px + bindsym $up resize shrink height 10px + bindsym $right resize grow width 10px + bindsym Return mode "default" + bindsym Escape mode "default" +} + +# default workspaces +assign [class="qutebrowser"] $ws2 + +# default floating +for_window [class="jetbrains-(.*)" title="Go to Line/Column"] floating enable +for_window [class="jetbrains-(.*)" title="Rename"] floating enable +for_window [class="jetbrains-(.*)" title="Open Project"] floating enable +for_window [class="jetbrains-(.*)" title="win0"] floating enable +for_window [title="win0"] floating enable +for_window [app_id="waybar" floating] { + move position cursor + move down 50px # adjust if some menus still don't fit +} + +# style +gaps inner 0 +gaps outer 0 +font TerminessTTF Nerd Font 10 +default_border pixel 1 +titlebar_padding 1 +for_window [title="win0"] floating enable + +# colorscheme +set $fg #22ff22 +set $bg #000000 +set $gr #222222 +set $wh #ffffff +# class border backgr. text indicator child_border +client.focused $wh $wh $bg $wh $wh +client.focused_inactive $gr $gr $wh $gr $gr +client.unfocused $gr $gr $wh $gr $gr +client.urgent $bg $bg $fg $bg $bg +client.placeholder $bg $bg $fg $bg $bg + +# i3bar +bar { + status_command $status + position top + strip_workspace_numbers yes + font Terminus 10 + colors { + statusline $wh + separator $wh + background $bg + # colorclass border background text + focused_workspace $wh $wh $bg + active_workspace $bg $bg $wh + inactive_workspace $bg $bg $wh + } +} + +# auto-exec +exec_always xrdb ~/.Xdefaults +exec redshift +exec libinput-gestures-setup start +exec light -S 10 +exec swayidle -w before-sleep "$HOME/.bin/lock -s" + +# gtk-settings for wayland +set $gnome-schema org.gnome.desktop.interface +exec_always { + gsettings set $gnome-schema gtk-theme "Raleigh" + gsettings set $gnome-schema icon-theme "Adwaita" + gsettings set $gnome-schema cursor-theme "Adwaita" +} + diff --git a/.config/tmux/tmux.conf b/.config/tmux/tmux.conf new file mode 100755 index 0000000..81e5d4f --- /dev/null +++ b/.config/tmux/tmux.conf @@ -0,0 +1,14 @@ +# mod key +set-option -g prefix ` +set-option -g mouse off +set-option -g mode-keys vi +set-option -g escape-time 0 +# set-option -g default-terminal "screen-256color" +set-option -g history-limit 5000 +set -s escape-time 0 + +# keybindings +bind-key ` last-window +bind-key j next-window +bind-key k previous-window +bind-key e send-prefix diff --git a/.config/user-dirs.dirs b/.config/user-dirs.dirs new file mode 100755 index 0000000..0e54d8c --- /dev/null +++ b/.config/user-dirs.dirs @@ -0,0 +1,15 @@ +# This file is written by xdg-user-dirs-update +# If you want to change or add directories, just edit the line you're +# interested in. All local changes will be retained on the next run. +# Format is XDG_xxx_DIR="$HOME/yyy", where yyy is a shell-escaped +# homedir-relative path, or XDG_xxx_DIR="/yyy", where /yyy is an +# absolute path. No other format is supported. +# +XDG_DOWNLOAD_DIR="$HOME/downloads" +XDG_DOCUMENTS_DIR="$HOME/" +XDG_MUSIC_DIR="$HOME/" +XDG_PICTURES_DIR="$HOME/pictures" +XDG_DESKTOP_DIR="$HOME/" +XDG_TEMPLATES_DIR="$HOME/" +XDG_PUBLICSHARE_DIR="$HOME/" +XDG_VIDEOS_DIR="$HOME/" diff --git a/.config/user-dirs.locale b/.config/user-dirs.locale new file mode 100755 index 0000000..3e0b419 --- /dev/null +++ b/.config/user-dirs.locale @@ -0,0 +1 @@ +en_US \ No newline at end of file diff --git a/.gnupg/gpg-agent.conf b/.gnupg/gpg-agent.conf new file mode 100755 index 0000000..9d344b4 --- /dev/null +++ b/.gnupg/gpg-agent.conf @@ -0,0 +1,3 @@ +use-standard-socket +enable-ssh-support +pinentry-program /home/qwd/.bin/pinentry-common diff --git a/.kshrc b/.kshrc new file mode 100755 index 0000000..a4e5a8c --- /dev/null +++ b/.kshrc @@ -0,0 +1,13 @@ +# ~/.kshrc +# echo export ENV=$HOME/.kshrc >> ~/.profile + +[ -f ~/.cprofile ] && . ~/.cprofile + +HOST=$(hostname) +PS1='${USER}@${HOST%%.*} $(pwd | sed "s,^$HOME,~,") $ ' + +export PS1 + +set -o vi +set -o vi-tabcomplete + diff --git a/.public-keys/0xF85CD02DB419D68C b/.public-keys/0xF85CD02DB419D68C new file mode 100755 index 0000000..eca02c8 --- /dev/null +++ b/.public-keys/0xF85CD02DB419D68C @@ -0,0 +1,109 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mQINBF5zMOcBEADL3CTqwOUm6S9LlrBo72oOHn3RCpZH7VpogE/ynNID2lsajPG8 +Izsfuy2WuUOyS5rJaUwUa/eitR5fEAjJWeDaDXDuYZAE2J1ZwkFavXQAI01H7Efb +jkPUGiIXtnVWt70uifPCugYyIW4LzTLai5bxE8mrjTXVNq/R36trg+BKVim5QXLZ +mKytNjuUmQANZcgQpeNjW/nXrCsYRd0qpqdqVynEalPX2EZaFZGQYZ3rL+pXpR4e +PH5SmuC4Q5+HoD/qzLjtG+k78PzZj3x+hjC3hm+FRH+CrovYZVQOLshX7FkAfCS0 +u8n1mRoYODfzrZbrT462aAEaZEKd+5JMa3NwHdxTNgWP7oeQqAKztMeKXE+iJ3B6 +q3J5pmJfywxGCyGk7MJUaIF+kFo0qDVdT/Vt/rcR7flfKPug0UdXhAt0Ttpl450/ +fe3+hs1N8Ajix8RKIU5Gcvx4RFH8BdkY8AXa9N3pgqSqUoKAeYnWmY0cOWeNqeV4 +xsisaq2WBgLoo4FGqWzM9B6b3dFbXof4HHR5yimmgKd9B48JqWAOBP5+SccRqOLq +utV08rC8xEQ31IIHM1iIThqmVX1I5gwurcGiaE+wHqRc03zqKFIyIwi8lrfxF8If +JRpeuxT3gS57cBz5Y4FIzZYjEn6Suj9AemnvEPPZ474tnDD5KpKqjE5FNQARAQAB +tCFyb21haW4gKEhlbGxvKSA8bWVAcmdvbmNhbHZlcy5zZT6JAkwEEwEKADYWIQSM +fW2vFPgUJkDOg+r4XNAttBnWjAUCXnMw5wIbAQQLCQgHBBUKCQgFFgIDAQACHgEC +F4AACgkQ+FzQLbQZ1owjvA/9E7z9HoTQMOlBS5Tg1axYouwH4+XZ7QDr/H3/ccTY +8HBaLpF5KAGcaV7C+WzbZf5zPoP4avcNFlir7ncm+8MJUDXp8XGSlFRWuQ/MLsVU +or81jOHCl0CXSdS1iUe0tNt9Mge9QfB1W7+au3byOCXj3KK7yfOBCYNbubWwoZq4 +wyPOg1zhsi3dSbKgnclS+sDyyJdZv+dzG5ZLuBbiA5qWchVTdKfGIYdft5C/i9c5 +V3FkFlCEyeQ6gYCoN22IHvhoIBXmORbYzzQwzXWOf/0ViXRqrrbViQ1WgIP6blWP +pboko3ZaExCCVLCZ0W58wK1xQafK5uURmbh4NhL6guaOq285r9IOIRTb5tadkkR0 +qlDz36F4Pr1tSiQ+RvQoRMm11Zo84pr6wCmXn+jRLc4gS1JopeYhdFeE/TFFl/yM +J+S5T6KivUedWGB3jN52TC9F4acs3rVwcJHhxJtaE7zvWNnZh2ujEbbX41wk/g9/ +ZFJaC+2XLyw3Vgn78h7uzK1+3LrWi1e12qqeyITSviedDA3aFDhzbjlzI7wdjZhI +2XWHcGX1gxQEqx5XzOCaP76lj1E6tGsAB0140nggRhoqGbdYR2Ufh34AVkoSvQEA +j2A5aDWIc94neWfRyMHfuW2PFb2hFNtJSSajlxtEsg1/zKP8lRxw2IaHfeMpuNG1 +yyG5Ag0EXnMyQQEQAOJJ016xc91HLpJxd4WsK8BmCTLMmNZf4xfJOSaCCEC7Uh7r +7fybIsFWJUf/fMf1seBZ0IB2mznaKp6fE78gU1s/wKjQl6yYxt2dmXvoOpCTCb1B +Zqu2lN54h2+OvRyq/UPXxOCKVZfMqrc6C/eoyl4VorUfBJrhg9VVbciqIOnO11uJ +UMQZQsYr7uvdFFJYyePI4FyjCytUPnnH38IIHlyL8YYf8mo3TJJGkohuAw/a87GY +AIFpxk39obIuLbHpQAKSoQKlPCjEjGD/c9dSLmkl/16XnWyMuyIcv6Vw2ek2f0TL +Bj5Jo26YXwU7+JJL4N3RgEAW6XLEa5Ylirpskt6qjHjlyNfxtnefrVMOL4k/hANQ +MlBdnE+5oONUlXcuVgSsCGtuMsV2P8dI5Hw3Cr9YkFPzkpJhLLdwPcCLvZz5DM7C +xrv6+TJEPqtVN3V9ZupRUprS+8E61XfdTZX1CYNytYTHGpb7qJ2wsvPST/GvZbui +Aa6CrwJb7RkCkoaD0kf5iIDpCmtMZtESivqrbC7J1KONCXL/uK6G5aW/Vr8Gqnvl +B5vZLb7GxJpYISkmGtegHAGOCd3ecGUJf8S3DLHyghskt2JKsUszaWqHmTsYYLQ4 +QB0ihz3ikoRMs9nd3k+CZwI8BMNKQE0l0rQCxlXhjCGwoibxNFA+vFq4kXcHABEB +AAGJBGwEGAEKACAWIQSMfW2vFPgUJkDOg+r4XNAttBnWjAUCXnMyQQIbAgJACRD4 +XNAttBnWjMF0IAQZAQoAHRYhBNb92WprxEfuG/J00SQUnphu2qDFBQJeczJBAAoJ +ECQUnphu2qDFARAQAK0Qs5KGWE1Ark8d0efTr8zQExebx8QJjsIXhdDxy/xJSt1l +dMqabIV6gO0HQPYoxexHecpJPFZOiAm35Oh+6N2yPRfgoktNllw1Q066BTOqJ9/D +XFrqCMV0nhuQSl7LSTQpc7qGxH7c92p8a1/wu5LbT3zELRUQm14WGyFX8X055+tm +wd3YexWTI8ueIFjj4h7hMGZ0sgPffON+GBrqmY0doT1ZIu+2tgLFuU0OlcoAO8g5 +9wS2BDcBa/4Kyq5rnYE7ONnhVZgfxmoWQg4rugVZ6sXs88ew4lD6Gtxh6SizIrgS +wfR2GbbbpIE7dcZOeFpPyogAKiBANWiUOYCRwe3ABL7lgMt6CETnF8r2sG1oYgng +E5NebaBlXRkgMmoSYp1Lnhc2uQ6gVUYJh902c/ueGUPDaOEX4s48iyVk/nu7Bbco +x432QPsZu/7Q5VtUvetnkbNu/aj+JM+snWkE/KfN704xIMk0V5IlwVty5uUDT0Na +/8BphfJd8RcWOz4uPxsTixgoyovAHUqJ3t1Zy+M0Ow2iLKmw5W/f3sFtlU9n8T2F +79RmrzYK2dTgXjxZZV/8jBXpqEXJQRmybmeOFKlOIRnBBmvFIWjCdFrbH8U+NB2o +7Nrazoc0JRYi5ewaxE+3RQk2XwLHUvxbBqqqnPzfOkNKHonM7p4kxeB0/btyWzUP +/2hM8Rn4tWljUOosMvlm2UCoUj8EJCENMXDFTUnzJob038/QfNNrXYDxwr3V4Fb1 +1TC1eh/2B1hgftNCzo0N8yXTCzyJkBLIp52G4bTHMuQcjpZeLWpf31IqLbCmeQ0P +t1XuIXgO1DWmDAkd053OdydU5Nq7KyYtfuYIcctu/2zd5t+N236Xf5MO+8VrnMzy +82pNgAMR07xqq/xfJeR/IJzDRPHOIrBO3FaJP0PkdmTt9NmMgMo7otI3h8LaWnON +3IAWvXLWXq3F2r2mZNJ9/2kSzBu2f2iwwgqFZ7mNt4/ez+8joHlpXyVAH2nh4jKO +Hf3RTW8ixLm+n6hFE6a8rbpO/2TPE5+ORIb8M3ZRfchXy62QZ8Gt4UJ7w1plpkZP +9dwiXyOKz1NMfXH8JywnAE+nmibVsm7hdQ4OCob5nQ9jgmmDWihH1T0at4ajSpY+ +B25mzzGID4sCloh2g7vEnM15VaDWwQ6LOuLhk1868qrvLvhaua4a0NvmdcUbclM8 +Mo1r135urbWOGyDkAZbWaqT3/unbEIezZyN9NiTXEZvHwtKeYX82xfJC/cS0ctRh +pAf4DJlIho1aei1RRZwmkIrPbLnRDgvmefTYWmVqTU9F+ITdy1JfaVBpE21JVVsQ +++aZhTLUXcohH4rSAyk9Tl1m0XSL5TFDrxMkEFAM1IPNuQINBF5zMm4BEADTaaZq ++SmImeGBOoUSjO7uu+M/RgqTE52ic7IhanWLOIakMAIAaLY/xeSS1dX8V8tQW+f3 +I5/XFpihaSbBVdN+jm7oQwnYrx6YoxQYIALF63pyg578enG/GK6lqeJRJvJ+5P6F +uIgI6pHkT/1mY1LYC+s30HlSMhka+dTtFhgMWx3EQjGQHoOuCxw9NV7IhNGVDn09 +7/43pKFtx5VVZ6zDRAzPcvUj3YEk4yfBG1xVsNKVeByz7cS6J6n6S9yVHfPvnlod +IjCSDFzyF6clp9Z4hhZAM2eD4Rv3CWl6CqFU30ShmjuNwR9Eso0GrZV8dqD060in +LPPlmyZ3v2PgkHxSJRerVt5T+yhC+oVntvhCs9rG3JpUqmFoxvTkHNohuEnSwGDg +mrfiSmsVCKUwALamDthEfA10fEZXR49l4ASOtVHiwLiZvQYtngljBIr83i7rYKOx +r4OKZ1DMmBRWQOeEV2nN7QDLNSazIPnGebLdwBdMUyw0fnrAj5ljm8iIO/azEsTG +qnhbOzLgNXAj2OT1Gc9XnOXGFeQcT4R5XKLu5N1Kvlpm4gmajMK2m8Nq3ERfhhal +J9utYm6O8HaVdvWOr1BqRe4leME82XrIs0DAQa3NWnY1sw0CRTdpbpdSdcVzkKgx +4QMU0UOvLnc3G6EwXfBWtukAKObz70PWGq+t4wARAQABiQI2BBgBCgAgFiEEjH1t +rxT4FCZAzoPq+FzQLbQZ1owFAl5zMm4CGwwACgkQ+FzQLbQZ1ozrRg//c2Sy6ZMw +LEpOFv2th39dXNeMvnX1ntGIh0Fm99RSE5vDRK+Frzanx6RNz0OLv084MVe9byPY +O4QTTTIBgVE2AQzc8Hf1uHh+1cVNMIodei09FLr3237tp4ju3ZbSOPLwH0lZS0bu +asLrOeAMjFPwRl5oHzfQvWqzB/TofvDDCKAs4A8VXO5I3sOK63c65dWsHKC6B9UQ +U/9YXHXVNa4kLFqk0xIuWB2UtX4ZghiQcyXXNRMKH5b3YoNbe4eKSsNeNbhn3EJd +TAFHuyCfGQ29os92pWjFfer7qZrfKYYDK8UXYPPJTGR0NDnXm6U32CZgW6/Cs91z +W1NZLdsauGcSoLqVKtx+aglkqmQmLxcXWToLIeOA+5KZy40sf0jEK1/sl/W7TTl2 +/BvIGwcVCWUlva/8hwmK12Vqdkkg1e4VvuMODSpnuMcWkY+YuVpX/aUboHPjmmQy +9x0lMVpMyVMLM9NM3S5Zlj7n1WoMAQJSM4h7xAQP5yCFqE5ZX4R0dx6a9muZG8K5 +wAqRHAbhsgV8QncLdckc+ELDo4mLJMQAMMEl4WLH7vW3iGDhB0zwoDpQoDZxBM87 +dbqaKgfNUBziSQ0OH+mfZ+Rup15c0PMjJQVuJhj0di2dNpnXWeSt2W1/mDTQX2Q9 +ufFZ4BGp5KYAzX4V2fS5JVG/U00winAhaTW5Ag0EXnMyowEQALu3xBuds7ntcpxa +gtONCWt/f6/t7z2H5UQBzG/+IdXQ8Pr40ID2UTz5MQlwFAMQWMKrOj0KQFrRYhQv +eqTeJswasdVUfq0bdZ+fW8qmUFnMJtWjgvql3yj53cfIsrDYgOwgqBVdWCVsfrVv +gM96tEq3PFhYG5hnvkVWnFZ5QqWMGBeHLNej54+o4LdEgszH/rg9YmHJT50nQLx8 +HsBUk74/ekeMl6VbgmQIDHa0YNu5o+Mi3KcLI0cXnaw1PKYviCcKHuD6wUxD6oQB +JYbJLHThYGlEkTRe5CGUc/HkJ3eq8DJ+7sN4r5Z8IpJt+YhLF/dwoYiWqFZ79pYv +woEmptUS+ri8JrLsMb+cX8MlNhWyInbqoE0JwREkHvGMREr/BoPTTO5NXLTcFSia +FjCBMpVvPspxjW8zUof/lA5pJVVh+4N15V1f0hcAhmqbP/OpEyY5CHjqFcVka3Cu +ARAVR9enENBU3aTrzgBSgLTkwiG2wuPMPKMj9ghPEQMKV/1KR96NVNpGV2X5otHp +n2z7Zo2Tdpq7lWHLARIPf2iynANs48VlnIyj9ZI9wyfQ0/5FUYxaVbw5ptSRerYh +JKHnkM0mybAwATzgswkMiTvkgh9mYuC427VXJiWtIC3Qvt0DSBREKE6hdm6UVNJp +1kbcNYD8MRdwPPju5l/Qbja0w485ABEBAAGJAjYEGAEKACAWIQSMfW2vFPgUJkDO +g+r4XNAttBnWjAUCXnMyowIbIAAKCRD4XNAttBnWjFtvEACgOyjGPtqfTH+lgttP +2+fxdrBy7+RcHZvHYzfc48Td/KBP7Vdx38OHyou3PEFAkDVTIrJTs8bIW7C0jCSx +Jvp2iroBYvyw7reMKJswqLsG0ne2wj0106gJ9Bo/L3fBVlhHM32tm5/cAv0I8M0d +A2QvqyQeV54rhqD2Y+X35beaOCUYzORuVWzFMfmK3nlWBJJ6LRL1120+XPTDsvuO +sIfd1YK33Ag2c77W5ybbVddBSw3E7v0SLuAHIv11qypUlkUjADkt3WNUNpEAO1jE +DiTNxXk9qPLsr7k5D1rMJbKiXaR+Y7z73ykHmlhxJaL0JQJ0AF9CK1GuFAF7siYQ +CwfYOoIggmGN6sjJyCT4XChjX1pByYNoBeAEF1RL4q0fgVJlFZFZRa/1G7JJxmgU +tNd+nGxynftzYpdGtHfKcOpWP3kqaQqbMjfFQZpmeglNxVjDeNXQxevhcPCtoeEB +FeodQ5W0Rpl3jucdMP3ld/T+Gxivx2Tl3ECvaw3EnFuCaepTcCcl5jKmTjywelo8 +UOjRJlSJ/mA1OwNJLz9vulCOHK5Now37FdeDW5K6KoVDi13RAO49zVPobEbmGaiF +ZaSBZW7ax7Y0/VfAdR1sjWC3fnJOstlUNeb35FoQHsi4166LI4+U+pGcv5orV2iE +jMkprlyrNuAcrXbn0AsZnS79DA== +=2hJ5 +-----END PGP PUBLIC KEY BLOCK----- diff --git a/.weechat/buflist.conf b/.weechat/buflist.conf new file mode 100755 index 0000000..99bd851 --- /dev/null +++ b/.weechat/buflist.conf @@ -0,0 +1,41 @@ +# +# weechat -- buflist.conf +# +# WARNING: It is NOT recommended to edit this file by hand, +# especially if WeeChat is running. +# +# Use commands like /set or /fset to change settings in WeeChat. +# +# For more info, see: https://weechat.org/doc/quickstart +# + +[look] +add_newline = on +auto_scroll = 50 +display_conditions = "${buffer.hidden}==0" +enabled = on +mouse_jump_visited_buffer = off +mouse_move_buffer = on +mouse_wheel = on +nick_prefix = off +nick_prefix_empty = on +signals_refresh = "" +sort = "number,-active" +use_items = 1 + +[format] +buffer = "${format_number}${indent}${format_nick_prefix}${color_hotlist}${name}${buffer.nick}" +buffer_current = "${color:,blue}${format_buffer}" +hotlist = " ${color:green}(${hotlist}${color:green})" +hotlist_highlight = "${color:magenta}" +hotlist_low = "${color:white}" +hotlist_message = "${color:brown}" +hotlist_none = "${color:default}" +hotlist_private = "${color:green}" +hotlist_separator = "${color:default}," +indent = " " +lag = " ${color:green}[${color:brown}${lag}${color:green}]" +name = "${name}" +nick_prefix = "${color_nick_prefix}${nick_prefix}" +number = "${color:green}${number}${if:${number_displayed}?.: }" +tls_version = " ${color:default}(${if:${tls_version}==TLS1.3?${color:green}:${if:${tls_version}==TLS1.2?${color:yellow}:${color:red}}}${translate:${tls_version}}${color:default})" diff --git a/.weechat/fset.conf b/.weechat/fset.conf new file mode 100755 index 0000000..3d7a814 --- /dev/null +++ b/.weechat/fset.conf @@ -0,0 +1,96 @@ +# +# weechat -- fset.conf +# +# WARNING: It is NOT recommended to edit this file by hand, +# especially if WeeChat is running. +# +# Use commands like /set or /fset to change settings in WeeChat. +# +# For more info, see: https://weechat.org/doc/quickstart +# + +[look] +auto_refresh = "*" +auto_unmark = off +condition_catch_set = "${count} >= 1" +export_help_default = on +format_number = 1 +marked_string = "*" +scroll_horizontal = 10 +show_plugins_desc = off +sort = "~name" +unmarked_string = " " +use_color_value = off +use_keys = on +use_mute = off + +[format] +export_help = "# ${description2}" +export_option = "/set ${name} ${quoted_value}" +export_option_null = "/unset ${name}" +option1 = "" +option2 = "${marked} ${name} ${type} ${value2}${newline} ${empty_name} ${_default_value}${color:darkgray} -- ${min}..${max}${newline} ${empty_name} ${description}" + +[color] +default_value = default +default_value_selected = white +description = default +description_selected = white +file = default +file_changed = brown +file_changed_selected = yellow +file_selected = white +help_default_value = white +help_description = default +help_name = white +help_quotes = darkgray +help_values = default +index = cyan +index_selected = lightcyan +line_marked_bg1 = default +line_marked_bg2 = default +line_selected_bg1 = blue +line_selected_bg2 = red +marked = brown +marked_selected = yellow +max = default +max_selected = white +min = default +min_selected = white +name = default +name_changed = brown +name_changed_selected = yellow +name_selected = white +option = default +option_changed = brown +option_changed_selected = yellow +option_selected = white +parent_name = default +parent_name_selected = white +parent_value = cyan +parent_value_selected = lightcyan +quotes = darkgray +quotes_changed = default +quotes_changed_selected = white +quotes_selected = default +section = default +section_changed = brown +section_changed_selected = yellow +section_selected = white +string_values = default +string_values_selected = white +title_count_options = cyan +title_current_option = lightcyan +title_filter = yellow +title_marked_options = lightgreen +title_sort = white +type = green +type_selected = lightgreen +unmarked = default +unmarked_selected = white +value = cyan +value_changed = brown +value_changed_selected = yellow +value_selected = lightcyan +value_undef = magenta +value_undef_selected = lightmagenta diff --git a/.weechat/logger.conf b/.weechat/logger.conf new file mode 100755 index 0000000..37c02b4 --- /dev/null +++ b/.weechat/logger.conf @@ -0,0 +1,36 @@ +# +# weechat -- logger.conf +# +# WARNING: It is NOT recommended to edit this file by hand, +# especially if WeeChat is running. +# +# Use commands like /set or /fset to change settings in WeeChat. +# +# For more info, see: https://weechat.org/doc/quickstart +# + +[look] +backlog = 0 +backlog_conditions = "" + +[color] +backlog_end = default +backlog_line = default + +[file] +auto_log = off +color_lines = off +flush_delay = 120 +fsync = off +info_lines = off +mask = "$plugin.$name.weechatlog" +name_lower_case = on +nick_prefix = "" +nick_suffix = "" +path = "${weechat_data_dir}/logs" +replacement_char = "_" +time_format = "%Y-%m-%d %H:%M:%S" + +[level] + +[mask] diff --git a/.weechat/weechat.conf b/.weechat/weechat.conf new file mode 100755 index 0000000..53e2776 --- /dev/null +++ b/.weechat/weechat.conf @@ -0,0 +1,704 @@ +# +# weechat -- weechat.conf +# +# WARNING: It is NOT recommended to edit this file by hand, +# especially if WeeChat is running. +# +# Use commands like /set or /fset to change settings in WeeChat. +# +# For more info, see: https://weechat.org/doc/quickstart +# + +[debug] + +[startup] +command_after_plugins = "" +command_before_plugins = "" +display_logo = on +display_version = on +sys_rlimit = "" + +[look] +align_end_of_lines = message +align_multiline_words = on +bar_more_down = "++" +bar_more_left = "<<" +bar_more_right = ">>" +bar_more_up = "--" +bare_display_exit_on_input = on +bare_display_time_format = "%H:%M" +buffer_auto_renumber = on +buffer_notify_default = all +buffer_position = end +buffer_search_case_sensitive = off +buffer_search_force_default = off +buffer_search_regex = off +buffer_search_where = prefix_message +buffer_time_format = "%H:%M:%S" +buffer_time_same = "" +color_basic_force_bold = off +color_inactive_buffer = on +color_inactive_message = on +color_inactive_prefix = on +color_inactive_prefix_buffer = on +color_inactive_time = off +color_inactive_window = on +color_nick_offline = off +color_pairs_auto_reset = 5 +color_real_white = off +command_chars = "" +command_incomplete = off +confirm_quit = off +confirm_upgrade = off +day_change = on +day_change_message_1date = "-- %a, %d %b %Y --" +day_change_message_2dates = "-- %%a, %%d %%b %%Y (%a, %d %b %Y) --" +eat_newline_glitch = off +emphasized_attributes = "" +highlight = "" +highlight_regex = "" +highlight_tags = "" +hotlist_add_conditions = "${away} || ${buffer.num_displayed} == 0 || ${info:relay_client_count,weechat,connected} > 0" +hotlist_buffer_separator = ", " +hotlist_count_max = 2 +hotlist_count_min_msg = 2 +hotlist_names_count = 3 +hotlist_names_length = 0 +hotlist_names_level = 12 +hotlist_names_merged_buffers = off +hotlist_prefix = "H: " +hotlist_remove = merged +hotlist_short_names = on +hotlist_sort = group_time_asc +hotlist_suffix = "" +hotlist_unique_numbers = on +hotlist_update_on_buffer_switch = on +input_cursor_scroll = 20 +input_share = none +input_share_overwrite = off +input_undo_max = 32 +item_away_message = on +item_buffer_filter = "*" +item_buffer_zoom = "!" +item_mouse_status = "M" +item_time_format = "%H:%M" +jump_current_to_previous_buffer = on +jump_previous_buffer_when_closing = on +jump_smart_back_to_buffer = on +key_bind_safe = on +key_grab_delay = 800 +mouse = off +mouse_timer_delay = 100 +nick_color_force = "" +nick_color_hash = djb2 +nick_color_hash_salt = "" +nick_color_stop_chars = "_|[" +nick_prefix = "" +nick_suffix = "" +paste_auto_add_newline = on +paste_bracketed = on +paste_bracketed_timer_delay = 10 +paste_max_lines = 1 +prefix_action = " *" +prefix_align = right +prefix_align_max = 0 +prefix_align_min = 0 +prefix_align_more = "+" +prefix_align_more_after = on +prefix_buffer_align = right +prefix_buffer_align_max = 0 +prefix_buffer_align_more = "+" +prefix_buffer_align_more_after = on +prefix_error = "=!=" +prefix_join = "-->" +prefix_network = "--" +prefix_quit = "<--" +prefix_same_nick = "" +prefix_same_nick_middle = "" +prefix_suffix = "|" +quote_nick_prefix = "<" +quote_nick_suffix = ">" +quote_time_format = "%H:%M:%S" +read_marker = line +read_marker_always_show = off +read_marker_string = "- " +read_marker_update_on_buffer_switch = on +save_config_on_exit = on +save_config_with_fsync = off +save_layout_on_exit = none +scroll_amount = 3 +scroll_bottom_after_switch = off +scroll_page_percent = 100 +search_text_not_found_alert = on +separator_horizontal = "-" +separator_vertical = "" +tab_width = 1 +time_format = "%a, %d %b %Y %T" +window_auto_zoom = off +window_separator_horizontal = on +window_separator_vertical = on +window_title = "" +word_chars_highlight = "!\u00A0,-,_,|,alnum" +word_chars_input = "!\u00A0,-,_,|,alnum" + +[palette] + +[color] +bar_more = lightmagenta +chat = default +chat_bg = default +chat_buffer = white +chat_channel = white +chat_day_change = cyan +chat_delimiters = green +chat_highlight = yellow +chat_highlight_bg = magenta +chat_host = cyan +chat_inactive_buffer = default +chat_inactive_window = default +chat_nick = lightcyan +chat_nick_colors = "cyan,magenta,green,brown,lightblue,default,lightcyan,lightmagenta,lightgreen,blue" +chat_nick_offline = default +chat_nick_offline_highlight = default +chat_nick_offline_highlight_bg = blue +chat_nick_other = cyan +chat_nick_prefix = green +chat_nick_self = white +chat_nick_suffix = green +chat_prefix_action = white +chat_prefix_buffer = brown +chat_prefix_buffer_inactive_buffer = default +chat_prefix_error = yellow +chat_prefix_join = lightgreen +chat_prefix_more = lightmagenta +chat_prefix_network = magenta +chat_prefix_quit = lightred +chat_prefix_suffix = green +chat_read_marker = magenta +chat_read_marker_bg = default +chat_server = brown +chat_tags = red +chat_text_found = yellow +chat_text_found_bg = lightmagenta +chat_time = default +chat_time_delimiters = brown +chat_value = cyan +chat_value_null = blue +emphasized = yellow +emphasized_bg = magenta +input_actions = lightgreen +input_text_not_found = red +item_away = yellow +nicklist_away = cyan +nicklist_group = green +separator = blue +status_count_highlight = magenta +status_count_msg = brown +status_count_other = default +status_count_private = green +status_data_highlight = lightmagenta +status_data_msg = yellow +status_data_other = default +status_data_private = lightgreen +status_filter = green +status_more = yellow +status_mouse = green +status_name = white +status_name_ssl = lightgreen +status_nicklist_count = default +status_number = yellow +status_time = default + +[completion] +base_word_until_cursor = on +command_inline = on +default_template = "%(nicks)|%(irc_channels)" +nick_add_space = on +nick_case_sensitive = off +nick_completer = ": " +nick_first_only = off +nick_ignore_chars = "[]`_-^" +partial_completion_alert = on +partial_completion_command = off +partial_completion_command_arg = off +partial_completion_count = on +partial_completion_other = off +partial_completion_templates = "config_options" + +[history] +display_default = 5 +max_buffer_lines_minutes = 0 +max_buffer_lines_number = 4096 +max_commands = 100 +max_visited_buffers = 50 + +[proxy] + +[network] +connection_timeout = 60 +gnutls_ca_system = on +gnutls_ca_user = "" +gnutls_handshake_timeout = 30 +proxy_curl = "" + +[plugin] +autoload = "*" +debug = off +extension = ".so,.dll" +path = "%h/plugins" +save_config_on_unload = on + +[signal] +sighup = "${if:${info:weechat_headless}?/reload:/quit -yes}" +sigquit = "/quit -yes" +sigterm = "/quit -yes" +sigusr1 = "" +sigusr2 = "" + +[bar] +buflist.color_bg = default +buflist.color_bg_inactive = default +buflist.color_delim = default +buflist.color_fg = default +buflist.conditions = "" +buflist.filling_left_right = vertical +buflist.filling_top_bottom = columns_vertical +buflist.hidden = off +buflist.items = "buflist" +buflist.position = left +buflist.priority = 0 +buflist.separator = on +buflist.size = 0 +buflist.size_max = 0 +buflist.type = root +fset.color_bg = default +fset.color_bg_inactive = default +fset.color_delim = cyan +fset.color_fg = default +fset.conditions = "${buffer.full_name} == fset.fset" +fset.filling_left_right = vertical +fset.filling_top_bottom = horizontal +fset.hidden = off +fset.items = "fset" +fset.position = top +fset.priority = 0 +fset.separator = on +fset.size = 3 +fset.size_max = 3 +fset.type = window +input.color_bg = default +input.color_bg_inactive = default +input.color_delim = cyan +input.color_fg = default +input.conditions = "" +input.filling_left_right = vertical +input.filling_top_bottom = horizontal +input.hidden = off +input.items = "[mode_indicator+][input_prompt]+(away),[input_search],[input_paste],input_text,[vi_buffer]" +input.position = bottom +input.priority = 1000 +input.separator = off +input.size = 0 +input.size_max = 0 +input.type = window +nicklist.color_bg = default +nicklist.color_bg_inactive = default +nicklist.color_delim = cyan +nicklist.color_fg = default +nicklist.conditions = "${nicklist}" +nicklist.filling_left_right = vertical +nicklist.filling_top_bottom = columns_vertical +nicklist.hidden = off +nicklist.items = "buffer_nicklist" +nicklist.position = right +nicklist.priority = 200 +nicklist.separator = on +nicklist.size = 0 +nicklist.size_max = 0 +nicklist.type = window +status.color_bg = blue +status.color_bg_inactive = darkgray +status.color_delim = cyan +status.color_fg = default +status.conditions = "" +status.filling_left_right = vertical +status.filling_top_bottom = horizontal +status.hidden = off +status.items = "[time],[buffer_last_number],[buffer_plugin],buffer_number+:+buffer_name+(buffer_modes)+{buffer_nicklist_count}+buffer_zoom+buffer_filter,scroll,[lag],[hotlist],[matrix_typing_notice],completion" +status.position = bottom +status.priority = 500 +status.separator = off +status.size = 1 +status.size_max = 0 +status.type = window +title.color_bg = blue +title.color_bg_inactive = darkgray +title.color_delim = cyan +title.color_fg = default +title.conditions = "" +title.filling_left_right = vertical +title.filling_top_bottom = horizontal +title.hidden = off +title.items = "buffer_title" +title.position = top +title.priority = 500 +title.separator = off +title.size = 1 +title.size_max = 0 +title.type = window +vi_line_numbers.color_bg = default +vi_line_numbers.color_bg_inactive = default +vi_line_numbers.color_delim = default +vi_line_numbers.color_fg = default +vi_line_numbers.conditions = "" +vi_line_numbers.filling_left_right = vertical +vi_line_numbers.filling_top_bottom = vertical +vi_line_numbers.hidden = on +vi_line_numbers.items = "line_numbers" +vi_line_numbers.position = left +vi_line_numbers.priority = 0 +vi_line_numbers.separator = off +vi_line_numbers.size = 0 +vi_line_numbers.size_max = 0 +vi_line_numbers.type = window + +[layout] + +[notify] + +[filter] +topic = on;*;irc_topic;* +irc_smart = on;*,!irc.undernet.*;irc_smart_filter;* +joinquit = on;*;irc_join,irc_part,irc_quit;* +irc_join_topic_date_names_creation = on;*;irc_332,irc_333,irc_366,irc_329,irc_372;* +backlog_in = on;*;<--;* +backlogtidy = on;*;logger_backlog;^\S+ \(\S+\) has (joined|left|quit) |^\S+ is now known as \S+$ + +[key] +ctrl-? = "/input delete_previous_char" +ctrl-A = "/input move_beginning_of_line" +ctrl-B = "/input move_previous_char" +ctrl-C_ = "/input insert \x1F" +ctrl-Cb = "/input insert \x02" +ctrl-Cc = "/input insert \x03" +ctrl-Ci = "/input insert \x1D" +ctrl-Co = "/input insert \x0F" +ctrl-Cv = "/input insert \x16" +ctrl-D = "/input delete_next_char" +ctrl-E = "/input move_end_of_line" +ctrl-F = "/input move_next_char" +ctrl-H = "/input delete_previous_char" +ctrl-I = "/input complete_next" +ctrl-J = "/input return" +ctrl-K = "/input delete_end_of_line" +ctrl-L = "/window refresh" +ctrl-M = "/input return" +ctrl-N = "/buffer +1" +ctrl-P = "/buffer -1" +ctrl-R = "/input search_text_here" +ctrl-Sctrl-U = "/input set_unread" +ctrl-T = "/input transpose_chars" +ctrl-U = "/input delete_beginning_of_line" +ctrl-W = "/input delete_previous_word" +ctrl-W= = "/window balance" +ctrl-Wh = "/window left" +ctrl-Wj = "/window down" +ctrl-Wk = "/window up" +ctrl-Wl = "/window right" +ctrl-Wq = "/window merge" +ctrl-Ws = "/window splith" +ctrl-Wv = "/window splitv" +ctrl-Wx = "/window swap" +ctrl-X = "/input switch_active_buffer" +ctrl-Y = "/input clipboard_paste" +meta-ctrl-M = "/input insert \n" +meta-meta-OP = "/bar scroll buflist * b" +meta-meta-OQ = "/bar scroll buflist * e" +meta-meta2-11~ = "/bar scroll buflist * b" +meta-meta2-12~ = "/bar scroll buflist * e" +meta-meta2-1~ = "/window scroll_top" +meta-meta2-23~ = "/bar scroll nicklist * b" +meta-meta2-24~ = "/bar scroll nicklist * e" +meta-meta2-4~ = "/window scroll_bottom" +meta-meta2-5~ = "/window scroll_up" +meta-meta2-6~ = "/window scroll_down" +meta-meta2-7~ = "/window scroll_top" +meta-meta2-8~ = "/window scroll_bottom" +meta-meta2-A = "/buffer -1" +meta-meta2-B = "/buffer +1" +meta-meta2-C = "/buffer +1" +meta-meta2-D = "/buffer -1" +meta-- = "/filter toggle @" +meta-/ = "/input jump_last_buffer_displayed" +meta-0 = "/buffer *10" +meta-1 = "/buffer *1" +meta-2 = "/buffer *2" +meta-3 = "/buffer *3" +meta-4 = "/buffer *4" +meta-5 = "/buffer *5" +meta-6 = "/buffer *6" +meta-7 = "/buffer *7" +meta-8 = "/buffer *8" +meta-9 = "/buffer *9" +meta-< = "/input jump_previously_visited_buffer" +meta-= = "/filter toggle" +meta-> = "/input jump_next_visited_buffer" +meta-B = "/buflist toggle" +meta-N = "/bar toggle nicklist" +meta-OA = "/input history_global_previous" +meta-OB = "/input history_global_next" +meta-OC = "/input move_next_word" +meta-OD = "/input move_previous_word" +meta-OF = "/input move_end_of_line" +meta-OH = "/input move_beginning_of_line" +meta-OP = "/bar scroll buflist * -100%" +meta-OQ = "/bar scroll buflist * +100%" +meta-Oa = "/input history_global_previous" +meta-Ob = "/input history_global_next" +meta-Oc = "/input move_next_word" +meta-Od = "/input move_previous_word" +meta2-11^ = "/bar scroll buflist * -100%" +meta2-11~ = "/bar scroll buflist * -100%" +meta2-12^ = "/bar scroll buflist * +100%" +meta2-12~ = "/bar scroll buflist * +100%" +meta2-15~ = "/buffer -1" +meta2-17~ = "/buffer +1" +meta2-18~ = "/window -1" +meta2-19~ = "/window +1" +meta2-1;3A = "/buffer -1" +meta2-1;3B = "/buffer +1" +meta2-1;3C = "/buffer +1" +meta2-1;3D = "/buffer -1" +meta2-1;3F = "/window scroll_bottom" +meta2-1;3H = "/window scroll_top" +meta2-1;3P = "/bar scroll buflist * b" +meta2-1;3Q = "/bar scroll buflist * e" +meta2-1;5A = "/input history_global_previous" +meta2-1;5B = "/input history_global_next" +meta2-1;5C = "/input move_next_word" +meta2-1;5D = "/input move_previous_word" +meta2-1;5P = "/bar scroll buflist * -100%" +meta2-1;5Q = "/bar scroll buflist * +100%" +meta2-1~ = "/input move_beginning_of_line" +meta2-200~ = "/input paste_start" +meta2-201~ = "/input paste_stop" +meta2-20~ = "/bar scroll title * -30%" +meta2-21~ = "/bar scroll title * +30%" +meta2-23;3~ = "/bar scroll nicklist * b" +meta2-23;5~ = "/bar scroll nicklist * -100%" +meta2-23^ = "/bar scroll nicklist * -100%" +meta2-23~ = "/bar scroll nicklist * -100%" +meta2-24;3~ = "/bar scroll nicklist * e" +meta2-24;5~ = "/bar scroll nicklist * +100%" +meta2-24^ = "/bar scroll nicklist * +100%" +meta2-24~ = "/bar scroll nicklist * +100%" +meta2-3~ = "/input delete_next_char" +meta2-4~ = "/input move_end_of_line" +meta2-5;3~ = "/window scroll_up" +meta2-5~ = "/window page_up" +meta2-6;3~ = "/window scroll_down" +meta2-6~ = "/window page_down" +meta2-7~ = "/input move_beginning_of_line" +meta2-8~ = "/input move_end_of_line" +meta2-A = "/input history_previous" +meta2-B = "/input history_next" +meta2-C = "/input move_next_char" +meta2-D = "/input move_previous_char" +meta2-F = "/input move_end_of_line" +meta2-G = "/window page_down" +meta2-H = "/input move_beginning_of_line" +meta2-I = "/window page_up" +meta2-Z = "/input complete_previous" +meta2-[E = "/buffer -1" +meta-_ = "/input redo" +meta-a = "/input jump_smart" +meta-b = "/input move_previous_word" +meta-d = "/input delete_next_word" +meta-f = "/input move_next_word" +meta-h = "/input hotlist_clear" +meta-j01 = "/buffer *1" +meta-j02 = "/buffer *2" +meta-j03 = "/buffer *3" +meta-j04 = "/buffer *4" +meta-j05 = "/buffer *5" +meta-j06 = "/buffer *6" +meta-j07 = "/buffer *7" +meta-j08 = "/buffer *8" +meta-j09 = "/buffer *9" +meta-j10 = "/buffer *10" +meta-j11 = "/buffer *11" +meta-j12 = "/buffer *12" +meta-j13 = "/buffer *13" +meta-j14 = "/buffer *14" +meta-j15 = "/buffer *15" +meta-j16 = "/buffer *16" +meta-j17 = "/buffer *17" +meta-j18 = "/buffer *18" +meta-j19 = "/buffer *19" +meta-j20 = "/buffer *20" +meta-j21 = "/buffer *21" +meta-j22 = "/buffer *22" +meta-j23 = "/buffer *23" +meta-j24 = "/buffer *24" +meta-j25 = "/buffer *25" +meta-j26 = "/buffer *26" +meta-j27 = "/buffer *27" +meta-j28 = "/buffer *28" +meta-j29 = "/buffer *29" +meta-j30 = "/buffer *30" +meta-j31 = "/buffer *31" +meta-j32 = "/buffer *32" +meta-j33 = "/buffer *33" +meta-j34 = "/buffer *34" +meta-j35 = "/buffer *35" +meta-j36 = "/buffer *36" +meta-j37 = "/buffer *37" +meta-j38 = "/buffer *38" +meta-j39 = "/buffer *39" +meta-j40 = "/buffer *40" +meta-j41 = "/buffer *41" +meta-j42 = "/buffer *42" +meta-j43 = "/buffer *43" +meta-j44 = "/buffer *44" +meta-j45 = "/buffer *45" +meta-j46 = "/buffer *46" +meta-j47 = "/buffer *47" +meta-j48 = "/buffer *48" +meta-j49 = "/buffer *49" +meta-j50 = "/buffer *50" +meta-j51 = "/buffer *51" +meta-j52 = "/buffer *52" +meta-j53 = "/buffer *53" +meta-j54 = "/buffer *54" +meta-j55 = "/buffer *55" +meta-j56 = "/buffer *56" +meta-j57 = "/buffer *57" +meta-j58 = "/buffer *58" +meta-j59 = "/buffer *59" +meta-j60 = "/buffer *60" +meta-j61 = "/buffer *61" +meta-j62 = "/buffer *62" +meta-j63 = "/buffer *63" +meta-j64 = "/buffer *64" +meta-j65 = "/buffer *65" +meta-j66 = "/buffer *66" +meta-j67 = "/buffer *67" +meta-j68 = "/buffer *68" +meta-j69 = "/buffer *69" +meta-j70 = "/buffer *70" +meta-j71 = "/buffer *71" +meta-j72 = "/buffer *72" +meta-j73 = "/buffer *73" +meta-j74 = "/buffer *74" +meta-j75 = "/buffer *75" +meta-j76 = "/buffer *76" +meta-j77 = "/buffer *77" +meta-j78 = "/buffer *78" +meta-j79 = "/buffer *79" +meta-j80 = "/buffer *80" +meta-j81 = "/buffer *81" +meta-j82 = "/buffer *82" +meta-j83 = "/buffer *83" +meta-j84 = "/buffer *84" +meta-j85 = "/buffer *85" +meta-j86 = "/buffer *86" +meta-j87 = "/buffer *87" +meta-j88 = "/buffer *88" +meta-j89 = "/buffer *89" +meta-j90 = "/buffer *90" +meta-j91 = "/buffer *91" +meta-j92 = "/buffer *92" +meta-j93 = "/buffer *93" +meta-j94 = "/buffer *94" +meta-j95 = "/buffer *95" +meta-j96 = "/buffer *96" +meta-j97 = "/buffer *97" +meta-j98 = "/buffer *98" +meta-j99 = "/buffer *99" +meta-k = "/input grab_key_command" +meta-l = "/window bare" +meta-m = "/mute mouse toggle" +meta-n = "/window scroll_next_highlight" +meta-p = "/window scroll_previous_highlight" +meta-r = "/input delete_line" +meta-s = "/mute spell toggle" +meta-u = "/window scroll_unread" +meta-x = "/input zoom_merged_buffer" +meta-z = "/window zoom" +ctrl-^ = "/input jump_last_buffer_displayed" +ctrl-_ = "/input undo" + +[key_search] +ctrl-I = "/input search_switch_where" +ctrl-J = "/input search_stop_here" +ctrl-M = "/input search_stop_here" +ctrl-Q = "/input search_stop" +ctrl-R = "/input search_switch_regex" +meta2-A = "/input search_previous" +meta2-B = "/input search_next" +meta-c = "/input search_switch_case" + +[key_cursor] +ctrl-J = "/cursor stop" +ctrl-M = "/cursor stop" +meta-meta2-A = "/cursor move area_up" +meta-meta2-B = "/cursor move area_down" +meta-meta2-C = "/cursor move area_right" +meta-meta2-D = "/cursor move area_left" +meta2-1;3A = "/cursor move area_up" +meta2-1;3B = "/cursor move area_down" +meta2-1;3C = "/cursor move area_right" +meta2-1;3D = "/cursor move area_left" +meta2-A = "/cursor move up" +meta2-B = "/cursor move down" +meta2-C = "/cursor move right" +meta2-D = "/cursor move left" +@chat(python.matrix.*):r = "hsignal:matrix_cursor_reply" +@item(buffer_nicklist):K = "/window ${_window_number};/kickban ${nick}" +@item(buffer_nicklist):b = "/window ${_window_number};/ban ${nick}" +@item(buffer_nicklist):k = "/window ${_window_number};/kick ${nick}" +@item(buffer_nicklist):q = "/window ${_window_number};/query ${nick};/cursor stop" +@item(buffer_nicklist):w = "/window ${_window_number};/whois ${nick}" +@chat:Q = "hsignal:chat_quote_time_prefix_message;/cursor stop" +@chat:m = "hsignal:chat_quote_message;/cursor stop" +@chat:q = "hsignal:chat_quote_prefix_message;/cursor stop" + +[key_mouse] +@bar(buflist):ctrl-wheeldown = "hsignal:buflist_mouse" +@bar(buflist):ctrl-wheelup = "hsignal:buflist_mouse" +@bar(input):button2 = "/input grab_mouse_area" +@bar(nicklist):button1-gesture-down = "/bar scroll nicklist ${_window_number} +100%" +@bar(nicklist):button1-gesture-down-long = "/bar scroll nicklist ${_window_number} e" +@bar(nicklist):button1-gesture-up = "/bar scroll nicklist ${_window_number} -100%" +@bar(nicklist):button1-gesture-up-long = "/bar scroll nicklist ${_window_number} b" +@chat(fset.fset):button1 = "/window ${_window_number};/fset -go ${_chat_line_y}" +@chat(fset.fset):button2* = "hsignal:fset_mouse" +@chat(fset.fset):wheeldown = "/fset -down 5" +@chat(fset.fset):wheelup = "/fset -up 5" +@chat(script.scripts):button1 = "/window ${_window_number};/script go ${_chat_line_y}" +@chat(script.scripts):button2 = "/window ${_window_number};/script go ${_chat_line_y};/script installremove -q ${script_name_with_extension}" +@chat(script.scripts):wheeldown = "/script down 5" +@chat(script.scripts):wheelup = "/script up 5" +@item(buffer_nicklist):button1 = "/window ${_window_number};/query ${nick}" +@item(buffer_nicklist):button1-gesture-left = "/window ${_window_number};/kick ${nick}" +@item(buffer_nicklist):button1-gesture-left-long = "/window ${_window_number};/kickban ${nick}" +@item(buffer_nicklist):button2 = "/window ${_window_number};/whois ${nick}" +@item(buffer_nicklist):button2-gesture-left = "/window ${_window_number};/ban ${nick}" +@item(buflist):button1* = "hsignal:buflist_mouse" +@item(buflist):button2* = "hsignal:buflist_mouse" +@item(buflist2):button1* = "hsignal:buflist_mouse" +@item(buflist2):button2* = "hsignal:buflist_mouse" +@item(buflist3):button1* = "hsignal:buflist_mouse" +@item(buflist3):button2* = "hsignal:buflist_mouse" +@bar:wheeldown = "/bar scroll ${_bar_name} ${_window_number} +20%" +@bar:wheelup = "/bar scroll ${_bar_name} ${_window_number} -20%" +@chat:button1 = "/window ${_window_number}" +@chat:button1-gesture-left = "/window ${_window_number};/buffer -1" +@chat:button1-gesture-left-long = "/window ${_window_number};/buffer 1" +@chat:button1-gesture-right = "/window ${_window_number};/buffer +1" +@chat:button1-gesture-right-long = "/window ${_window_number};/input jump_last_buffer" +@chat:ctrl-wheeldown = "/window scroll_horiz -window ${_window_number} +10%" +@chat:ctrl-wheelup = "/window scroll_horiz -window ${_window_number} -10%" +@chat:wheeldown = "/window scroll_down -window ${_window_number}" +@chat:wheelup = "/window scroll_up -window ${_window_number}" +@*:button3 = "/cursor go ${_x},${_y}" diff --git a/.xinitrc.dwm b/.xinitrc.dwm new file mode 100755 index 0000000..04ea96f --- /dev/null +++ b/.xinitrc.dwm @@ -0,0 +1,2 @@ +xrdb -merge ~/.Xresources +exec dbus-run-session -- ~/.bin/dwm-start diff --git a/.zshrc b/.zshrc new file mode 100755 index 0000000..f30f562 --- /dev/null +++ b/.zshrc @@ -0,0 +1,62 @@ +# ~/.zshrc configuration ~~ rgoncalves.se + +. ~/.cprofile + +set -o vi + +precmd() { + vcs_info +} + +# keybinds +autoload -U history-search-end +zle -N history-beginning-search-backward-end history-search-end +zle -N history-beginning-search-forward-end history-search-end +bindkey "^[[A" history-beginning-search-backward-end +bindkey "^[[B" history-beginning-search-forward-end +bindkey "^[[1;5C" forward-word +bindkey "^[[1;5D" backward-word +bindkey "\[[H" beginning-of-line +bindkey "\[[F" end-of-line +bindkey "\e[3~" delete-char +bindkey '^[[Z' reverse-menu-complete +zstyle ':completion:*' completer _complete +zstyle ':completion:*' matcher-list '' 'm:{[:lower:][:upper:]}={[:upper:][:lower:]}' '+l:|=* r:|=*' +autoload -Uz compinit +compinit -u + +# history +HISTSIZE=1000 +HISTFILE=~/.zsh_history +SAVEHIST=1000 +HISTDUP=erase +setopt INC_APPEND_HISTORY +setopt HIST_IGNORE_ALL_DUPS + +# prompt +setopt PROMPT_SUBST +_hostname="@${HOST}" +_user="${USER}" +_separator=" " +_prompt="%%" +_dir="%~" +_color=002 + +autoload -Uz vcs_info +zstyle ':vcs_info:*' enable git svn +zstyle ':vcs_info:*' enable git +zstyle ':vcs_info:*' get-revision true +zstyle ':vcs_info:*' check-for-changes true +zstyle ':vcs_info:*' stagedstr "●" +zstyle ':vcs_info:*' unstagedstr "+" +zstyle ":completion:*" menu select +zstyle ':vcs_info:git*' formats "%F{$_color} ▒ %b %u%c" +vcs_info + +PROMPT="${_user}%F{$_color}${_hostname}:" +PROMPT="${PROMPT}%F{015}${_dir}" +PROMPT="${PROMPT}${_separator}${_prompt}${_separator}%f" +RPROMPT='${vcs_info_msg_0_}' + +(cat ~/.cache/dot/sequences 2>/dev/null &) +# clear -- cgit v1.2.3