commit 20b77ce3f6ab8119cccc0e7c56455222a5018276 parent e6ed1e8a0d08c10239e0e10b235bab8020b8ff92 Author: mtmn <miro@haravara.org> Date: Mon, 22 Jun 2026 12:54:00 +0200 cleanup, move plugins to flake inputs Diffstat:
37 files changed, 83 insertions(+), 4706 deletions(-)
diff --git a/flake.lock b/flake.lock @@ -310,7 +310,10 @@ "nix-index-database": "nix-index-database", "nixpkgs": "nixpkgs_3", "ragenix": "ragenix", - "shirts": "shirts" + "shirts": "shirts", + "tmux-xpanes": "tmux-xpanes", + "zsh-autopair": "zsh-autopair", + "zsh-histdb": "zsh-histdb" } }, "rust-overlay": { @@ -396,6 +399,54 @@ "repo": "default", "type": "github" } + }, + "tmux-xpanes": { + "flake": false, + "locked": { + "lastModified": 1777951388, + "narHash": "sha256-9lNeKJSWSsJRTu+mmbH+PQlF9so2Snk05mQ+KTKVcxM=", + "owner": "greymd", + "repo": "tmux-xpanes", + "rev": "384b12780759f53056f58fb05645dfac89688da8", + "type": "github" + }, + "original": { + "owner": "greymd", + "repo": "tmux-xpanes", + "type": "github" + } + }, + "zsh-autopair": { + "flake": false, + "locked": { + "lastModified": 1720984677, + "narHash": "sha256-3zvOgIi+q7+sTXrT+r/4v98qjeiEL4Wh64rxBYnwJvQ=", + "owner": "hlissner", + "repo": "zsh-autopair", + "rev": "449a7c3d095bc8f3d78cf37b9549f8bb4c383f3d", + "type": "github" + }, + "original": { + "owner": "hlissner", + "repo": "zsh-autopair", + "type": "github" + } + }, + "zsh-histdb": { + "flake": false, + "locked": { + "lastModified": 1713463338, + "narHash": "sha256-vtG1poaRVbfb/wKPChk1WpPgDq+7udLqLfYfLqap4Vg=", + "owner": "larkery", + "repo": "zsh-histdb", + "rev": "90a6c104d0fcc0410d665e148fa7da28c49684eb", + "type": "github" + }, + "original": { + "owner": "larkery", + "repo": "zsh-histdb", + "type": "github" + } } }, "root": "root", diff --git a/flake.nix b/flake.nix @@ -31,6 +31,21 @@ corpus = { url = "sourcehut:~mtmn/corpus"; }; + + zsh-autopair = { + url = "github:hlissner/zsh-autopair"; + flake = false; + }; + + zsh-histdb = { + url = "github:larkery/zsh-histdb"; + flake = false; + }; + + tmux-xpanes = { + url = "github:greymd/tmux-xpanes"; + flake = false; + }; }; outputs = { diff --git a/hosts/bbox/default.nix b/hosts/bbox/default.nix @@ -24,7 +24,6 @@ git-crypt git-absorb git-annex - lazygit jujutsu jjui prek diff --git a/hosts/void/default.nix b/hosts/void/default.nix @@ -49,7 +49,6 @@ git-crypt git-absorb git-bug - lazygit jujutsu jjui prek diff --git a/hosts/void/overlays/config/shell/rc/void b/hosts/void/overlays/config/shell/rc/void Binary files differ. diff --git a/hosts/work/default.nix b/hosts/work/default.nix Binary files differ. diff --git a/modules/mixins/dotfiles/bin/xpanes b/modules/mixins/dotfiles/bin/xpanes @@ -1,2217 +0,0 @@ -#!/usr/bin/env bash -# https://github.com/greymd/tmux-xpanes - -readonly XP_SHELL="/usr/bin/env bash" - -# @Author Yamada, Yasuhiro -# @Filename xpanes - -set -u -readonly XP_VERSION="4.2.0" - -## trap might be updated in 'xpns_pre_execution' function -trap 'rm -f "${XP_CACHE_HOME}"/__xpns_*$$; xpns_clean_session' EXIT - -## -------------------------------- -# Error constants -## -------------------------------- -# Invalid option/argument -readonly XP_EINVAL=4 - -# Could not open tty. -readonly XP_ETTY=5 - -# Invalid layout. -readonly XP_ELAYOUT=6 - -# Impossible layout: Small pane -readonly XP_ESMLPANE=7 - -# Log related exit status is 2x. -## Could not create a directory. -readonly XP_ELOGDIR=20 - -## Could not directory to store logs is not writable. -readonly XP_ELOGWRITE=21 - -# User's intentional exit is 3x -## User exit the process intentionally by following warning message. -readonly XP_EINTENT=30 - -## All the panes are closed before processing due to user's options/command. -readonly XP_ENOPANE=31 - -# Necessary commands are not found -readonly XP_ENOCMD=127 - -# =============== - -# XP_THIS_FILE_NAME is supposed to be "xpanes". -readonly XP_THIS_FILE_NAME="${0##*/}" -# shellcheck disable=SC2155 -readonly XP_THIS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")" && pwd)" -readonly XP_ABS_THIS_FILE_NAME="${XP_THIS_DIR}/${XP_THIS_FILE_NAME}" - -# Prevent cache directory being created under root / directory in any case. -# This is quite rare case (but it can be happened). -readonly XP_USER_HOME="${HOME:-/tmp}" - -# Basically xpanes follows XDG Base Direcotry Specification. -# https://specifications.freedesktop.org/basedir-spec/basedir-spec-0.6.html -XDG_CACHE_HOME="${XDG_CACHE_HOME:-${XP_USER_HOME}/.cache}" -readonly XP_CACHE_HOME="${XDG_CACHE_HOME}/xpanes" - -# This is supposed to be xpanes-12345(PID) -readonly XP_SESSION_NAME="${XP_THIS_FILE_NAME}-$$" -# Temporary window name is tmp-12345(PID) -readonly XP_TMP_WIN_NAME="tmp-$$" -readonly XP_EMPTY_STR="EMPTY" - -readonly XP_SUPPORT_TMUX_VERSION_LOWER="1.8" - -# Check dependencies just in case. -# Even POSIX compliant commands are only used in this program. -# `xargs`, `sleep`, `mkfifo` are omitted because minimum functions can work without them. -readonly XP_DEPENDENCIES="${XP_DEPENDENCIES:-tmux grep sed tr od echo touch printf cat sort pwd cd mkfifo}" - -## -------------------------------- -# User customizable shell variables -## -------------------------------- -TMUX_XPANES_EXEC=${TMUX_XPANES_EXEC:-tmux} -TMUX_XPANES_PANE_BORDER_FORMAT="${TMUX_XPANES_PANE_BORDER_FORMAT:-#[bg=green,fg=black] #T #[default]}" -TMUX_XPANES_PANE_BORDER_STATUS="${TMUX_XPANES_PANE_BORDER_STATUS:-bottom}" -TMUX_XPANES_PANE_DEAD_MESSAGE=${TMUX_XPANES_PANE_DEAD_MESSAGE:-'\033[41m\033[4m\033[30m Pane is dead: Press [Enter] to exit... \033[0m\033[39m\033[49m'} -XP_DEFAULT_TMUX_XPANES_LOG_FORMAT="[:ARG:].log.%Y-%m-%d_%H-%M-%S" -TMUX_XPANES_LOG_FORMAT="${TMUX_XPANES_LOG_FORMAT:-${XP_DEFAULT_TMUX_XPANES_LOG_FORMAT}}" -XP_DEFAULT_TMUX_XPANES_LOG_DIRECTORY="${XP_CACHE_HOME}/logs" -TMUX_XPANES_LOG_DIRECTORY="${TMUX_XPANES_LOG_DIRECTORY:-${XP_DEFAULT_TMUX_XPANES_LOG_DIRECTORY}}" - -## -------------------------------- -# Initialize Options -## -------------------------------- -# options which work individually. -# readonly XP_FLAG_OPTIONS="[hVdetxs]" -# options which need arguments. -readonly XP_ARG_OPTIONS="[ISclnCRB]" -readonly XP_DEFAULT_LAYOUT="tiled" -readonly XP_DEFAULT_REPSTR="{}" -readonly XP_DEFAULT_CMD_UTILITY="echo {} " -readonly XP_SSH_CMD_UTILITY="ssh -o StrictHostKeyChecking=no {} " -readonly XP_OFS="${XP_OFS:- }" -XP_OPTIONS=() -XP_ARGS=() -XP_STDIN=() -XP_BEGIN_ARGS=() -XP_IS_PIPE_MODE=0 -XP_OPT_IS_SYNC=1 -XP_OPT_DRY_RUN=0 -XP_OPT_ATTACH=1 -XP_OPT_LOG_STORE=0 -XP_REPSTR="" -XP_DEFAULT_SOCKET_PATH_BASE="${XP_CACHE_HOME}/socket" -XP_DEFAULT_SOCKET_PATH="${XP_DEFAULT_SOCKET_PATH_BASE}.$$" -XP_SOCKET_PATH="${XP_SOCKET_PATH:-${XP_DEFAULT_SOCKET_PATH}}" -XP_NO_OPT=0 -XP_OPT_CMD_UTILITY=0 -XP_CMD_UTILITY="" -XP_LAYOUT="${XP_DEFAULT_LAYOUT}" -XP_MAX_PANE_ARGS="" -XP_OPT_SET_TITLE=0 -XP_OPT_CHANGE_BORDER=0 -XP_OPT_EXTRA=0 -XP_OPT_REUSE=0 -XP_OPT_SPEEDY=0 -XP_OPT_SPEEDY_AWAIT=0 -XP_OPT_USE_PRESET_LAYOUT=0 -XP_OPT_CUSTOM_SIZE_COLS= -XP_OPT_CUSTOM_SIZE_ROWS= -XP_OPT_BULK_COLS= -XP_WINDOW_WIDTH= -XP_WINDOW_HEIGHT= -XP_COLS= -XP_COLS_OFFSETS= -XP_OPT_INTERVAL=0 -XP_OPT_DEBUG=0 -XP_OPT_IGNORE_SIZE_LIMIT=0 - -xpns_log() { - local _loglevel="info" - local debugoutput="" - if [[ "$#" -gt 1 ]]; then - # we ignore the return value of this command, hence disabling shell check - # shellcheck disable=SC2155 - local _specifiedloglevel=$(echo "$1" | tr '[:upper:]' '[:lower:]') - case ${_specifiedloglevel} in - info | warning | error) - loglevel=${_specifiedloglevel} - ;; - debug) - if [[ $XP_OPT_DEBUG -eq 1 ]]; then - debugoutput=$(date "+:%F_%T"):${FUNCNAME[1]} - loglevel=${_specifiedloglevel} - else - return - fi - ;; - *) - printf "[%s] %s %s\n" "${XP_THIS_FILE_NAME}:internal error" "invalid log type, if you get this error." "Please file an issue on github: https://github.com/greymd/tmux-xpanes/issues" >&2 - return - ;; - esac - shift - fi - # in this case we want empty arguments, as debugoutput is not populated at all times. - # shellcheck disable=SC2183 - printf "[%s] %s %s %s\n" "${XP_THIS_FILE_NAME}"":${loglevel}""${debugoutput}" "$*" >&2 -} - -xpns_usage_warn() { - xpns_usage_short >&2 - echo "Try '${XP_THIS_FILE_NAME} --help' for more information." >&2 -} - -xpns_usage_short() { - cat << _EOS_ -Usage: ${XP_THIS_FILE_NAME} [OPTIONS] [argument ...] -Usage(Pipe mode): command ... | ${XP_THIS_FILE_NAME} [OPTIONS] [<command> ...] -_EOS_ -} - -xpns_usage() { - cat << USAGE -Usage: - ${XP_THIS_FILE_NAME} [OPTIONS] [argument ...] - -Usage(Pipe mode): - command ... | ${XP_THIS_FILE_NAME} [OPTIONS] [<command> ...] - -OPTIONS: - -h,--help Display this help and exit. - -V,--version Output version information and exit. - -B <begin-command> Run <begin-command> before processing <command> in each pane. Multiple options are allowed. - -c <command> Set <command> to be executed in each pane. Default is \`echo {}\`. - -d,--desync Make synchronize-panes option off in new window. - -e Execute given arguments as is. Same as \`-c '{}'\` - -I <repstr> Replacing one or more occurrences of <repstr> in command provided by -c or -B. Default is \`{}\`. - -C NUM,--cols=NUM Number of columns of window layout. - -R NUM,--rows=NUM Number of rows of window layout. - -l <layout> Set the preset of window layout. Recognized layout arguments are: - t tiled - eh even-horizontal - ev even-vertical - mh main-horizontal - mv main-vertical - -n <number> Set the maximum number of <argument> taken for each pane. - -r Reuse the existing panes, or create then in the current active window. - -s Speedy mode: Run command without opening an interactive shell. - -ss Speedy mode AND close a pane automatically at the same time as process exiting. - -S <socket-path> Set a full alternative path to the server socket. - -t Display each argument on the each pane's border as their title. - -x Create extra panes in the current active window. - --log[=<directory>] Enable logging and store log files to ~/.cache/xpanes/logs or <directory>. - --log-format=<FORMAT> Make name of log files follow <FORMAT>. Default is \`${XP_DEFAULT_TMUX_XPANES_LOG_FORMAT}\`. - --ssh Same as \`-t -s -c 'ssh -o StrictHostKeyChecking=no {}'\`. - --stay Do not switch to new window. - --bulk-cols=NUM1[,NUM2 ...] Set number of columns on multiple rows (i.e, "2,2,2" represents 2 cols x 3 rows). - --interval=<seconds> Set interval between each pane creation and each command execution. - sleep(1) is used for the interval. - --debug Print debug message. - -Copyright (c) 2023 Yamada, Yasuhiro -Released under the MIT License. -https://github.com/greymd/tmux-xpanes -USAGE -} - -# Show version number -xpns_version() { - echo "${XP_THIS_FILE_NAME} ${XP_VERSION}" -} - -# Get version number for tmux -xpns_get_tmux_version() { - local _tmux_version="" - if ! ${TMUX_XPANES_EXEC} -V &> /dev/null; then - # From tmux 0.9 to 1.3, there is no -V option. - _tmux_version="tmux 0.9-1.3" - else - _tmux_version="$( ${TMUX_XPANES_EXEC} -V)" - fi - read -r _ _ver <<< "${_tmux_version}" - # Strip the leading "next-" part that is present in tmux versions that are - # in development. Eg: next-3.3 - echo "${_ver//next-/}" -} - -# Check whether the prefered tmux version is greater than host's tmux version. -# $1 ... Prefered version. -# $2 ... Host tmux version(optional). -# In case of tmux version is 1.7, the result will be like this. -# 0 is true, 1 is false. -## arg -> result -# func 1.5 1.7 -> 0 -# func 1.6 1.7 -> 0 -# func 1.7 1.7 -> 0 -# func 1.8 1.7 -> 1 -# func 1.9 1.7 -> 1 -# func 1.9a 1.7 -> 1 -# func 2.0 1.7 -> 1 -xpns_tmux_is_greater_equals() { - local _check_version="$1" - local _tmux_version="${2:-$(xpns_get_tmux_version)}" - # Simple numerical comparison does not work because there is the version like "1.9a". - if [[ "$( printf "%s\\n%s" "${_tmux_version}" "${_check_version}" | sort -n | head -n 1)" != "${_check_version}" ]]; then - return 1 - else - return 0 - fi -} - -xpns_get_local_tmux_conf() { - local _conf_name="$1" - local _session="${2-}" - { - if [[ -z "${_session-}" ]]; then - ${TMUX_XPANES_EXEC} show-window-options - else - ${TMUX_XPANES_EXEC} -S "${_session}" show-window-options - fi - } | grep "^${_conf_name}" | - { - read -r _ _v - printf "%s\\n" "${_v}" - } -} - -xpns_get_global_tmux_conf() { - local _conf_name="$1" - local _session="${2-}" - { - if [[ -z "${_session-}" ]]; then - ${TMUX_XPANES_EXEC} show-window-options -g - else - ${TMUX_XPANES_EXEC} -S "${_session}" show-window-options -g - fi - } | grep "^${_conf_name}" | - { - read -r _ _v - printf "%s\\n" "${_v}" - } -} - -# Disable allow-rename because -# window separation does not work correctly -# if "allow-rename" option is on -xpns_suppress_allow_rename() { - local _default_allow_rename="$1" - local _session="${2-}" - if [[ "${_default_allow_rename-}" == "on" ]]; then - ## Temporary, disable "allow-rename" - xpns_log "debug" "'allow-rename' option is 'off' temporarily." - if [[ -z "${_session-}" ]]; then - ${TMUX_XPANES_EXEC} set-window-option -g allow-rename off - else - ${TMUX_XPANES_EXEC} -S "${_session}" set-window-option -g allow-rename off - fi - fi -} - -# Restore default "allow-rename" -# Do not write like 'xpns_restore_allow_rename "some value" "some value" > /dev/null' -# In tmux 1.6, 'tmux set-window-option' might be stopped in case of redirection. -xpns_restore_allow_rename() { - local _default_allow_rename="$1" - local _session="${2-}" - if [[ "${_default_allow_rename-}" == "on" ]]; then - xpns_log "debug" "Restore original value of 'allow-rename' option." - if [[ -z "${_session-}" ]]; then - ${TMUX_XPANES_EXEC} set-window-option -g allow-rename on - else - ${TMUX_XPANES_EXEC} -S "${_session}" set-window-option -g allow-rename on - fi - fi -} - -xpns_interval() { - local _interval="$1" - if [[ "${_interval}" != "0" ]]; then - sleep "${_interval}" - fi -} - -# func "11" "2" -# => 6 -# 11 / 2 = 5.5 => ceiling => 6 -xpns_ceiling() { - local _divide="$1" - shift - local _by="$1" - printf "%s\\n" $(((_divide + _by - 1) / _by)) -} - -# func "10" "3" -# => 4 3 3 -# Divide 10 into 3 parts as equally as possible. -xpns_divide_equally() { - local _number="$1" - shift - local _count="$1" - local _upper _lower _upper_count _lower_count - _upper="$(xpns_ceiling "$_number" "$_count")" - _lower=$((_upper - 1)) - _lower_count=$((_upper * _count - _number)) - _upper_count=$((_count - _lower_count)) - eval "printf '${_upper} %.0s' {1..$_upper_count}" - ((_lower_count > 0)) && eval "printf '${_lower} %.0s' {1..$_lower_count}" -} - -# echo 3 3 3 3 | func -# => 3 6 9 12 -xpns_nums_accumulate_sum() { - local s=0 - while read -r n; do - ((s = s + n)) - printf "%s " "$s" - done < <( cat | tr ' ' '\n') -} - -# func 3 2 2 2 -# => 4 4 1 -# -# For example, "3 2 2 2" represents following cell positions -# 1 2 3 -# 1 [] [] [] => 3 rows -# 2 [] [] => 2 rows -# 3 [] [] => 2 rows -# 4 [] [] => 2 rows -# -# After the transposition, it must be "4 4 1" which represents below -# 1 2 3 4 -# 1 [] [] [] [] => 4 rows -# 2 [] [] [] [] => 4 rows -# 3 [] => 1 rows -xpns_nums_transpose() { - local _colnum="$1" - local _spaces= - local _result= - xpns_log "debug" "column num = $_colnum, input = $*" - _spaces="$(for i in "$@"; do - printf "%${i}s\\n" - done)" - - # 'for' statement does not work somehow - _result="$(while read -r i; do - ## This part is depending on the following 'cut' behavior - ## $ echo 1234 | cut -c 5 - ## => result is supposed to be empty - printf "%s\\n" "$_spaces" | cut -c "$i" | grep -c ' ' - done < <(xpns_seq 1 "${_colnum}") | xpns_newline2space)" - xpns_log "debug" "result = $_result" - printf "%s\\n" "$_result" -} - -# Adjust size of columns and rows in accordance with given N -# func <col> <row> <N> -# i.e: -# func "" "" 20 -# => returns 4 5 -# func "6" 0 20 -# => returns 6 4 -xpns_adjust_col_row() { - local col="${1:-0}" - shift - local row="${1:-0}" - shift - local N="$1" - shift - local fix_col_flg - local fix_row_flg - ((col != 0)) && fix_col_flg=1 || fix_col_flg=0 - ((row != 0)) && fix_row_flg=1 || fix_row_flg=0 - - # This is just a author (@greymd)'s preference. - if ((fix_col_flg == 0)) && ((fix_row_flg == 0)) && ((N == 2)); then - col=2 - row=1 - printf "%d %d\\n" "${col}" "${row}" - return - fi - - # If both values are provided, col is used. - if ((fix_col_flg == 1)) && ((fix_row_flg == 1)); then - row=0 - fix_row_flg=0 - fi - # This algorhythm is almost same as tmux default - # https://github.com/tmux/tmux/blob/2.8/layout-set.c#L436 - while ((col * row < N)); do - ((fix_row_flg != 1)) && ((row = row + 1)) - if ((col * row < N)); then - ((fix_col_flg != 1)) && ((col = col + 1)) - fi - done - printf "%d %d\\n" "${col}" "${row}" -} - -# Make each line unique by adding index number -# echo aaa bbb ccc aaa ccc ccc | xargs -n 1 | xpns_unique_line -# aaa-1 -# bbb-1 -# ccc-1 -# aaa-2 -# ccc-2 -# ccc-3 -# -# Eval is used because associative array is not supported before bash 4.2 -xpns_unique_line() { - local _val_name - while read -r line; do - _val_name="__xpns_hash_$(printf "%s" "${line}" | xpns_value2key)" - # initialize variable - eval "${_val_name}=\${${_val_name}:-0}" - # increment variable - eval "${_val_name}=\$(( ++${_val_name} ))" - printf "%s\\n" "${line}-$(eval printf "%s" "\$${_val_name}")" - done -} - -# -# Generate log file names from given arguments. -# Usage: -# echo <arg1> <arg2> ... | xpns_log_filenames <FORMAT> -# Return: -# File names. -# Example: -# $ echo aaa bbb ccc aaa ccc ccc | xargs -n 1 | xpns_log_filenames '[:ARG:]_[:PID:]_%Y%m%d.log' -# aaa-1_1234_20160101.log -# bbb-1_1234_20160101.log -# ccc-1_1234_20160101.log -# aaa-2_1234_20160101.log -# ccc-2_1234_20160101.log -# ccc-3_1234_20160101.log -# -xpns_log_filenames() { - local _arg_fmt="$1" - local _full_fmt= - _full_fmt="$(date "+${_arg_fmt}")" - cat | - # 1st argument + '-' + unique number (avoid same argument has same name) - xpns_unique_line | - while read -r _arg; do - cat <<< "${_full_fmt}" | sed -e "s/\\[:ARG:\\]/${_arg}/g" -e "s/\\[:PID:\\]/$$/g" - done -} - -## -------------------------------- -# Normalize directory by making following conversion. -# * Tilde expansion. -# * Remove the slash '/' at the end of the dirname. -# Usage: -# xpns_normalize_directory <direname> -# Return: -# Normalized <dirname> -## -------------------------------- - -xpns_normalize_directory() { - # Remove end of slash '/' for the first arguement - local _dir="${1%/}" - # tilde expansion - printf "%s\\n" "${_dir/#~/$HOME}" -} -## -------------------------------- -# Ensure existence of given directory -# Usage: -# xpns_is_valid_directory <dirname> -# Return: -# Absolute path of the <dirname> -## -------------------------------- -xpns_is_valid_directory() { - local _dir="$1" - local _checkfile="${XP_THIS_FILE_NAME}.$$" - # Check directory. - if ! [[ -d "${_dir}" ]]; then - # Create directory - if ! mkdir "${_dir}"; then - xpns_log "error" "Failed to create ${_dir}" - exit ${XP_ELOGDIR} - fi - xpns_log "info" "${_dir} is created." - fi - # Try to create file. - # Not only checking directory permission, - # but also i-node and other misc situations. - if ! touch "${_dir}/${_checkfile}"; then - xpns_log "error" "${_dir} is not writable." - rm -f "${_dir}/${_checkfile}" - exit ${XP_ELOGWRITE} - fi - rm -f "${_dir}/${_checkfile}" -} - -# Convert array to string which is can be used as command line argument. -# Usage: -# xpns_arr2args <array object> -# Example: -# array=(aaa bbb "ccc ddd" eee "f'f") -# xpns_arr2args "${array[@]}" -# @returns "'aaa' 'bbb' 'ccc ddd' 'eee' 'f\'f'" -# Result: -xpns_arr2args() { - # If there is no argument, usage will be shown. - if [[ $# -lt 1 ]]; then - return 0 - fi - for _arg in "$@"; do - # Use 'cat <<<"input"' command instead of 'echo', - # because such the command recognizes option like '-e'. - cat <<< "${_arg}" | - # Escaping single quotes and - # Surround argument with single quotations. - sed "s/'/'\"'\"'/g; s/^/'/; s/$/' /" | - # Remove new lines - tr -d '\n' - done -} - -# Extract first field to generate window name. -# ex, $2 = 'aaa bbb ccc' -# return = aaa-12345(PID) -xpns_generate_window_name() { - local _unprintable_str="${1-}" - shift - # Leave first 200 characters to prevent - # the name exceed the maximum length of tmux window name (2000 byte). - printf "%s\\n" "${1:-${_unprintable_str}}" | - ( read -r _name _ && printf "%s\\n" "${_name:0:200}-$$" ) -} - -# Convert any string (including multi-byte chars) to another string -# which can be handled as tmux window name. -xpns_value2key() { - od -v -tx1 -An | tr -dc 'a-zA-Z0-9' | tr -d '\n' -} - -# Restore string encoded by xpns_value2key function. -xpns_key2value() { - read -r _key - # shellcheck disable=SC2059 - printf "$(printf "%s" "$_key" | sed 's/../\\x&/g')" -} - -# Remove empty lines -# This function behaves like `awk NF` -xpns_rm_empty_line() { - { - cat - printf "\\n" - } | while IFS= read -r line; do - # shellcheck disable=SC2086 - set -- ${line-} - if [[ $# != 0 ]]; then - printf "%s\\n" "${line}" - fi - done -} - -# Enable logging feature to the all the panes in the target window. -xpns_enable_logging() { - local _window_name="$1" - shift - local _index_offset="$1" - shift - local _log_dir="$1" - shift - local _log_format="$1" - shift - local _unprintable_str="$1" - shift - local _args=("$@") - local _args_num=$(($# - 1)) - # Generate log files from arguments. - local _idx=0 - while read -r _logfile; do - # Start logging - xpns_log "debug" "Start logging pipe-pane(cat >> '${_log_dir}/${_logfile}')" - ${TMUX_XPANES_EXEC} \ - pipe-pane -t "${_window_name}.$((_idx + _index_offset))" \ - "cat >> '${_log_dir}/${_logfile}'" # Tilde expansion does not work here. - _idx=$((_idx + 1)) - done < <( - for i in $(xpns_seq 0 "${_args_num}"); do - # Replace empty string. - printf "%s\\n" "${_args[i]:-${_unprintable_str}}" - done | xpns_log_filenames "${_log_format}" - ) -} - -## Print "1" on the particular named pipe -xpns_notify() { - local _wait_id="$1" - shift - local _fifo= - _fifo="${XP_CACHE_HOME}/__xpns_${_wait_id}" - xpns_log "debug" "Notify to $_fifo" - printf "%s\\n" 1 > "$_fifo" & -} - -xpns_notify_logging() { - local _window_name="$1" - shift - local _args_num=$(($# - 1)) - for i in $(xpns_seq 0 "${_args_num}"); do - xpns_notify "log_${_window_name}-${i}-$$" - done -} - -xpns_notify_sync() { - local _window_name="$1" - shift - local _interval="$1" - shift - local _args_num=$(($# - 1)) - for i in $(xpns_seq 0 "${_args_num}"); do - xpns_interval "${_interval}" - xpns_notify "sync_${_window_name}-${i}-$$" - done -} - -xpns_is_window_alive() { - local _window_name="$1" - shift - local _speedy_await_flag="$1" - shift - local _def_allow_rename="$1" - shift - local _window_name_on_tmux _exit_status - # Check not only exit status but also the if the window id is empty, - # because the exit status of display-message is - # no longer available from tmux version 3.2 (GitHub Issue #175) - _window_name_on_tmux=$(${TMUX_XPANES_EXEC} display-message -t "$_window_name" -p '#{window_id}') - _exit_status=$? - if [[ $_exit_status -ne 0 ]] || [[ -z "$_window_name_on_tmux" ]]; then - xpns_log "info" "All the panes are closed before displaying the result." - if [[ "${_speedy_await_flag}" -eq 0 ]]; then - xpns_log "info" "Use '-s' option instead of '-ss' option to avoid this behavior." - fi - xpns_restore_allow_rename "${_def_allow_rename-}" - exit ${XP_ENOPANE} - fi -} - -xpns_inject_title() { - local _target_pane="$1" - shift - local _message="$1" - shift - local _pane_tty= - _pane_tty="$( ${TMUX_XPANES_EXEC} display-message -t "${_target_pane}" -p "#{pane_tty}")" - printf "\\033]2;%s\\033\\\\" "${_message}" > "${_pane_tty}" - xpns_log "debug" "target_pane=${_target_pane} pane_title=${_message} pane_tty=${_pane_tty}" -} - -xpns_is_pane_title_required() { - local _title_flag="$1" - shift - local _extra_flag="$1" - shift - local _pane_border_status= - _pane_border_status=$(xpns_get_local_tmux_conf "pane-border-status") - if [[ $_title_flag -eq 1 ]]; then - return 0 - elif [[ ${_extra_flag} -eq 1 ]] && - [[ "${_pane_border_status}" != "off" ]] && - [[ -n "${_pane_border_status}" ]]; then - ## For -x option - # Even the -t option is not specified, it is required to inject pane title here. - # Because user expects the title is displayed on the pane if the original window is - # generated from tmux-xpanes with -t option. - return 0 - fi - return 1 -} - -# Set pane titles for each pane for -t option -xpns_set_titles() { - local _window_name="$1" - shift - local _index_offset="$1" - shift - local _index=0 - local _pane_index= - for arg in "$@"; do - _pane_index=$((_index + _index_offset)) - xpns_inject_title "${_window_name}.${_pane_index}" "${arg}" - _index=$((_index + 1)) - done -} - -# Send command to the all the panes in the target window. -xpns_send_commands() { - local _window_name="$1" - shift - local _index_offset="$1" - shift - local _interval="$1" - shift - local _repstr="$1" - shift - local _cmd="$1" - shift - local _index=0 - for arg in "$@"; do - xpns_interval "${_interval}" - _pane_index=$((_index + _index_offset)) - ${TMUX_XPANES_EXEC} send-keys -t "${_window_name}.${_pane_index}" "${_cmd//${_repstr}/${arg}}" C-m - ((_index++)) - done -} - -# Separate window vertically, when the number of panes is 1 or 2. -xpns_organize_panes() { - local _window_name="$1" - shift - local _args_num="$1" - - # Default behavior - local layout_command=" select-layout -t ${_window_name} even-horizontal" - if ((_args_num > 1)); then - layout_command=" select-layout -t ${_window_name} tiled" - fi - # Update layout - if [[ "${XP_LAYOUT}" != "${XP_DEFAULT_LAYOUT}" ]]; then - layout_command=" select-layout -t ${_window_name} ${XP_LAYOUT}" - fi - # shellcheck disable=SC2086 - ${TMUX_XPANES_EXEC} $layout_command -} - -# -# Generate sequential number descending order. -# seq is not used because old version of -# seq does not generate descending order. -# $ xpns_seq 3 0 -# 3 -# 2 -# 1 -# 0 -# -xpns_seq() { - local _num1="$1" - local _num2="$2" - eval "printf \"%d\\n\" {$_num1..$_num2}" -} - -xpns_wait_func() { - local _wait_id="$1" - local _fifo="${XP_CACHE_HOME}/__xpns_${_wait_id}" - local _arr=("$_fifo") - local _fifo_arg= - _fifo_arg=$(xpns_arr2args "${_arr[@]}") - xpns_log "debug" "mkfifo $_fifo" - mkfifo "${_fifo}" - xpns_log "debug" "grep -q 1 ${_fifo_arg}" - printf "%s\\n" "grep -q 1 ${_fifo_arg}" -} - -# Split a new window into multiple panes. -# -xpns_split_window() { - local _window_name="$1" - shift - local _log_flag="$1" - shift - local _title_flag="$1" - shift - local _speedy_flag="$1" - shift - local _await_flag="$1" - shift - local _interval="$1" - shift - local _pane_base_index="$1" - shift - local _repstr="$1" - shift - local _cmd_template="$1" - shift - local _exec_cmd= - local _sep_count=0 - local args=("$@") - _last_idx=$((${#args[@]} - 1)) - - for i in $(xpns_seq $_last_idx 0); do - xpns_log "debug" "Index:${i} Argument:${args[i]}" - _sep_count=$((_sep_count + 1)) - _exec_cmd="${_cmd_template//${_repstr}/${args[i]}}" - xpns_interval "${_interval}" - ## Speedy mode - if [[ $_speedy_flag -eq 1 ]]; then - _exec_cmd=$(xpns_inject_wait_command "${_log_flag}" "${_title_flag}" "${_speedy_flag}" "${_await_flag}" "$i" "${_exec_cmd}") - # Execute command as a child process of default-shell. - ${TMUX_XPANES_EXEC} split-window -t "${_window_name}" -h -d "${_exec_cmd}" - else - # Open login shell and execute command on the interactive screen. - ${TMUX_XPANES_EXEC} split-window -t "${_window_name}" -h -d - fi - # Restraining that size of pane's width becomes - # less than the minimum size which is defined by tmux. - if [[ ${_sep_count} -gt 2 ]]; then - ${TMUX_XPANES_EXEC} select-layout -t "${_window_name}" tiled - fi - done -} - -# -# Create new panes on existing window. -# Usage: -# func <window name> <offset of index> <number of pane> -# -xpns_prepare_extra_panes() { - local _window_name="$1" - shift - local _pane_base_index="$1" - shift - local _log_flag="$1" - shift - local _title_flag="$1" - shift - local _speedy_flg="$1" - shift - local _await_flg="$1" - shift - local _interval="$1" - shift - # specify a pane which has the biggest index number. - # Because pane_id may not be immutable. - # If the small number of index is specified here, correspondance between pane_title and command can be slip off. - ${TMUX_XPANES_EXEC} select-pane -t "${_window_name}.${_pane_base_index}" - - # split window into multiple panes - xpns_split_window \ - "${_window_name}" \ - "${_log_flag}" \ - "${_title_flag}" \ - "${_speedy_flg}" \ - "${_await_flg}" \ - "${_interval}" \ - "${_pane_base_index}" \ - "$@" -} - -xpns_get_joined_begin_commands() { - local _commands="$1" - if [[ "${#XP_BEGIN_ARGS[*]}" -lt 1 ]]; then - printf "%s" "${_commands}" - return - fi - printf "%s\\n" "${XP_BEGIN_ARGS[@]}" "${_commands}" -} - -xpns_inject_wait_command() { - local _log_flag="$1" - shift - local _title_flag="$1" - shift - local _speedy_flg="$1" - shift - local _await_flg="$1" - shift - local _idx="$1" - shift - local _exec_cmd="$1" - shift - - ## Speedy mode + logging - if [[ "${_log_flag}" -eq 1 ]] && [[ "${_speedy_flg}" -eq 1 ]]; then - # Wait for start of logging - # Without this part, logging thread may start after new process is finished. - # Execute function to wait for logging start. - _exec_cmd="$(xpns_wait_func "log_${_window_name}-${_idx}-$$")"$'\n'"${_exec_cmd}" - fi - - ## Speedy mode (Do not allow to close panes before the separation is finished). - if [[ "${_speedy_flg}" -eq 1 ]]; then - _exec_cmd="$(xpns_wait_func "sync_${_window_name}-${_idx}-$$")"$'\n'${_exec_cmd} - fi - - ## -s: Speedy mode (Not -ss: Speedy mode + nowait) - if [[ "${_await_flg}" -eq 1 ]]; then - local _msg - _msg="$(xpns_arr2args "${TMUX_XPANES_PANE_DEAD_MESSAGE}" | sed 's/"/\\"/g')" - _exec_cmd="${_exec_cmd}"$'\n'"${XP_SHELL} -c \"printf -- ${_msg} >&2 && read\"" - fi - printf "%s" "${_exec_cmd}" -} - -xpns_new_window() { - local _window_name="$1" - shift - local _attach_flg="$1" - shift - local _speedy_flg="$1" - shift - local _exec_cmd="$1" - shift - local _window_id= - - # Create new window. - if [[ "${_attach_flg}" -eq 1 ]]; then - if [[ "${_speedy_flg}" -eq 1 ]]; then - _window_id=$(${TMUX_XPANES_EXEC} new-window -n "${_window_name}" -F '#{window_id}' -P "${_exec_cmd}") - else - _window_id=$(${TMUX_XPANES_EXEC} new-window -n "${_window_name}" -F '#{window_id}' -P) - fi - else - # Keep background - if [[ "${_speedy_flg}" -eq 1 ]]; then - _window_id=$(${TMUX_XPANES_EXEC} new-window -n "${_window_name}" -F '#{window_id}' -P -d "${_exec_cmd}") - else - _window_id=$(${TMUX_XPANES_EXEC} new-window -n "${_window_name}" -F '#{window_id}' -P -d) - fi - fi - printf "%s" "${_window_id}" -} - -xpns_new_pane_vertical() { - local _window_id="$1" - shift - local _cell_height="$1" - shift - local _speedy_flg="$1" - shift - local _exec_cmd="$1" - shift - local _pane_id= - if [[ "${_speedy_flg}" -eq 1 ]]; then - _pane_id="$(${TMUX_XPANES_EXEC} split-window -t "$_window_id" -v -d -l "${_cell_height}" -F '#{pane_id}' -P "${_exec_cmd}")" - else - _pane_id="$(${TMUX_XPANES_EXEC} split-window -t "$_window_id" -v -d -l "${_cell_height}" -F '#{pane_id}' -P)" - fi - printf "%s\\n" "${_pane_id}" -} - -xpns_split_pane_horizontal() { - local _target_pane_id="$1" - shift - local _cell_width="$1" - shift - local _speedy_flg="$1" - shift - local _exec_cmd="$1" - shift - if [[ "${_speedy_flg}" -eq 1 ]]; then - ${TMUX_XPANES_EXEC} split-window -t "$_target_pane_id" -h -d -l "$_cell_width" "${_exec_cmd}" - else - ${TMUX_XPANES_EXEC} split-window -t "$_target_pane_id" -h -d -l "$_cell_width" - fi -} - -xpns_prepare_window() { - local _window_name="$1" - shift - local _log_flag="$1" - shift - local _title_flag="$1" - shift - local _attach_flg="$1" - shift - local _speedy_flg="$1" - shift - local _await_flg="$1" - shift - local _interval="$1" - shift - local _repstr="$1" - shift - local _cmd_template="$1" - shift - local _args=("$@") - local _window_height="$XP_WINDOW_HEIGHT" - local _window_width="$XP_WINDOW_WIDTH" - local _col="$XP_OPT_CUSTOM_SIZE_COLS" - local _row="$XP_OPT_CUSTOM_SIZE_ROWS" - local _cols=("${XP_COLS[@]}") - local _cols_offset=("${XP_COLS_OFFSETS[@]}") - local _exec_cmd= - local _pane_id= - local _first_pane_id= - local _window_id= - local _cell_height= - local _cell_width= - local _top_pane_height= - local _current_pane_width= - local i= - local j= - local _rest_col= - local _rest_row= - local _offset= - - _cell_height=$(((_window_height - _row + 1) / _row)) - ## Insert first element - _exec_cmd="${_cmd_template//${_repstr}/${_args[0]}}" - _exec_cmd="$(xpns_inject_wait_command "${_log_flag}" "${_title_flag}" "${_speedy_flg}" "${_await_flg}" 0 "${_exec_cmd}")" - _window_id=$(xpns_new_window "${_window_name}" "${_attach_flg}" "${_speedy_flg}" "${_exec_cmd}") - _first_pane_id=$(${TMUX_XPANES_EXEC} display-message -t "$_window_id" -p -F '#{pane_id}' | head -n 1) - - ## Start from last row - for ((i = _row - 1; i > 0; i--)); do - _col="${_cols[i]}" - _cell_width=$(((_window_width - _col + 1) / _col)) - xpns_log "debug" "_col=$_col" - ((_offset = _cols_offset[i])) - for ((j = 0; j < _col; j++)); do - xpns_interval "${_interval}" - if ((j == 0)); then - ((idx = _offset - _col)) - # Create new row - # Insert first element of the row first - _exec_cmd="${_cmd_template//${_repstr}/${_args[idx]}}" - _exec_cmd="$(xpns_inject_wait_command "${_log_flag}" "${_title_flag}" "${_speedy_flg}" "${_await_flg}" "${idx}" "${_exec_cmd}")" - _pane_id=$(xpns_new_pane_vertical "${_window_name}" "${_cell_height}" "${_speedy_flg}" "${_exec_cmd}") - fi - # Separate row into columns - if ((j != 0)); then - ((idx = _offset - j)) - _exec_cmd="${_cmd_template//${_repstr}/${_args[idx]}}" - _exec_cmd="$(xpns_inject_wait_command "${_log_flag}" "${_title_flag}" "${_speedy_flg}" "${_await_flg}" "${idx}" "${_exec_cmd}")" - ## Separate row into columns - _current_pane_width=$(${TMUX_XPANES_EXEC} display-message -t "$_pane_id" -p '#{pane_width}' | head -n 1) - _rest_col=$((_col - j + 1)) - _cell_width=$(((_current_pane_width - _rest_col + 1) / _rest_col)) - xpns_split_pane_horizontal "$_pane_id" "$_cell_width" "${_speedy_flg}" "${_exec_cmd}" - fi - done - - # Adjust height - _top_pane_height=$(${TMUX_XPANES_EXEC} display-message -t "$_window_id" -p '#{pane_height}' | head -n 1) - _rest_row=$((i)) - xpns_log "debug" "_top_pane_height=$_top_pane_height _rest_row=$_rest_row" - _cell_height=$(((_top_pane_height - _rest_row + 1) / _rest_row)) - done - - # Split first row into columns - _col="${_cols[0]}" - _cell_width=$(((_window_width - _col + 1) / _col)) - for ((j = 1; j < _col; j++)); do - xpns_interval "${_interval}" - idx=$((_cols_offset[0] - j)) - # Adjust width - _current_pane_width=$(${TMUX_XPANES_EXEC} display-message -t "$_first_pane_id" -p '#{pane_width}' | head -n 1) - _rest_col=$((_col - j + 1)) - _cell_width=$(((_current_pane_width - _rest_col + 1) / _rest_col)) - ## Split top row into columns - _exec_cmd="${_cmd_template//${_repstr}/${_args[idx]}}" - _exec_cmd="$(xpns_inject_wait_command "${_log_flag}" "${_title_flag}" "${_speedy_flg}" "${_await_flg}" "${idx}" "${_exec_cmd}")" - xpns_split_pane_horizontal "${_first_pane_id}" "${_cell_width}" "${_speedy_flg}" "${_exec_cmd}" - done -} - -xpns_is_session_running() { - local _socket="$1" - ${TMUX_XPANES_EXEC} -S "${_socket}" list-session > /dev/null 2>&1 -} - -# Remove unnecessary session files as much as possible -# to make xpanes avoid loading old .tmux.conf. -xpns_clean_session() { - if [[ "${XP_SOCKET_PATH}" != "${XP_DEFAULT_SOCKET_PATH}" ]]; then - return - fi - # Delete old socket file (xpanes v3.1.0 or before). - if [[ -e "${XP_DEFAULT_SOCKET_PATH_BASE}" ]]; then - if ! xpns_is_session_running "${XP_DEFAULT_SOCKET_PATH_BASE}"; then - xpns_log "debug" "socket(${XP_DEFAULT_SOCKET_PATH_BASE}) is not running. Remove it" - rm -f "${XP_DEFAULT_SOCKET_PATH_BASE}" - fi - fi - for _socket in "${XP_CACHE_HOME}"/socket.*; do - xpns_log "debug" "file = ${_socket}" - if ! xpns_is_session_running "${_socket}"; then - xpns_log "debug" "socket(${_socket}) is not running. Remove it" - rm -f "${_socket}" - else - xpns_log "debug" "socket(${_socket}) is running. Keep ${_socket}" - fi - done -} - -# -# Split a new window into multiple panes. -# Usage: -# xpns_prepare_preset_layout_window <window name> <offset of index> <number of pane> <attach or not> -# -xpns_prepare_preset_layout_window() { - local _window_name="$1" - shift - local _pane_base_index="$1" - shift - local _log_flag="$1" - shift - local _title_flag="$1" - shift - local _attach_flg="$1" - shift - local _speedy_flg="$1" - shift - local _await_flg="$1" - shift - local _interval="$1" - shift - # Create new window. - if [[ "${_attach_flg}" -eq 1 ]]; then - ${TMUX_XPANES_EXEC} new-window -n "${_window_name}" - else - # Keep background - ${TMUX_XPANES_EXEC} new-window -n "${_window_name}" -d - fi - - # specify a pane which has the youngest number of index. - ${TMUX_XPANES_EXEC} select-pane -t "${_window_name}.${_pane_base_index}" - - # split window into multiple panes - xpns_split_window \ - "${_window_name}" \ - "${_log_flag}" \ - "${_title_flag}" \ - "${_speedy_flg}" \ - "${_await_flg}" \ - "${_interval}" \ - "${_pane_base_index}" \ - "$@" - - ### If the first pane is still remaining, - ### panes cannot be organized well. - # Delete the first pane - ${TMUX_XPANES_EXEC} kill-pane -t "${_window_name}.${_pane_base_index}" - - # Select second pane here. - # If the command gets error, it would most likely be caused by user (XP_ENOPANE). - # Suppress error message here and announce it in xpns_execution. - ${TMUX_XPANES_EXEC} select-pane -t "${_window_name}.${_pane_base_index}" > /dev/null 2>&1 -} - -# Check whether given command is in the PATH or not. -xpns_check_env() { - local _cmds="$1" - while read -r cmd; do - if ! type "${cmd}" > /dev/null 2>&1; then - if [[ "${cmd}" == "tmux" ]] && [[ "${TMUX_XPANES_EXEC}" == "tmux" ]]; then - xpns_log "error" "${cmd} is required. Install ${cmd} or set TMUX_XPANES_EXEC variable." - exit ${XP_ENOCMD} - elif [[ "${cmd}" != "tmux" ]]; then - xpns_log "error" "${cmd} is required." - exit ${XP_ENOCMD} - fi - fi - done < <(echo "${_cmds}" | tr ' ' '\n') - - if ! mkdir -p "${XP_CACHE_HOME}"; then - xpns_log "warning" "failed to create cache directory '${XP_CACHE_HOME}'." - fi - - # Do not omit this part, this is used by testing. - TMUX_XPANES_TMUX_VERSION="${TMUX_XPANES_TMUX_VERSION:-$(xpns_get_tmux_version)}" - if ( xpns_tmux_is_greater_equals \ - "${XP_SUPPORT_TMUX_VERSION_LOWER}" \ - "${TMUX_XPANES_TMUX_VERSION}" ); then - : "Supported tmux version" - else - xpns_log "warning" \ - "'${XP_THIS_FILE_NAME}' may not work correctly! Please check followings. -* tmux is installed correctly. -* Supported tmux version is installed. - Version ${XP_SUPPORT_TMUX_VERSION_LOWER} and over is officially supported." - fi - - return 0 -} - -xpns_pipe_filter() { - local _number="${1-}" - if [[ -z "${_number-}" ]]; then - cat - else - xargs -n "${_number}" - fi -} - -# Merge array's element by combining with space. -# i.e -# array=(1 2 3 4 5) -# func 3 "array" -# => array is going to be ("1 2 3" "4 5") -xpns_merge_array_elements() { - local _line="" - local _pane_num="$1" - shift - local _arr_name="$1" - shift - local _filtered_args=() - eval 'set -- "${'"$_arr_name"'[@]}"' - local _num="$#" - for ((i = 1; i <= _num; i++)); do - if [[ -z "$_line" ]]; then - _line="$1" - else - _line="${_line}${XP_OFS}$1" - fi - shift - if ((i % _pane_num == 0)); then - _filtered_args+=("${_line}") - _line="" - fi - done - if [[ -n "$_line" ]]; then - _filtered_args+=("${_line}") - fi - eval "$_arr_name"'=("${_filtered_args[@]}")' -} - -xpns_newline2space() { - local _result="" - while read -r _line; do - if [[ -z "$_result" ]]; then - _result="$_line" - else - _result="${_result}${XP_OFS}${_line}" - fi - done - printf "%s\\n" "${_result}" -} - -xpns_get_window_height_width() { - local _height= - local _width= - local _result= - local _dev= - local _pattern='^([0-9]+)[ \t]+([0-9]+)$' - - if ! type stty > /dev/null 2>&1; then - xpns_log "debug" "'stty' does not exist: Failed to get window height and size. Skip checking" - return 1 - fi - - ## This condition is used for unit testing - if [[ -z "${XP_IS_PIPE_MODE-}" ]]; then - if [[ ! -t 0 ]]; then - XP_IS_PIPE_MODE=1 - fi - fi - if [[ $XP_IS_PIPE_MODE -eq 0 ]]; then - if _result=$(stty size 2> /dev/null) && [[ "$_result" =~ $_pattern ]]; then - _height="${BASH_REMATCH[1]}" - _width="${BASH_REMATCH[2]}" - xpns_log "debug" "window height: $_height, width: $_width" - printf "%s\\n" "$_height $_width" - return 0 - fi - else - if ! type ps > /dev/null 2>&1; then - xpns_log "debug" "'ps' does not exist: Failed to get window height and size. Skip checking" - return 1 - fi - { - read -r # Remove first line - read -r _dev - } < <(ps -o tty -p $$ 2> /dev/null) - ## If it's Linux, -F option is used - if _result=$(stty -F "/dev/${_dev}" size 2> /dev/null) && [[ "$_result" =~ $_pattern ]]; then - _height="${BASH_REMATCH[1]}" - _width="${BASH_REMATCH[2]}" - xpns_log "debug" "window height: $_height, width: $_width" - printf "%s\\n" "$_height $_width" - return 0 - fi - ## If it's BSD, macOS, -F option is used - if _result=$(stty -f "/dev/${_dev}" size 2> /dev/null) && [[ "$_result" =~ $_pattern ]]; then - _height="${BASH_REMATCH[1]}" - _width="${BASH_REMATCH[2]}" - xpns_log "debug" "window height: $_height, width: $_width" - printf "%s\\n" "$_height $_width" - return 0 - fi - return 1 - fi - return 1 -} - -xpns_check_cell_size_bulk() { - local _cell_num="$1" - shift - local _bulk_cols="$1" - shift - local _win_height="$1" - shift - local _win_width="$1" - shift - local _ignore_flag="$1" - shift - local _all_cols=() - # shellcheck disable=SC2178 - local _cols=0 - local _rows=0 - local _sum_cell=0 - IFS="," read -r -a _all_cols <<< "${_bulk_cols}" - _rows="${#_all_cols[@]}" - for i in "${_all_cols[@]}"; do - ((i >= _cols)) && ((_cols = i)) - ((_sum_cell = _sum_cell + i)) - done - if ((_sum_cell != _cell_num)); then - xpns_log "error" "Number of cols does not equals to the number of arguments." - xpns_log "error" "Expected (# of args) : $_cell_num, Actual (--bulk-cols) : $_sum_cell)." - return ${XP_ELAYOUT:-6} - fi - local cell_height=$(((_win_height - _rows + 1) / _rows)) - local cell_width=$(((_win_width - _cols + 1) / _cols)) - - ## Display basic information - xpns_log "debug" "Window: { Height: $_win_height, Width: $_win_width }" - xpns_log "debug" "Cell: { Height: $cell_height, Width: $cell_width }" - xpns_log "debug" "# Of Panes: ${_cell_num}" - xpns_log "debug" " | Row[0] --...--> Row[MAX]" - xpns_log "debug" " -----+------------------------..." - xpns_log "debug" " Col[]| ${_all_cols[*]}" - xpns_log "debug" " -----+------------------------..." - - if [[ "$_ignore_flag" -ne 1 ]] && ( ((cell_height < 2)) || ((cell_width < 2)) ); then - xpns_log "error" "Expected pane size is too small (height: $cell_height lines, width: $cell_width chars)" - return ${XP_ESMLPANE:-7} - fi - printf "%s\\n" "${_cols} ${_rows} ${_all_cols[*]}" -} - -xpns_check_cell_size() { - local _cell_num="$1" - shift - local _cols="$1" - shift - local _rows="$1" - shift - local _win_height="$1" - shift - local _win_width="$1" - shift - local _ignore_flag="$1" - shift - local _all_cols_num= - local _all_rows=() - - if [[ -n "${_cols-}" ]] && [[ -n "${_rows-}" ]]; then - xpns_log "warning" "Both col size and row size are provided. Col size is preferentially going to be applied." - fi - ## if col is only defined - if [[ -n "${_cols-}" ]]; then - read -r _cols _rows < <(xpns_adjust_col_row "${_cols-}" 0 "${_cell_num}") - IFS=" " read -r -a _all_rows <<< "$(xpns_divide_equally "${_cell_num}" "${_cols}")" - _all_cols_num="$(xpns_nums_transpose "${_all_rows[@]}")" - - ## if row is only defined - elif [[ -n "${_rows-}" ]]; then - read -r _cols _rows < <(xpns_adjust_col_row 0 "${_rows-}" "${_cell_num}") - _all_cols_num="$(xpns_divide_equally "${_cell_num}" "${_rows}")" - - ## if both are undefined - else - read -r _cols _rows < <(xpns_adjust_col_row 0 0 "${_cell_num}") - _all_cols_num="$(xpns_divide_equally "${_cell_num}" "${_rows}")" - fi - - local cell_height=$(((_win_height - _rows + 1) / _rows)) - local cell_width=$(((_win_width - _cols + 1) / _cols)) - - ## Display basic information - xpns_log "debug" "Window: { Height: $_win_height, Width: $_win_width }" - xpns_log "debug" "Cell: { Height: $cell_height, Width: $cell_width }" - xpns_log "debug" "# Of Panes: ${_cell_num}" - xpns_log "debug" " | Row[0] --...--> Row[MAX]" - xpns_log "debug" " -----+------------------------..." - xpns_log "debug" " Col[]| ${_all_cols_num}" - xpns_log "debug" " -----+------------------------..." - - if [[ "$_ignore_flag" -ne 1 ]] && ( ((cell_height < 2)) || ((cell_width < 2)) ); then - xpns_log "error" "Expected pane size is too small (height: $cell_height lines, width: $cell_width chars)" - return "${XP_ESMLPANE:-7}" - fi - printf "%s\\n" "${_cols} ${_rows} ${_all_cols_num}" -} - -# Execute from Normal mode1 -xpns_pre_execution() { - local _opts4args="" - local _args4args="" - - if [[ ${XP_OPT_EXTRA} -eq 1 ]]; then - xpns_log "error" "'-x' must be used on the running tmux session." - exit ${XP_EINVAL} - fi - if [[ ${XP_OPT_REUSE} -eq 1 ]]; then - xpns_log "error" "'-r' must be used on the running tmux session." - exit ${XP_EINVAL} - fi - - # Run as best effort. - # Because after the tmux session is created, cols and rows would be provided by tmux. - IFS=" " read -r XP_WINDOW_HEIGHT XP_WINDOW_WIDTH < <(xpns_get_window_height_width) && { - local _arg_num="${#XP_ARGS[@]}" - local _cell_num _tmp_col_row_cols _tmp_cols - if [[ -n "$XP_MAX_PANE_ARGS" ]] && ((XP_MAX_PANE_ARGS > 1)); then - _cell_num=$((_arg_num / XP_MAX_PANE_ARGS)) - else - _cell_num="${_arg_num}" - fi - if [[ -n "${XP_OPT_BULK_COLS}" ]]; then - _tmp_col_row_cols="$(xpns_check_cell_size_bulk \ - "${_cell_num}" \ - "${XP_OPT_BULK_COLS}" \ - "${XP_WINDOW_HEIGHT}" \ - "${XP_WINDOW_WIDTH}" \ - "${XP_OPT_IGNORE_SIZE_LIMIT:-0}")" - local _exit_status="$?" - [[ $_exit_status -eq ${XP_ELAYOUT} ]] && exit ${XP_ELAYOUT} - [[ $_exit_status -eq ${XP_ESMLPANE} ]] && exit ${XP_ESMLPANE} - else - _tmp_col_row_cols="$(xpns_check_cell_size \ - "${_cell_num}" \ - "${XP_OPT_CUSTOM_SIZE_COLS-}" \ - "${XP_OPT_CUSTOM_SIZE_ROWS-}" \ - "${XP_WINDOW_HEIGHT}" \ - "${XP_WINDOW_WIDTH}" \ - "${XP_OPT_IGNORE_SIZE_LIMIT:-0}")" - [[ $? -eq ${XP_ESMLPANE} ]] && exit ${XP_ESMLPANE} - fi - - IFS=" " read -r XP_OPT_CUSTOM_SIZE_COLS XP_OPT_CUSTOM_SIZE_ROWS _tmp_cols <<< "$_tmp_col_row_cols" - IFS=" " read -r -a XP_COLS <<< "${_tmp_cols}" - IFS=" " read -r -a XP_COLS_OFFSETS <<< "$(printf "%s\\n" "${XP_COLS[*]}" | xpns_nums_accumulate_sum)" - xpns_log "debug" "Options: $(xpns_arr2args "${XP_OPTIONS[@]}")" - xpns_log "debug" "Arguments: $(xpns_arr2args "${XP_ARGS[@]}")" - } - - # Append -- flag. - # Because any arguments may have `-` - if [[ ${XP_NO_OPT} -eq 1 ]]; then - XP_ARGS=("--" "${XP_ARGS[@]}") - fi - - # If there is any options, escape them. - if [[ -n "${XP_OPTIONS[*]-}" ]]; then - _opts4args=$(xpns_arr2args "${XP_OPTIONS[@]}") - fi - _args4args=$(xpns_arr2args "${XP_ARGS[@]}") - - # Run as best effort - xpns_clean_session || true - - # Create new session. - ${TMUX_XPANES_EXEC} -S "${XP_SOCKET_PATH}" new-session \ - -s "${XP_SESSION_NAME}" \ - -n "${XP_TMP_WIN_NAME}" \ - -d "${XP_ABS_THIS_FILE_NAME} ${_opts4args} ${_args4args}" - - # Avoid attaching (for unit testing). - if [[ ${XP_OPT_ATTACH} -eq 1 ]]; then - if ! ${TMUX_XPANES_EXEC} -S "${XP_SOCKET_PATH}" attach-session -t "${XP_SESSION_NAME}" && - [[ ${XP_IS_PIPE_MODE} -eq 1 ]]; then - ## In recovery case, overwrite trap to keep socket file - trap 'rm -f "${XP_CACHE_HOME}"/__xpns_*$$;' EXIT - - xpns_log "info" "Recovery" \ - "Execute below command line to re-attach the new session. - -${TMUX_XPANES_EXEC} -S ${XP_SOCKET_PATH} attach-session -t ${XP_SESSION_NAME} - -" - exit ${XP_ETTY} - fi - fi -} - -# Execute from inside of tmux session -xpns_execution() { - local _pane_base_index= - local _window_name= - local _last_args_idx= - local _def_allow_rename= - local _pane_count=0 - - if [[ ${XP_IS_PIPE_MODE} -eq 0 ]] && [[ -n "${XP_MAX_PANE_ARGS-}" ]]; then - xpns_merge_array_elements "${XP_MAX_PANE_ARGS}" 'XP_ARGS' - fi - - ## Fix window size and define pane size - { - local _tmp_col_row_cols _tmp_cols - IFS=" " read -r XP_WINDOW_HEIGHT XP_WINDOW_WIDTH < <( - ${TMUX_XPANES_EXEC} display-message -p '#{window_height} #{window_width}' - ) - if [[ -n "${XP_OPT_BULK_COLS}" ]]; then - _tmp_col_row_cols="$(xpns_check_cell_size_bulk \ - "${#XP_ARGS[@]}" \ - "${XP_OPT_BULK_COLS}" \ - "${XP_WINDOW_HEIGHT}" \ - "${XP_WINDOW_WIDTH}" \ - "${XP_OPT_IGNORE_SIZE_LIMIT:-0}")" - local _exit_status="$?" - [[ $_exit_status -eq ${XP_ELAYOUT} ]] && exit ${XP_ELAYOUT} - [[ $_exit_status -eq ${XP_ESMLPANE} ]] && exit ${XP_ESMLPANE} - else - _tmp_col_row_cols="$(xpns_check_cell_size \ - "${#XP_ARGS[@]}" \ - "${XP_OPT_CUSTOM_SIZE_COLS-}" \ - "${XP_OPT_CUSTOM_SIZE_ROWS-}" \ - "${XP_WINDOW_HEIGHT}" \ - "${XP_WINDOW_WIDTH}" \ - "${XP_OPT_IGNORE_SIZE_LIMIT:-0}")" - [[ $? -eq ${XP_ESMLPANE} ]] && exit ${XP_ESMLPANE} - fi - IFS=" " read -r XP_OPT_CUSTOM_SIZE_COLS XP_OPT_CUSTOM_SIZE_ROWS _tmp_cols <<< "$_tmp_col_row_cols" - IFS=" " read -r -a XP_COLS <<< "${_tmp_cols}" - IFS=" " read -r -a XP_COLS_OFFSETS <<< "$(printf "%s\\n" "${XP_COLS[*]}" | xpns_nums_accumulate_sum)" - xpns_log "debug" "Options: $(xpns_arr2args "${XP_OPTIONS[@]}")" - xpns_log "debug" "Arguments: $(xpns_arr2args "${XP_ARGS[@]}")" - } - - _pane_base_index=$(xpns_get_global_tmux_conf 'pane-base-index') - _last_args_idx=$((${#XP_ARGS[@]} - 1)) - _def_allow_rename="$(xpns_get_global_tmux_conf 'allow-rename')" - - xpns_suppress_allow_rename "${_def_allow_rename-}" - XP_CMD_UTILITY="$(xpns_get_joined_begin_commands "${XP_CMD_UTILITY}")" - - if [[ ${XP_OPT_REUSE} -eq 1 ]]; then - _window_name="$( ${TMUX_XPANES_EXEC} display -p -F "#{window_id}")" - _pane_count="$( ${TMUX_XPANES_EXEC} list-panes | grep -c .)" - _pane_base_index=$(($(${TMUX_XPANES_EXEC} display -p -F "#{pane_index}") + 1)) - _pane_active_pane_id=$(${TMUX_XPANES_EXEC} display -p -F "#{pane_id}") - - # Reusing the panes: if there's only 1 pane, behave like -x otherwise - # make sure there are enough panes of higher index than the current one. - # This allows to run -r to create the panes and then repeatedly to reuse - # those panes. - if [[ $((_pane_count - _pane_base_index)) -lt ${#XP_ARGS[@]} ]]; then - xpns_log "error" "Not enough panes ($((_pane_count - 1))) after this one to run the ${#XP_ARGS[@]} commands." - exit ${XP_EINVAL} - fi - fi - if [[ ${XP_OPT_EXTRA} -eq 1 ]]; then - # Reuse existing window name - # tmux 1.6 does not support -F option - _window_name="$( ${TMUX_XPANES_EXEC} display -p -F "#{window_id}")" - _pane_count="$( ${TMUX_XPANES_EXEC} list-panes | grep -c .)" - _pane_base_index=$((_pane_base_index + _pane_count - 1)) - _pane_active_pane_id=$(${TMUX_XPANES_EXEC} display -p -F "#{pane_id}") - elif [[ ${XP_OPT_REUSE} -eq 0 ]]; then - _window_name=$( - xpns_generate_window_name \ - "${XP_EMPTY_STR}" \ - "${XP_ARGS[0]}" | - xpns_value2key - ) - fi - - ## -------------------- - # Prepare window and panes - ## -------------------- - if [[ ${XP_OPT_REUSE} -eq 0 ]]; then - if [[ ${XP_OPT_EXTRA} -eq 1 ]]; then - xpns_prepare_extra_panes \ - "${_window_name}" \ - "${_pane_base_index}" \ - "${XP_OPT_LOG_STORE}" \ - "${XP_OPT_SET_TITLE}" \ - "${XP_OPT_SPEEDY}" \ - "${XP_OPT_SPEEDY_AWAIT}" \ - "${XP_OPT_INTERVAL}" \ - "${XP_REPSTR}" \ - "${XP_CMD_UTILITY}" \ - "${XP_ARGS[@]}" - elif [[ ${XP_OPT_USE_PRESET_LAYOUT} -eq 1 ]]; then - xpns_prepare_preset_layout_window \ - "${_window_name}" \ - "${_pane_base_index}" \ - "${XP_OPT_LOG_STORE}" \ - "${XP_OPT_SET_TITLE}" \ - "${XP_OPT_ATTACH}" \ - "${XP_OPT_SPEEDY}" \ - "${XP_OPT_SPEEDY_AWAIT}" \ - "${XP_OPT_INTERVAL}" \ - "${XP_REPSTR}" \ - "${XP_CMD_UTILITY}" \ - "${XP_ARGS[@]}" - elif [[ ${XP_OPT_USE_PRESET_LAYOUT} -eq 0 ]]; then - xpns_prepare_window \ - "${_window_name}" \ - "${XP_OPT_LOG_STORE}" \ - "${XP_OPT_SET_TITLE}" \ - "${XP_OPT_ATTACH}" \ - "${XP_OPT_SPEEDY}" \ - "${XP_OPT_SPEEDY_AWAIT}" \ - "${XP_OPT_INTERVAL}" \ - "${XP_REPSTR}" \ - "${XP_CMD_UTILITY}" \ - "${XP_ARGS[@]}" - fi - fi - - ## With -ss option, it is possible to close all the panes as of here. - ## Check status of the window. If no window exists, there is nothing to do any more and just exit. - xpns_log "debug" "xpns_is_window_alive:1: After window separation" - xpns_is_window_alive "${_window_name}" "${XP_OPT_SPEEDY_AWAIT}" "${_def_allow_rename-}" - - if [[ ${XP_OPT_EXTRA} -eq 1 ]]; then - # Set offset to avoid sending command to the original pane. - _pane_base_index=$((_pane_base_index + 1)) - # Avoid to make layout even-horizontal even if there are many panes. - # in xpns_organize_panes - _last_args_idx=$((_last_args_idx + _pane_count)) - # Re-select the windown that was active before. - ${TMUX_XPANES_EXEC} select-pane -t "${_window_name}.${_pane_active_pane_id}" - fi - - if [[ ${XP_OPT_LOG_STORE} -eq 1 ]]; then - xpns_enable_logging \ - "${_window_name}" \ - "${_pane_base_index}" \ - "${TMUX_XPANES_LOG_DIRECTORY}" \ - "${TMUX_XPANES_LOG_FORMAT}" \ - "${XP_EMPTY_STR}" \ - "${XP_ARGS[@]}" - - if [[ $XP_OPT_SPEEDY -eq 1 ]]; then - xpns_notify_logging \ - "${_window_name}" \ - "${XP_ARGS[@]}" - fi - fi - - xpns_log "debug" "xpns_is_window_alive:2: After logging" - xpns_is_window_alive "${_window_name}" "${XP_OPT_SPEEDY_AWAIT}" "${_def_allow_rename-}" - - # Set pane titles for each pane. - if xpns_is_pane_title_required "${XP_OPT_SET_TITLE}" "${XP_OPT_EXTRA}"; then - xpns_set_titles \ - "${_window_name}" \ - "${_pane_base_index}" \ - "${XP_ARGS[@]}" - fi - - if [[ $XP_OPT_SPEEDY -eq 1 ]]; then - xpns_notify_sync \ - "${_window_name}" \ - "${XP_OPT_INTERVAL}" \ - "${XP_ARGS[@]}" - fi - - xpns_log "debug" "xpns_is_window_alive:3: After setting title" - xpns_is_window_alive "${_window_name}" "${XP_OPT_SPEEDY_AWAIT}" "${_def_allow_rename-}" - - # Sending operations for each pane. - # With -s option, command is already sent. - if [[ $XP_OPT_SPEEDY -eq 0 ]]; then - xpns_send_commands \ - "${_window_name}" \ - "${_pane_base_index}" \ - "${XP_OPT_INTERVAL}" \ - "${XP_REPSTR}" \ - "${XP_CMD_UTILITY}" \ - "${XP_ARGS[@]}" - fi - - xpns_log "debug" "xpns_is_window_alive:4: After sending commands" - xpns_is_window_alive "${_window_name}" "${XP_OPT_SPEEDY_AWAIT}" "${_def_allow_rename-}" - - ## With -l <layout>, panes are organized. - ## As well as -x, they are re-organized. - if [[ (${XP_OPT_USE_PRESET_LAYOUT} -eq 1 || ${XP_OPT_EXTRA} -eq 1) && ${XP_OPT_REUSE} -eq 0 ]]; then - xpns_organize_panes \ - "${_window_name}" \ - "${_last_args_idx}" - fi - - # Enable broadcasting - if [[ ${XP_OPT_IS_SYNC} -eq 1 ]] && [[ ${XP_OPT_EXTRA} -eq 0 ]]; then - ${TMUX_XPANES_EXEC} \ - set-window-option -t "${_window_name}" \ - synchronize-panes on - fi - - ## In case of -t option - if [[ ${XP_OPT_SET_TITLE} -eq 1 ]] && [[ ${XP_OPT_CHANGE_BORDER} -eq 1 ]]; then - # Set border format - ${TMUX_XPANES_EXEC} \ - set-window-option -t "${_window_name}" \ - pane-border-format "${TMUX_XPANES_PANE_BORDER_FORMAT}" - # Show border status - ${TMUX_XPANES_EXEC} \ - set-window-option -t "${_window_name}" \ - pane-border-status "${TMUX_XPANES_PANE_BORDER_STATUS}" - fi - - # In case of -x or -r, this statement is skipped to keep the original window name - if [[ ${XP_OPT_EXTRA} -eq 0 ]] && [[ ${XP_OPT_REUSE} -eq 0 ]]; then - # Restore original window name. - ${TMUX_XPANES_EXEC} \ - rename-window -t "${_window_name}" \ - -- "$(printf "%s\\n" "${_window_name}" | xpns_key2value)" - fi - - xpns_restore_allow_rename "${_def_allow_rename-}" -} - -## ---------------- -# Arrange options for pipe mode -# * argument -> command -# * stdin -> argument -## ---------------- -xpns_switch_pipe_mode() { - local _pane_num4new_term="" - if [[ -n "${XP_ARGS[*]-}" ]] && [[ -n "${XP_CMD_UTILITY-}" ]]; then - xpns_log "error" "Both arguments and other options (like '-c', '-e') which updates <command> are given." - exit ${XP_EINVAL} - fi - - if [[ -z "${TMUX-}" ]]; then - xpns_log "warning" "Attached session is required for 'Pipe mode'." - # This condition is used when the following situations. - # * Enter from outside of tmux session(Normal mode1) - # * Pipe mode. - # * -n option. - # - # For example: - # (Normal mode1)$ echo {a..g} | ./xpanes -n 2 - # => This will once create the new window like this. - # (inside of tmux session)$ ./xpanes '-n' '2' 'a' 'b' 'c' 'd' 'e' 'f' 'g' - # => After the window is closed, following panes would be left. - # (pane 1)$ echo a b - # (pane 2)$ echo c d - # (pane 3)$ echo e f - # (pane 4)$ echo g - # In order to create such the query, - # separate all the argument into minimum tokens - # with xargs -n 1 - if [[ -n "${XP_MAX_PANE_ARGS-}" ]]; then - _pane_num4new_term=1 - fi - fi - - while read -r line; do - XP_STDIN+=("${line}") - done < <(cat | xpns_rm_empty_line | - xpns_pipe_filter "${_pane_num4new_term:-${XP_MAX_PANE_ARGS}}") - - # Merge them into command. - if [[ -n "${XP_ARGS[*]-}" ]]; then - # Attention: It might be wrong result if IFS is changed. - XP_CMD_UTILITY="${XP_ARGS[*]}" - fi - - # If there is empty -I option or user does not assign the <repstr>, - # Append the space and <repstr> at the end of the <command> - # This is same as the xargs command of GNU. - # i.e, - # $ echo 10 | xargs seq - # => seq 10 - # Whith is same as - # $ echo 10 | xargs -I@ seq @ - # => seq 10 - if [[ -z "${XP_REPSTR}" ]]; then - XP_REPSTR="${XP_DEFAULT_REPSTR}" - if [[ -n "${XP_ARGS[*]-}" ]]; then - XP_CMD_UTILITY="${XP_ARGS[*]-} ${XP_REPSTR}" - fi - fi - - # Deal with stdin as arguments. - XP_ARGS=("${XP_STDIN[@]-}") -} - -xpns_layout_short2long() { - sed \ - -e 's/^t$/tiled/' \ - -e 's/^eh$/even-horizontal/' \ - -e 's/^ev$/even-vertical/' \ - -e 's/^mh$/main-horizontal/' \ - -e 's/^mv$/main-vertical/' \ - -e ';' -} - -xpns_is_valid_layout() { - local _layout="${1-}" - local _pat='^(tiled|even-horizontal|even-vertical|main-horizontal|main-vertical)$' - if ! [[ $_layout =~ $_pat ]]; then - xpns_log "error" "Invalid layout '${_layout}'." - exit ${XP_ELAYOUT} - fi -} - -xpns_warning_before_extra() { - local _ans= - local _synchronized= - _synchronized="$(xpns_get_local_tmux_conf "synchronize-panes")" - if [[ "on" == "${_synchronized}" ]]; then - xpns_log "warning" "Panes are now synchronized. -'-x' option may cause unexpected behavior on the synchronized panes." - printf "Are you really sure? [y/n]: " - read -r _ans - if ! [[ "${_ans-}" =~ ^[yY] ]]; then - return 1 - fi - fi -} -xpns_opt_checker() { - local _option="$1" - local _arg="$2" - local _check_value="${3:-default}" - # if we do not define a positional parameter in options, we expect an integer - local _pattern="^[0-9]+$" - if [[ "$_check_value" == "float" ]]; then - _pattern="^[0-9]*\.?[0-9]*$" - elif [[ "$_check_value" == "csv" ]]; then - _pattern="^[0-9]+(,[0-9]+)*$" - elif [[ "$_check_value" == "string" ]]; then - if [[ -n "$_arg" ]]; then - return 0 - fi - fi - if [[ -n "$_arg" ]] && [[ "$_arg" =~ $_pattern ]]; then - return 0 - fi - xpns_log "error" "Invalid argument '$_arg' for $_option option" - exit ${XP_EINVAL} -} - -xpns_parse_options() { - while (($# > 0)); do - opt="$1" - shift - if [[ ${XP_NO_OPT} -eq 1 ]]; then - XP_ARGS+=("$opt") - continue - fi - - ## Skip regularization if the arg is empty or --log= option - if [[ -n "$opt" ]] && [[ -n "${opt##--log=*}" ]]; then - # shellcheck disable=SC2295 - ## -ovalue → -o value - if [[ -z "${opt##-${XP_ARG_OPTIONS}?*}" ]]; then - set -- "${opt#??}" ${1+"$@"} - opt="${opt%$1}" - ## -abc → -a -bc - elif [[ -z "${opt##-[!-]?*}" ]]; then - set -- "-${opt#??}" ${1+"$@"} - opt="${opt%${1#-}}" - ## --option=value → --option value - elif [[ -z "${opt##--*=*}" ]]; then - set -- "${opt#--*=}" ${1+"$@"} - opt="${opt%%=*}" - fi - fi - - case "$opt" in - --) - # Disable any more options - XP_NO_OPT=1 - ;; - ## ---------------- - # Long options - ## ---------------- - --help) - xpns_usage - exit 0 - ;; - --version) - xpns_version - exit 0 - ;; - --desync) - XP_OPTIONS+=("$opt") - XP_OPT_IS_SYNC=0 - ;; - --log-format) - xpns_opt_checker "$opt" "$1" "string" - XP_OPTIONS+=("$opt") - XP_OPT_LOG_STORE=1 - TMUX_XPANES_LOG_FORMAT="$1" - XP_OPTIONS+=("$1") - shift - ;; - --log=*) - XP_OPT_LOG_STORE=1 - XP_OPTIONS+=("$opt") - TMUX_XPANES_LOG_DIRECTORY="${opt#--log=}" - xpns_opt_checker "${opt%=}" "$TMUX_XPANES_LOG_DIRECTORY" "string" - ;; - --log) - XP_OPT_LOG_STORE=1 - XP_OPTIONS+=("$opt") - ;; - --ssh) - XP_OPTIONS+=("$opt") - XP_CMD_UTILITY="${XP_SSH_CMD_UTILITY}" - # Enable -t option - XP_OPT_SET_TITLE=1 - XP_OPT_CHANGE_BORDER=1 - # Enable -s option - XP_OPT_SPEEDY=1 - XP_OPT_SPEEDY_AWAIT=1 - ;; - --stay) - XP_OPTIONS+=("$opt") - XP_OPT_ATTACH=0 - ;; - --cols) - xpns_opt_checker "$opt" "$1" - XP_OPTIONS+=("$opt") - XP_OPT_CUSTOM_SIZE_COLS="$1" - XP_OPTIONS+=("$1") - shift - ;; - --rows) - xpns_opt_checker "$opt" "$1" - XP_OPTIONS+=("$opt") - XP_OPT_CUSTOM_SIZE_ROWS="$1" - XP_OPTIONS+=("$1") - shift - ;; - --bulk-cols) - xpns_opt_checker "$opt" "$1" "csv" - XP_OPTIONS+=("$opt") - XP_OPT_BULK_COLS="$1" - XP_OPTIONS+=("$1") - shift - ;; - --interval) - xpns_opt_checker "$opt" "$1" "float" - XP_OPTIONS+=("$opt") - XP_OPT_INTERVAL="$1" - XP_OPTIONS+=("$1") - shift - ;; - --debug) - XP_OPTIONS+=("$opt") - XP_OPT_DEBUG=1 - ;; - --dry-run) - XP_OPTIONS+=("$opt") - XP_OPT_DRY_RUN=1 - ;; - --ignore-size-limit) # Hidden for testing - XP_OPTIONS+=("$opt") - XP_OPT_IGNORE_SIZE_LIMIT=1 - ;; - ## ---------------- - # Short options without argument - ## ---------------- - -h) - xpns_usage - exit 0 - ;; - -V) - xpns_version - exit 0 - ;; - -x) - # If you modify those, make similar changes to -r - XP_OPTIONS+=("$opt") - XP_OPT_EXTRA=1 - XP_OPT_USE_PRESET_LAYOUT=1 ## Layout presets must be used with -x - if ! xpns_warning_before_extra; then - exit ${XP_EINTENT} - fi - ;; - -d) - XP_OPTIONS+=("$opt") - XP_OPT_IS_SYNC=0 - ;; - -e) - XP_OPTIONS+=("$opt") - XP_REPSTR="{}" - XP_CMD_UTILITY="{}" - ;; - -t) - XP_OPTIONS+=("$opt") - if ( xpns_tmux_is_greater_equals 2.3 ); then - XP_OPT_SET_TITLE=1 - XP_OPT_CHANGE_BORDER=1 - else - xpns_log "warning" "-t option cannot be used by tmux version less than 2.3. Disabled." - sleep 1 - fi - ;; - -r) - XP_OPTIONS+=("$opt") - # Reusing the panes: if there's only 1 pane, behave like -x - # This allows to run -r to create the panes and then repeatedly to reuse - # those panes. - _pane_count="$( ${TMUX_XPANES_EXEC} list-panes | grep -c .)" - if [[ ${_pane_count} -eq 1 ]]; then - XP_OPT_EXTRA=1 - XP_OPT_USE_PRESET_LAYOUT=1 ## Layout presets must be used with -x - if ! xpns_warning_before_extra; then - exit ${XP_EINTENT} - fi - else - XP_OPT_REUSE=1 - XP_OPT_EXTRA=0 - XP_OPT_IS_SYNC=0 - fi - ;; - -s) - XP_OPTIONS+=("$opt") - XP_OPT_SPEEDY=1 - XP_OPT_SPEEDY_AWAIT=1 - if [[ -z "${1#-s}" ]]; then - XP_OPT_SPEEDY_AWAIT=0 - XP_OPTIONS+=("$1") - shift - fi - ;; - ## ---------------- - # Short options with argument - ## ---------------- - -I) - xpns_opt_checker "$opt" "$1" "string" - XP_OPTIONS+=("$opt") - XP_REPSTR="$1" - XP_OPTIONS+=("$1") - shift - ;; - -l) - xpns_opt_checker "$opt" "$1" "string" - XP_OPTIONS+=("$opt") - XP_OPT_USE_PRESET_LAYOUT=1 - XP_LAYOUT="$(printf '%s\n' "$1" | xpns_layout_short2long)" - xpns_is_valid_layout "${XP_LAYOUT}" - XP_OPTIONS+=("$1") - shift - ;; - -c) - # -c allows empty - XP_OPTIONS+=("$opt") - XP_CMD_UTILITY="$1" - XP_OPT_CMD_UTILITY=1 - XP_OPTIONS+=("$1") - shift - ;; - -n) - xpns_opt_checker "$opt" "$1" - XP_OPTIONS+=("$opt") - XP_MAX_PANE_ARGS="$1" - XP_OPTIONS+=("$1") - shift - ;; - -S) - xpns_opt_checker "$opt" "$1" "string" - XP_OPTIONS+=("$opt") - XP_SOCKET_PATH="$1" - XP_OPTIONS+=("$1") - shift - ;; - -C) - xpns_opt_checker "$opt" "$1" - XP_OPTIONS+=("$opt") - XP_OPT_CUSTOM_SIZE_COLS="$1" - XP_OPTIONS+=("$1") - shift - ;; - -R) - xpns_opt_checker "$opt" "$1" - XP_OPTIONS+=("$opt") - XP_OPT_CUSTOM_SIZE_ROWS="$1" - XP_OPTIONS+=("$1") - shift - ;; - -B) - # -B allows empty - XP_OPTIONS+=("$opt") - XP_BEGIN_ARGS+=("$1") - XP_OPTIONS+=("$1") - shift - ;; - -*) - xpns_log "error" "Invalid option -- '${opt}'" - xpns_usage_warn - exit ${XP_EINVAL} - ;; - ## ---------------- - # Other arguments - ## ---------------- - *) - XP_ARGS+=("$opt") - XP_NO_OPT=1 - ;; - esac - done - # If there is any standard input from pipe, - # 1 line handled as 1 argument. - if [[ ! -t 0 ]]; then - XP_IS_PIPE_MODE=1 - xpns_switch_pipe_mode - fi - - # When no argument is given, exit. - if [[ -z "${XP_ARGS[*]-}" ]]; then - xpns_log "error" "No arguments." - xpns_usage_warn - exit ${XP_EINVAL} - fi - - if [[ -n "${XP_OPT_CUSTOM_SIZE_COLS-}" ]] || [[ -n "${XP_OPT_CUSTOM_SIZE_ROWS-}" ]]; then - if [[ "$XP_OPT_EXTRA" -eq 1 ]]; then - xpns_log "warning" "The columns/rows options (-C, --cols, -R, --rows) cannot be used with -x option. Ignored." - elif [[ "$XP_OPT_EXTRA" -eq 0 ]] && [[ "${XP_OPT_USE_PRESET_LAYOUT}" -eq 1 ]]; then - # This part is required to keep backward compatibility. - ## Users can simulate xpanes v3.x to set : alias xpanes="xpanes -lt" - xpns_log "info" "Columns/rows option (-C, --cols, -R, --rows) and -l option are provided. Disable -l. " - XP_OPT_USE_PRESET_LAYOUT=0 - fi - fi - - # Set default value in case of empty. - XP_CMD_UTILITY="${XP_CMD_UTILITY:-${XP_DEFAULT_CMD_UTILITY}}" - XP_REPSTR="${XP_REPSTR:-${XP_DEFAULT_REPSTR}}" - - # To set command on pre_execution, set -c option manually. - if [[ ${XP_OPT_CMD_UTILITY} -eq 0 ]]; then - XP_OPTIONS+=("-c" "${XP_CMD_UTILITY}") - fi -} - -## -------------------------------- -# Main function -## -------------------------------- -xpns_main() { - xpns_parse_options ${1+"$@"} - xpns_check_env "${XP_DEPENDENCIES}" - ## -------------------------------- - # Parameter validation - ## -------------------------------- - # When do dry-run flag is enabled, skip running (this is used to execute unit test of itself). - if [[ ${XP_OPT_DRY_RUN} -eq 1 ]]; then - return 0 - fi - # Validate log directory. - if [[ ${XP_OPT_LOG_STORE} -eq 1 ]]; then - TMUX_XPANES_LOG_DIRECTORY=$(xpns_normalize_directory "${TMUX_XPANES_LOG_DIRECTORY}") - xpns_is_valid_directory "${TMUX_XPANES_LOG_DIRECTORY}" && - TMUX_XPANES_LOG_DIRECTORY=$(cd "${TMUX_XPANES_LOG_DIRECTORY}" && pwd) - fi - ## -------------------------------- - # If current shell is outside of tmux session. - ## -------------------------------- - if [[ -z "${TMUX-}" ]]; then - xpns_pre_execution - ## -------------------------------- - # If current shell is already inside of tmux session. - ## -------------------------------- - else - xpns_execution - fi - exit 0 -} - -## -------------------------------- -# Entry Point -## -------------------------------- -xpns_main ${1+"$@"} diff --git a/modules/mixins/dotfiles/config/lazygit/config.yml b/modules/mixins/dotfiles/config/lazygit/config.yml @@ -1,24 +0,0 @@ -gui: - theme: - activeBorderColor: - - '#94d0eb' # cursor accent (blue) - - bold - inactiveBorderColor: - - '#484040' # regular0 (dark) - searchingActiveBorderColor: - - '#c0b060' # regular3 (yellow) - - bold - optionsTextColor: - - '#9fbfe7' # regular4 (blue) - selectedLineBgColor: - - '#3d5e57' # selection-background - selectedRangeBgColor: - - '#3d5e57' # selection-background - cherryPickedCommitBgColor: - - '#a0c0d0' # regular6 (cyan) - cherryPickedCommitFgColor: - - '#383035' # background - unstagedChangesColor: - - '#eca28f' # regular1 (red/salmon) - defaultFgColor: - - '#e0d5b7' # foreground diff --git a/modules/mixins/dotfiles/config/shell/rc/aliased-short-names b/modules/mixins/dotfiles/config/shell/rc/aliased-short-names @@ -143,3 +143,5 @@ alias bakg='backup -t git' alias bakm='backup -t mobius' alias chav='cha --visual' + +alias pwc='pwd | wl-copy' diff --git a/modules/mixins/dotfiles/config/shell/rc/git b/modules/mixins/dotfiles/config/shell/rc/git @@ -3,7 +3,6 @@ alias cdg='cd "$(git rev-parse --show-toplevel)"' alias gst='git status' alias ng='nvim -c ":Neogit"' -alias lg='lazygit' alias gprl='git-prole' alias gprla='git-prole add' diff --git a/modules/mixins/dotfiles/config/zed/settings-nix.json b/modules/mixins/dotfiles/config/zed/settings-nix.json @@ -1,37 +0,0 @@ -{ - "agent_servers": { - "qwen-code": { - "type": "registry" - } - }, - "relative_line_numbers": "enabled", - "buffer_font_family": "Comic Code", - "telemetry": { - "diagnostics": false, - "metrics": false - }, - "title_bar": { - "show_user_picture": false, - "show_sign_in": false - }, - "toolbar": { - "breadcrumbs": false, - "quick_actions": false, - "selections_menu": false - }, - "icon_theme": "Zed (Default)", - "vim_mode": true, - "ui_font_size": 16, - "buffer_font_size": 16, - "theme": "Doric Dark", - "disable_ai": false, - "collaboration_panel": { - "button": false - }, - "chat_panel": { - "button": "never" - }, - "agent": { - "button": false - } -} diff --git a/modules/mixins/dotfiles/config/zed/themes/doris-dark.json b/modules/mixins/dotfiles/config/zed/themes/doris-dark.json @@ -1,402 +0,0 @@ -{ - "$schema": "https://zed.dev/schema/themes/v0.2.0.json", - "name": "Doric Dark", - "author": "Protesilaos Stavrou <info@protesilaos.com>", - "themes": [ - { - "name": "Doric Dark", - "appearance": "dark", - "style": { - "border": "#707070", - "border.variant": "#484040", - "border.focused": "#9fbfe7", - "border.selected": "#cda4df", - "border.transparent": "#00000000", - "border.disabled": "#43404c", - "elevated_surface.background": "#0d0d0d", - "surface.background": "#0d0d0d", - "background": "#000000", - "element.background": "#43404c", - "element.hover": "#3d5e57", - "element.active": "#521e40", - "element.selected": "#521e40", - "element.disabled": "#484040", - "drop_target.background": "#3d5e5755", - "ghost_element.background": "#00000000", - "ghost_element.hover": "#484040", - "ghost_element.active": "#43404c", - "ghost_element.selected": "#3d5e57", - "ghost_element.disabled": "#484040", - "text": "#ffffff", - "text.muted": "#a2a0b2", - "text.placeholder": "#707070", - "text.disabled": "#707070", - "text.accent": "#cda4df", - "icon": "#c5c7d4", - "icon.muted": "#a2a0b2", - "icon.disabled": "#707070", - "icon.placeholder": "#707070", - "icon.accent": "#cda4df", - "status_bar.background": "#0d0d0d", - "title_bar.background": "#000000", - "title_bar.inactive_background": "#0d0d0d", - "toolbar.background": "#000000", - "tab_bar.background": "#0d0d0d", - "tab.inactive_background": "#0d0d0d", - "tab.active_background": "#000000", - "search.match_background": "#3d5e57", - "panel.background": "#0d0d0d", - "panel.focused_border": "#9fbfe7", - "pane.focused_border": "#9fbfe7", - "pane.group_border": "#707070", - "scrollbar.thumb.background": "#43404c99", - "scrollbar.thumb.hover_background": "#a2a0b2", - "scrollbar.thumb.border": "#43404c", - "scrollbar.track.background": "#00000000", - "scrollbar.track.border": "#484040", - "editor.foreground": "#ffffff", - "editor.background": "#000000", - "editor.gutter.background": "#000000", - "editor.subheader.background": "#0d0d0d", - "editor.active_line.background": "#0d0b0e", - "editor.highlighted_line.background": "#48404055", - "editor.line_number": "#707070", - "editor.active_line_number": "#c5c7d4", - "editor.invisible": "#43404c", - "editor.wrap_guide": "#484040", - "editor.active_wrap_guide": "#43404c", - "editor.indent_guide": "#484040", - "editor.indent_guide_active": "#43404c", - "editor.document_highlight.read_background": "#3d5e5744", - "editor.document_highlight.write_background": "#521e4044", - "terminal.background": "#000000", - "terminal.foreground": "#ffffff", - "terminal.bright_foreground": "#ffffff", - "terminal.dim_foreground": "#a2a0b2", - "terminal.ansi.black": "#000000", - "terminal.ansi.bright_black": "#43404c", - "terminal.ansi.white": "#c5c7d4", - "terminal.ansi.bright_white": "#ffffff", - "terminal.ansi.red": "#eca28f", - "terminal.ansi.bright_red": "#eca28f", - "terminal.ansi.green": "#b9d0aa", - "terminal.ansi.bright_green": "#b9d0aa", - "terminal.ansi.yellow": "#c0b060", - "terminal.ansi.bright_yellow": "#c0b060", - "terminal.ansi.blue": "#9fbfe7", - "terminal.ansi.bright_blue": "#9fbfe7", - "terminal.ansi.magenta": "#e9acbf", - "terminal.ansi.bright_magenta": "#cda4df", - "terminal.ansi.cyan": "#a0c0d0", - "terminal.ansi.bright_cyan": "#a0c0d0", - "link_text.hover": "#9fbfe7", - "conflict": "#c0b060", - "conflict.background": "#504432", - "conflict.border": "#c0b060", - "created": "#b9d0aa", - "created.background": "#1f402e", - "created.border": "#b9d0aa", - "deleted": "#eca28f", - "deleted.background": "#4d1f20", - "deleted.border": "#eca28f", - "error": "#eca28f", - "error.background": "#4d1f20", - "error.border": "#eca28f", - "hidden": "#a2a0b2", - "hidden.background": "#484040", - "hidden.border": "#707070", - "hint": "#a2a0b2", - "hint.background": "#484040", - "hint.border": "#43404c", - "ignored": "#707070", - "ignored.background": "#000000", - "ignored.border": "#43404c", - "info": "#9fbfe7", - "info.background": "#223567", - "info.border": "#9fbfe7", - "modified": "#c0b060", - "modified.background": "#504432", - "modified.border": "#c0b060", - "predictive": "#a2a0b2", - "predictive.background": "#484040", - "predictive.border": "#707070", - "renamed": "#cda4df", - "renamed.background": "#521e40", - "renamed.border": "#cda4df", - "success": "#b9d0aa", - "success.background": "#1f402e", - "success.border": "#b9d0aa", - "unreachable": "#707070", - "unreachable.background": "#484040", - "unreachable.border": "#43404c", - "warning": "#c0b060", - "warning.background": "#504432", - "warning.border": "#c0b060", - "players": [ - { - "cursor": "#ccaaee", - "background": "#ccaaee", - "selection": "#ccaaee33" - }, - { - "cursor": "#9fbfe7", - "background": "#9fbfe7", - "selection": "#9fbfe733" - }, - { - "cursor": "#b9d0aa", - "background": "#b9d0aa", - "selection": "#b9d0aa33" - }, - { - "cursor": "#e9acbf", - "background": "#e9acbf", - "selection": "#e9acbf33" - }, - { - "cursor": "#a0c0d0", - "background": "#a0c0d0", - "selection": "#a0c0d033" - }, - { - "cursor": "#c0b060", - "background": "#c0b060", - "selection": "#c0b06033" - }, - { - "cursor": "#cda4df", - "background": "#cda4df", - "selection": "#cda4df33" - }, - { - "cursor": "#eca28f", - "background": "#eca28f", - "selection": "#eca28f33" - } - ], - "syntax": { - "attribute": { - "color": "#cda4df", - "font_style": null, - "font_weight": null - }, - "boolean": { - "color": "#c0b060", - "font_style": null, - "font_weight": null - }, - "comment": { - "color": "#a2a0b2", - "font_style": "italic", - "font_weight": null - }, - "comment.doc": { - "color": "#cfcff8", - "font_style": "italic", - "font_weight": null - }, - "constant": { - "color": "#c0b060", - "font_style": null, - "font_weight": null - }, - "constructor": { - "color": "#a0c0d0", - "font_style": null, - "font_weight": null - }, - "embedded": { - "color": "#cfcff8", - "font_style": null, - "font_weight": null - }, - "emphasis": { - "color": "#cda4df", - "font_style": "italic", - "font_weight": null - }, - "emphasis.strong": { - "color": "#cfcff8", - "font_style": null, - "font_weight": 700 - }, - "enum": { - "color": "#c0b060", - "font_style": null, - "font_weight": null - }, - "function": { - "color": "#9fbfe7", - "font_style": null, - "font_weight": null - }, - "function.builtin": { - "color": "#a0c0d0", - "font_style": null, - "font_weight": null - }, - "function.method": { - "color": "#9fbfe7", - "font_style": null, - "font_weight": null - }, - "hint": { - "color": "#a2a0b2", - "font_style": "italic", - "font_weight": null - }, - "keyword": { - "color": "#e9acbf", - "font_style": null, - "font_weight": null - }, - "keyword.control": { - "color": "#e9acbf", - "font_style": null, - "font_weight": null - }, - "label": { - "color": "#cda4df", - "font_style": null, - "font_weight": null - }, - "link_text": { - "color": "#9fbfe7", - "font_style": "italic", - "font_weight": null - }, - "link_uri": { - "color": "#a0c0d0", - "font_style": null, - "font_weight": null - }, - "number": { - "color": "#c0b060", - "font_style": null, - "font_weight": null - }, - "operator": { - "color": "#c5c7d4", - "font_style": null, - "font_weight": null - }, - "predictive": { - "color": "#a2a0b2", - "font_style": "italic", - "font_weight": null - }, - "preproc": { - "color": "#cda4df", - "font_style": null, - "font_weight": null - }, - "primary": { - "color": "#ffffff", - "font_style": null, - "font_weight": null - }, - "property": { - "color": "#a0c0d0", - "font_style": null, - "font_weight": null - }, - "punctuation": { - "color": "#c5c7d4", - "font_style": null, - "font_weight": null - }, - "punctuation.bracket": { - "color": "#a2a0b2", - "font_style": null, - "font_weight": null - }, - "punctuation.delimiter": { - "color": "#a2a0b2", - "font_style": null, - "font_weight": null - }, - "punctuation.list_marker": { - "color": "#c0b060", - "font_style": null, - "font_weight": null - }, - "punctuation.special": { - "color": "#cda4df", - "font_style": null, - "font_weight": null - }, - "string": { - "color": "#b9d0aa", - "font_style": null, - "font_weight": null - }, - "string.escape": { - "color": "#c0b060", - "font_style": null, - "font_weight": null - }, - "string.regex": { - "color": "#a0c0d0", - "font_style": null, - "font_weight": null - }, - "string.special": { - "color": "#cda4df", - "font_style": null, - "font_weight": null - }, - "string.special.symbol": { - "color": "#cda4df", - "font_style": null, - "font_weight": null - }, - "tag": { - "color": "#9fbfe7", - "font_style": null, - "font_weight": null - }, - "text.literal": { - "color": "#b9d0aa", - "font_style": null, - "font_weight": null - }, - "title": { - "color": "#cfcff8", - "font_style": null, - "font_weight": 700 - }, - "type": { - "color": "#a0c0d0", - "font_style": null, - "font_weight": null - }, - "type.builtin": { - "color": "#9fbfe7", - "font_style": null, - "font_weight": null - }, - "variable": { - "color": "#ffffff", - "font_style": null, - "font_weight": null - }, - "variable.builtin": { - "color": "#e9acbf", - "font_style": null, - "font_weight": null - }, - "variable.special": { - "color": "#cda4df", - "font_style": null, - "font_weight": null - }, - "variant": { - "color": "#a0c0d0", - "font_style": null, - "font_weight": null - } - } - } - } - ] -} diff --git a/modules/mixins/dotfiles/config/zsh/plugins/zsh-autopair/.editorconfig b/modules/mixins/dotfiles/config/zsh/plugins/zsh-autopair/.editorconfig @@ -1,10 +0,0 @@ -[*] -charset = utf-8 -end_of_line = lf -insert_final_newline = true -trim_trailing_whitespace = true -indent_style = space -indent_size = 4 - -[*.md] -indent_style = space diff --git a/modules/mixins/dotfiles/config/zsh/plugins/zsh-autopair/.travis.yml b/modules/mixins/dotfiles/config/zsh/plugins/zsh-autopair/.travis.yml @@ -1,35 +0,0 @@ -dist: trusty -sudo: required - -language: generic - -env: - - ZSH_VERSION=5.3.1 URL=https://downloads.sourceforge.net/project/zsh/zsh/5.3.1/zsh-5.3.1.tar.xz - - ZSH_VERSION=5.2 URL=https://downloads.sourceforge.net/project/zsh/zsh/5.2/zsh-5.2.tar.xz - - ZSH_VERSION=5.1.1 URL=https://downloads.sourceforge.net/project/zsh/zsh/5.1.1/zsh-5.1.1.tar.xz - - ZSH_VERSION=5.0.8 URL=https://downloads.sourceforge.net/project/zsh/zsh/5.0.8/zsh-5.0.8.tar.gz - -addons: - apt: - packages: - - build-essential - -before_install: - - export LOCAL="$(mktemp --directory --tmpdir=${TMPDIR:/tmp} local.bin.XXXXXX)" - - wget $URL - - tar -xf zsh-$ZSH_VERSION.tar.* - - cd zsh-$ZSH_VERSION - - ./configure --prefix=$LOCAL - - make - - make install - - cd - - - export PATH="$LOCAL/bin:$HOME/bin:$PATH" - -before_script: - - mkdir -p ~/bin - - curl -L https://github.com/zunit-zsh/zunit/releases/download/v0.8.1/zunit > ~/bin/zunit - - curl -L https://raw.githubusercontent.com/molovo/revolver/master/revolver > ~/bin/revolver - - chmod u+x ~/bin/{revolver,zunit} - -script: - - zunit --verbose diff --git a/modules/mixins/dotfiles/config/zsh/plugins/zsh-autopair/.zunit.yml b/modules/mixins/dotfiles/config/zsh/plugins/zsh-autopair/.zunit.yml @@ -1,8 +0,0 @@ -tap: false -directories: - tests: tests - output: tests/_output - support: tests/_support -time_limit: 0 -fail_fast: false -allow_risky: false diff --git a/modules/mixins/dotfiles/config/zsh/plugins/zsh-autopair/LICENSE b/modules/mixins/dotfiles/config/zsh/plugins/zsh-autopair/LICENSE @@ -1,22 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2016-24 Henrik Lissner. - -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. diff --git a/modules/mixins/dotfiles/config/zsh/plugins/zsh-autopair/README.md b/modules/mixins/dotfiles/config/zsh/plugins/zsh-autopair/README.md @@ -1,249 +0,0 @@ -[](https://github.com/hlissner/doom-emacs) -[](./LICENSE) - -[](https://travis-ci.org/hlissner/zsh-autopair) - -# zsh-autopair -A simple plugin that auto-closes, deletes and skips over matching delimiters in -zsh intelligently. Hopefully. - -> NOTE: zsh-autopair is untested for versions of Zsh below 5.0.2. Please report -> any issues you have in earlier versions! - -Specifically, zsh-autopair does 5 things for you: - -1. It inserts matching pairs (by default, that means brackets, quotes and - spaces): - - e.g. `echo |` => <kbd>"</kbd> => `echo "|"` - -2. It skips over matched pairs: - - e.g. `cat ./*.{py,rb|}` => <kbd>}</kbd> => `cat ./*.{py,rb}|` - -3. It auto-deletes pairs on backspace: - - e.g. `git commit -m "|"` => <kbd>backspace</kbd> => `git commit -m |` - -4. And does all of the above only when it makes sense to do so. e.g. when the - pair is balanced and when the cursor isn't next to a boundary character: - - e.g. `echo "|""` => <kbd>backspace</kbd> => `echo |""` (doesn't aggressively eat up too many quotes) - -5. Spaces between brackets are expanded and contracted. - - e.g. `echo [|]` => <kbd>space</kbd> => `echo [ | ]` => <kbd>backspace</kbd> => `echo [|]` - - -<!-- markdown-toc start - Don't edit this section. Run M-x markdown-toc-refresh-toc --> -**Table of Contents** - -- [Install](#install) - - [Antigen](#antigen) - - [zgen](#zgen) - - [zplug](#zplug) - - [Hombrew](#homebrew) - - [Oh My Zsh](#oh-my-zsh) -- [Configuration](#configuration) - - [Adding/Removing pairs](#addingremoving-pairs) -- [Troubleshooting & compatibility issues](#troubleshooting--compatibility-issues) - - [zgen & prezto compatibility](#zgen--prezto-compatibility) - - [text on right-side of cursor interfere with completion](#text-on-right-side-of-cursor-interfere-with-completion) - - [zsh-autopair & isearch?](#zsh-autopair--isearch) - - [Midnight Commander](#midnight-commander) -- [Other resources](#other-resources) - -<!-- markdown-toc end --> - -## Install -Download and source `autopair.zsh` - -```bash -if [[ ! -d ~/.zsh-autopair ]]; then - git clone https://github.com/hlissner/zsh-autopair ~/.zsh-autopair -fi - -source ~/.zsh-autopair/autopair.zsh -autopair-init -``` - -### Hoembrew -`brew install zsh-autopair` - -``` bash -# Add to .zshrc -source $HOMEBREW_PREFIX/share/zsh-autopair/autopair.zsh -``` - -### Antigen -`antigen bundle hlissner/zsh-autopair` - -### zgen -```bash -if ! zgen saved; then - echo "Creating a zgen save" - - # ... other plugins - zgen load hlissner/zsh-autopair - - zgen save -fi -``` - -### zplug -Load autopair _after compinit_, otherwise, the plugin won't work. -```bash -zplug "hlissner/zsh-autopair", defer:2 -``` - -### Homebrew -For Homebrew users, you can install it through the following command -```shell -brew install zsh-autopair -``` -Then source it in your `.zshrc` -```shell -source $(brew --prefix)/share/zsh-autopair/autopair.zsh -``` - -### Oh My Zsh -1. Clone this repository into `$ZSH_CUSTOM/plugins` (by default `~/.oh-my-zsh/custom/plugins`) - - ```sh - git clone https://github.com/hlissner/zsh-autopair ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autopair - ``` - -2. Add the plugin to the list of plugins for Oh My Zsh to load (inside `~/.zshrc`): - - ```sh - plugins=( - # other plugins... - zsh-autopair - ) - ``` - -3. Start a new terminal session. - -## Configuration -zsh-autopair sets itself up. You can prevent this by setting -`AUTOPAIR_INHIBIT_INIT`. - -**Options:** -* `AUTOPAIR_BETWEEN_WHITESPACE` (default: blank): if set, regardless of whether - delimiters are unbalanced or do not meet a boundary check, pairs will be - auto-closed if surrounded by whitespace, BOL or EOL. -* `AUTOPAIR_INHIBIT_INIT` (default: blank): if set, autopair will not - automatically set up keybinds. [Check out the initialization - code](autopair.zsh#L118) if you want to know what it does. -* `AUTOPAIR_PAIRS` (default: ``('`' '`' "'" "'" '"' '"' '{' '}' '[' ']' '(' ')' - ' ' ' ')``): An associative array that map pairs. Only one-character pairs are - supported. To modify this, see the "Adding/Removing pairs" section. -* `AUTOPAIR_LBOUNDS`/`AUTOPAIR_RBOUNDS` (default: see below): Associative lists - of regex character groups dictating the 'boundaries' for autopairing depending - on the delimiter. These are their default values: - - ```bash - AUTOPAIR_LBOUNDS=(all '[.:/\!]') - AUTOPAIR_LBOUNDS+=(quotes '[]})a-zA-Z0-9]') - AUTOPAIR_LBOUNDS+=(spaces '[^{([]') - AUTOPAIR_LBOUNDS+=(braces '') - AUTOPAIR_LBOUNDS+=('`' '`') - AUTOPAIR_LBOUNDS+=('"' '"') - AUTOPAIR_LBOUNDS+=("'" "'") - - AUTOPAIR_RBOUNDS=(all '[[{(<,.:?/%$!a-zA-Z0-9]') - AUTOPAIR_RBOUNDS+=(quotes '[a-zA-Z0-9]') - AUTOPAIR_RBOUNDS+=(spaces '[^]})]') - AUTOPAIR_RBOUNDS+=(braces '') - ``` - - For example, if `$AUTOPAIR_LBOUNDS[braces]="[a-zA-Z]"`, then braces (`{([`) won't be - autopaired if the cursor follows an alphabetical character. - - Individual delimiters can be used too. Setting `$AUTOPAIR_RBOUNDS['{']="[0-9]"` will - cause <kbd>{</kbd> specifically to not be autopaired when the cursor precedes a number. - -### Adding/Removing pairs -You can change the designated pairs in zsh-autopair by modifying the -`AUTOPAIR_PAIRS` envvar. This can be done _before_ initialization like so: - -``` sh -typeset -gA AUTOPAIR_PAIRS -AUTOPAIR_PAIRS+=("<" ">") -``` - -Or after initialization; however, you'll have to bind keys to `autopair-insert` -manually: - -```sh -AUTOPAIR_PAIRS+=("<" ">") -bindkey "<" autopair-insert -# prevents breakage in isearch -bindkey -M isearch "<" self-insert -``` - -To _remove_ pairs, use `unset 'AUTOPAIR_PAIRS[<]'`. Unbinding is optional. - -## Troubleshooting & compatibility issues -### zgen & prezto compatibility -Prezto's Editor module is known to reset autopair's bindings. A workaround is to -_defer autopair from initializing_ (by setting `AUTOPAIR_INHIBIT_INIT=1`) and -initialize it manually (by calling `autopair-init`): - -``` sh -source "$HOME/.zgen/zgen.zsh" - -# Add this -AUTOPAIR_INHIBIT_INIT=1 - -if ! zgen saved; then - zgen prezto - # ... - zgen load hlissner/zsh-autopair 'autopair.zsh' - #... - zgen save -fi - -# And this -autopair-init -``` - -### text on right-side of cursor interfere with completion -Bind <kbd>Tab</kbd> to `expand-or-complete-prefix` and completion will ignore -what's to the right of cursor: - -`bindkey '^I' expand-or-complete-prefix` - -This has the unfortunate side-effect of overwriting whatever's right of the -cursor, however. - -### zsh-autopair & isearch? -zsh-autopair silently disables itself in isearch, as the two are incompatible. - -### Midnight Commander -MC hangs when zsh-autopair tries to bind the space key. This also breaks the MC -subshell. - -Disable space expansion to work around this: `unset 'AUTOPAIR_PAIRS[ ]'` - -## Other resources -* Works wonderfully with [zsh-syntax-highlight] and - `ZSH_HIGHLIGHT_HIGHLIGHTERS+=brackets`, but zsh-syntax-highlight must be - loaded *after* zsh-autopair. -* Mixes well with these vi-mode zsh modules: [surround], [select-quoted], and - [select-bracketed] (they're built into zsh as of zsh-5.0.8) -* Other relevant repositories of mine: - + [dotfiles] - + [emacs.d] - + [vimrc] - + [zshrc] - - -[dotfiles]: https://github.com/hlissner/dotfiles -[vimrc]: https://github.com/hlissner/.vim -[emacs.d]: https://github.com/hlissner/doom-emacs -[zshrc]: https://github.com/hlissner/dotfiles/blob/master/config/zsh/.zshrc -[zsh-syntax-highlighting]: https://github.com/zsh-users/zsh-syntax-highlighting/blob/master/docs/highlighters/pattern.md -[surround]: https://github.com/zsh-users/zsh/blob/master/Functions/Zle/surround -[select-quoted]: https://github.com/zsh-users/zsh/blob/master/Functions/Zle/select-quoted -[select-bracketed]: https://github.com/zsh-users/zsh/blob/master/Functions/Zle/select-bracketed diff --git a/modules/mixins/dotfiles/config/zsh/plugins/zsh-autopair/autopair.plugin.zsh b/modules/mixins/dotfiles/config/zsh/plugins/zsh-autopair/autopair.plugin.zsh @@ -1,4 +0,0 @@ -# <https://github.com/zdharma-continuum/Zsh-100-Commits-Club/blob/master/Zsh-Plugin-Standard.adoc> -0="${${ZERO:-${0:#$ZSH_ARGZERO}}:-${(%):-%N}}" -0="${${(M)0:#/*}:-$PWD/$0}" -source "${0:A:h}/autopair.zsh" diff --git a/modules/mixins/dotfiles/config/zsh/plugins/zsh-autopair/autopair.zsh b/modules/mixins/dotfiles/config/zsh/plugins/zsh-autopair/autopair.zsh @@ -1,227 +0,0 @@ -#!/usr/bin/env zsh - -AUTOPAIR_INHIBIT_INIT=${AUTOPAIR_INHIBIT_INIT:-} -AUTOPAIR_BETWEEN_WHITESPACE=${AUTOPAIR_BETWEEN_WHITESPACE:-} -AUTOPAIR_SPC_WIDGET=${AUTOPAIR_SPC_WIDGET:-"$(bindkey " " | cut -c5-)"} -AUTOPAIR_BKSPC_WIDGET=${AUTOPAIR_BKSPC_WIDGET:-"$(bindkey "^?" | cut -c6-)"} -AUTOPAIR_DELWORD_WIDGET=${AUTOPAIR_DELWORD_WIDGET:-"$(bindkey "^w" | cut -c6-)"} - -typeset -gA AUTOPAIR_PAIRS -AUTOPAIR_PAIRS=('`' '`' "'" "'" '"' '"' '{' '}' '[' ']' '(' ')' ' ' ' ') - -typeset -gA AUTOPAIR_LBOUNDS -AUTOPAIR_LBOUNDS=(all '[.:/\!]') -AUTOPAIR_LBOUNDS+=(quotes '[]})a-zA-Z0-9]') -AUTOPAIR_LBOUNDS+=(spaces '[^{([]') -AUTOPAIR_LBOUNDS+=(braces '') -AUTOPAIR_LBOUNDS+=('`' '`') -AUTOPAIR_LBOUNDS+=('"' '"') -AUTOPAIR_LBOUNDS+=("'" "'") - -typeset -gA AUTOPAIR_RBOUNDS -AUTOPAIR_RBOUNDS=(all '[[{(<,.:?/%$!a-zA-Z0-9]') -AUTOPAIR_RBOUNDS+=(quotes '[a-zA-Z0-9]') -AUTOPAIR_RBOUNDS+=(spaces '[^]})]') -AUTOPAIR_RBOUNDS+=(braces '') - - -### Helpers ############################ - -# Returns the other pair for $1 (a char), blank otherwise -_ap-get-pair() { - if [[ -n $1 ]]; then - echo ${AUTOPAIR_PAIRS[$1]} - elif [[ -n $2 ]]; then - local i - for i in ${(@k)AUTOPAIR_PAIRS}; do - [[ $2 == ${AUTOPAIR_PAIRS[$i]} ]] && echo $i && break - done - fi -} - -# Return 0 if cursor's surroundings match either regexp: $1 (left) or $2 (right) -_ap-boundary-p() { - [[ -n $1 && $LBUFFER =~ "$1$" ]] || [[ -n $2 && $RBUFFER =~ "^$2" ]] -} - -# Return 0 if the surrounding text matches any of the AUTOPAIR_*BOUNDS regexps -_ap-next-to-boundary-p() { - local -a groups - groups=(all) - case $1 in - \'|\"|\`) groups+=quotes ;; - \{|\[|\(|\<) groups+=braces ;; - " ") groups+=spaces ;; - esac - groups+=$1 - local group - for group in $groups; do - _ap-boundary-p ${AUTOPAIR_LBOUNDS[$group]} ${AUTOPAIR_RBOUNDS[$group]} && return 0 - done - return 1 -} - -# Return 0 if there are the same number of $1 as there are $2 (chars; a -# delimiter pair) in the buffer. -_ap-balanced-p() { - local lbuf="${LBUFFER//\\$1}" - local rbuf="${RBUFFER//\\$2}" - local llen="${#lbuf//[^$1]}" - local rlen="${#rbuf//[^$2]}" - if (( rlen == 0 && llen == 0 )); then - return 0 - elif [[ $1 == $2 ]]; then - if [[ $1 == " " ]]; then - # Silence WARN_CREATE_GLOBAL errors - local match= - local mbegin= - local mend= - # Balancing spaces is unnecessary. If there is at least one space on - # either side of the cursor, it is considered balanced. - [[ $LBUFFER =~ "[^'\"]([ ]+)$" && $RBUFFER =~ "^${match[1]}" ]] && return 0 - return 1 - elif (( llen == rlen || (llen + rlen) % 2 == 0 )); then - return 0 - fi - else - local l2len="${#lbuf//[^$2]}" - local r2len="${#rbuf//[^$1]}" - local ltotal=$((llen - l2len)) - local rtotal=$((rlen - r2len)) - - (( ltotal < 0 )) && ltotal=0 - (( ltotal < rtotal )) && return 1 - return 0 - fi - return 1 -} - -# Return 0 if the last keypress can be auto-paired. -_ap-can-pair-p() { - local rchar="$(_ap-get-pair $KEYS)" - - [[ -n $rchar ]] || return 1 - - if [[ $rchar != " " ]]; then - # Force pair if surrounded by space/[BE]OL, regardless of - # boundaries/balance - [[ -n $AUTOPAIR_BETWEEN_WHITESPACE && \ - $LBUFFER =~ "(^|[ ])$" && \ - $RBUFFER =~ "^($|[ ])" ]] && return 0 - - # Don't pair quotes if the delimiters are unbalanced - ! _ap-balanced-p $KEYS $rchar && return 1 - elif [[ $RBUFFER =~ "^[ ]*$" ]]; then - # Don't pair spaces surrounded by whitespace - return 1 - fi - - # Don't pair when in front of characters that likely signify the start of a - # string, path or undesirable boundary. - _ap-next-to-boundary-p $KEYS $rchar && return 1 - - return 0 -} - -# Return 0 if the adjacent character (on the right) can be safely skipped over. -_ap-can-skip-p() { - if [[ -z $LBUFFER ]]; then - return 1 - elif [[ $1 == $2 ]]; then - if [[ $1 == " " ]]; then - return 1 - elif ! _ap-balanced-p $1 $2; then - return 1 - fi - fi - if ! [[ -n $2 && ${RBUFFER[1]} == $2 && ${LBUFFER[-1]} != '\' ]]; then - return 1 - fi - return 0 -} - -# Return 0 if the adjacent character (on the right) can be safely deleted. -_ap-can-delete-p() { - local lchar="${LBUFFER[-1]}" - local rchar="$(_ap-get-pair $lchar)" - ! [[ -n $rchar && ${RBUFFER[1]} == $rchar ]] && return 1 - if [[ $lchar == $rchar ]]; then - if [[ $lchar == ' ' && ( $LBUFFER =~ "[^{([] +$" || $RBUFFER =~ "^ +[^]})]" ) ]]; then - # Don't collapse spaces unless in delimiters - return 1 - elif ! _ap-balanced-p $lchar $rchar; then - return 1 - fi - fi - return 0 -} - -# Insert $1 and add $2 after the cursor -_ap-self-insert() { - LBUFFER+=$1 - RBUFFER="$2$RBUFFER" -} - - -### Widgets ############################ - -autopair-insert() { - local rchar="$(_ap-get-pair $KEYS)" - if [[ $KEYS == (\'|\"|\`| ) ]] && _ap-can-skip-p $KEYS $rchar; then - zle forward-char - elif _ap-can-pair-p; then - _ap-self-insert $KEYS $rchar - elif [[ $rchar == " " ]]; then - zle ${AUTOPAIR_SPC_WIDGET:-self-insert} - else - zle self-insert - fi -} - -autopair-close() { - if _ap-can-skip-p "$(_ap-get-pair "" $KEYS)" $KEYS; then - zle forward-char - else - zle self-insert - fi -} - -autopair-delete() { - _ap-can-delete-p && RBUFFER=${RBUFFER:1} - zle ${AUTOPAIR_BKSPC_WIDGET:-backward-delete-char} -} - -autopair-delete-word() { - _ap-can-delete-p && RBUFFER=${RBUFFER:1} - zle ${AUTOPAIR_DELWORD_WIDGET:-backward-delete-word} -} - - -### Initialization ##################### - -autopair-init() { - zle -N autopair-insert - zle -N autopair-close - zle -N autopair-delete - zle -N autopair-delete-word - - local p - for p in ${(@k)AUTOPAIR_PAIRS}; do - bindkey "$p" autopair-insert - bindkey -M isearch "$p" self-insert - - local rchar="$(_ap-get-pair $p)" - if [[ $p != $rchar ]]; then - bindkey "$rchar" autopair-close - bindkey -M isearch "$rchar" self-insert - fi - done - - bindkey "^?" autopair-delete - bindkey "^h" autopair-delete - bindkey "^w" autopair-delete-word - bindkey -M isearch "^?" backward-delete-char - bindkey -M isearch "^h" backward-delete-char - bindkey -M isearch "^w" backward-delete-word -} -[[ -n $AUTOPAIR_INHIBIT_INIT ]] || autopair-init diff --git a/modules/mixins/dotfiles/config/zsh/plugins/zsh-autopair/tests/_support/bootstrap b/modules/mixins/dotfiles/config/zsh/plugins/zsh-autopair/tests/_support/bootstrap @@ -1,15 +0,0 @@ -#!/usr/bin/env zsh -source autopair.zsh -export KEYS= -export LBUFFER= -export RBUFFER= - -assert_true() { - run $@ - assert $state equals 0 -} - -assert_false() { - run $@ - assert $state equals 1 -} diff --git a/modules/mixins/dotfiles/config/zsh/plugins/zsh-autopair/tests/balanced-p.zunit b/modules/mixins/dotfiles/config/zsh/plugins/zsh-autopair/tests/balanced-p.zunit @@ -1,16 +0,0 @@ -#!/usr/bin/env zunit -@test 'basic boundary tests' { - LBUFFER="abc" - RBUFFER="123" - assert_false _ap-boundary-p " " " " - assert_true _ap-boundary-p "[^3]" "[^a]" - assert_false _ap-boundary-p "[^c]" "[^1]" - assert_true _ap-boundary-p "c" " " - assert_true _ap-boundary-p " " "1" -} - -@test 'no boundary on blank line' { - LBUFFER= - RBUFFER= - assert_false _ap-next-to-boundary-p "{" -} diff --git a/modules/mixins/dotfiles/config/zsh/plugins/zsh-autopair/tests/can-delete-p.zunit b/modules/mixins/dotfiles/config/zsh/plugins/zsh-autopair/tests/can-delete-p.zunit @@ -1,24 +0,0 @@ -#!/usr/bin/env zunit -@test 'delete if next to space and pair' { - LBUFFER="[ " RBUFFER=" ]" assert_true _ap-can-delete-p -} - -@test 'delete if next to homogeneous counter-pair' { - LBUFFER="'" RBUFFER="'" assert_true _ap-can-delete-p -} - -@test 'delete if next to heterogeneous counter-pair' { - LBUFFER="(" RBUFFER=")" assert_true _ap-can-delete-p -} - -@test 'do not delete if at eol' { - LBUFFER="'" assert_false _ap-can-delete-p -} - -@test 'do not delete if within too many spaces' { - LBUFFER="[ " RBUFFER=" ]" assert_false _ap-can-delete-p -} - -@test 'do not delete if only next to space' { - LBUFFER=" " RBUFFER=" " assert_false _ap-can-delete-p -} diff --git a/modules/mixins/dotfiles/config/zsh/plugins/zsh-autopair/tests/can-pair-p.zunit b/modules/mixins/dotfiles/config/zsh/plugins/zsh-autopair/tests/can-pair-p.zunit @@ -1,59 +0,0 @@ -#!/usr/bin/env zunit -@test 'pair if blank line' { - KEYS="'" LBUFFER="" RBUFFER="" assert_true _ap-can-pair-p -} - -@test 'pair if next to balanced delimiter' { # {{|}} - KEYS="{" LBUFFER="{" RBUFFER="}" assert_true _ap-can-pair-p -} - -@test 'pair space if next to brackets' { # { | } - KEYS=" " - LBUFFER="{" RBUFFER="}" assert_true _ap-can-pair-p - LBUFFER="[" RBUFFER="]" assert_true _ap-can-pair-p - LBUFFER="(" RBUFFER=")" assert_true _ap-can-pair-p -} - -@test 'pair brackets at the end of a word' { # abc{|} - KEYS='{' LBUFFER="hello" assert_true _ap-can-pair-p -} - -@test 'do not pair brackets at the beginning of a word' { # {|abc - KEYS='{' RBUFFER="hello" assert_false _ap-can-pair-p -} - -@test 'do not pair quotes next to a word' { - KEYS="'" - LBUFFER="hello" assert_false _ap-can-pair-p # abc"| - RBUFFER="hello" assert_false _ap-can-pair-p # "|abc -} - -@test 'do not pair the same quotes from inside quotes' { # ""|" - KEYS='"' LBUFFER='"' RBUFFER='"' assert_false _ap-can-pair-p -} - -@test 'do not pair if delimiter is invalid' { - KEYS="<" LBUFFER="<" RBUFFER=">" assert_false _ap-can-pair-p -} - -@test 'do not pair if next to unbalanced delimiter' { # {|} - KEYS="{" LBUFFER="" RBUFFER="}" assert_false _ap-can-pair-p -} - -@test 'do not pair if next to unbalanced delimiter after space' { # {| } - AUTOPAIR_BETWEEN_WHITESPACE= - KEYS="{" LBUFFER="" RBUFFER=" }" assert_false _ap-can-pair-p - KEYS="{" LBUFFER="" RBUFFER=" }" assert_false _ap-can-pair-p - KEYS="{" LBUFFER=" " RBUFFER=" }" assert_false _ap-can-pair-p -} - -@test 'do not pair space if next to non-brackets/spaces' { - KEYS=" " - LBUFFER="'" RBUFFER="'" assert_false _ap-can-pair-p # ' |' - LBUFFER="abc" RBUFFER="xyz" assert_false _ap-can-pair-p # abc |xyz' - LBUFFER="[ " RBUFFER=" ]" assert_false _ap-can-pair-p # [ | ] -} - -@test 'AUTOPAIR_BETWEEN_WHITESPACE=1' { - AUTOPAIR_BETWEEN_WHITESPACE=1 KEYS='{' LBUFFER=" " RBUFFER=" }" assert_true _ap-can-pair-p -} diff --git a/modules/mixins/dotfiles/config/zsh/plugins/zsh-autopair/tests/can-skip-p.zunit b/modules/mixins/dotfiles/config/zsh/plugins/zsh-autopair/tests/can-skip-p.zunit @@ -1,25 +0,0 @@ -#!/usr/bin/env zunit - -@test 'fail skip-check on blank line' { - LBUFFER='' RBUFFER='' assert_false _ap-can-skip-p '{' '}' -} - -@test 'fail skip-check on wrong pair' { - LBUFFER='"' RBUFFER='"' assert_false _ap-can-skip-p '{' '}' -} - -@test 'skip if next to homogeneous counter-pair' { - LBUFFER='"' RBUFFER='"' assert_true _ap-can-skip-p '"' '"' -} - -@test 'skip if next to heterogeneous counter-pair' { - LBUFFER='{' RBUFFER='}' assert_true _ap-can-skip-p '{' '}' -} - -@test 'do not skip if next to unbalanced, homogeneous counter-pair' { - LBUFFER='' RBUFFER='"' assert_false _ap-can-skip-p '"' '"' -} - -@test 'do not skip if next to unbalanced, heterogeneous counter-pair' { - LBUFFER='' RBUFFER='}' assert_false _ap-can-skip-p '{' '}' -} diff --git a/modules/mixins/dotfiles/config/zsh/plugins/zsh-autopair/tests/get-pair.zunit b/modules/mixins/dotfiles/config/zsh/plugins/zsh-autopair/tests/get-pair.zunit @@ -1,26 +0,0 @@ -#!/usr/bin/env zunit -@test 'existing pair' { - assert $(_ap-get-pair "{") same_as "}" -} - -@test 'existing right-pair' { - assert $(_ap-get-pair "" "}") same_as "{" -} - -@test 'non-existent pair' { - assert $(_ap-get-pair "<") same_as "" -} - -@test 'non-existent right-pair' { - assert $(_ap-get-pair "" ">") same_as "" -} - -@test 'all default pairs' { - assert '"' in ${(@k)AUTOPAIR_PAIRS} - assert "'" in ${(@k)AUTOPAIR_PAIRS} - assert '`' in ${(@k)AUTOPAIR_PAIRS} - assert '{' in ${(@k)AUTOPAIR_PAIRS} - assert '[' in ${(@k)AUTOPAIR_PAIRS} - assert '(' in ${(@k)AUTOPAIR_PAIRS} - assert ' ' in ${(@k)AUTOPAIR_PAIRS} -} diff --git a/modules/mixins/dotfiles/config/zsh/plugins/zsh-autopair/zsh-autopair.plugin.zsh b/modules/mixins/dotfiles/config/zsh/plugins/zsh-autopair/zsh-autopair.plugin.zsh @@ -1,4 +0,0 @@ -# <https://github.com/zdharma-continuum/Zsh-100-Commits-Club/blob/master/Zsh-Plugin-Standard.adoc> -0="${${ZERO:-${0:#$ZSH_ARGZERO}}:-${(%):-%N}}" -0="${${(M)0:#/*}:-$PWD/$0}" -source "${0:A:h}/autopair.zsh" diff --git a/modules/mixins/dotfiles/config/zsh/plugins/zsh-histdb/LICENSE b/modules/mixins/dotfiles/config/zsh/plugins/zsh-histdb/LICENSE @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2019 Tom Hinton - -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. diff --git a/modules/mixins/dotfiles/config/zsh/plugins/zsh-histdb/README.org b/modules/mixins/dotfiles/config/zsh/plugins/zsh-histdb/README.org @@ -1,182 +0,0 @@ -#+TITLE:ZSH History Database - -* News -- 13/10/21 :: Thanks to Aloxaf some subshell invocations have been removed which should make things quicker. Thanks to m42e (again) ~histdb-sync~ uses the remote database IDs as the canonical ones which should make syncing a bit less thrashy. Thanks to Chad Transtrum we use ~builtin which~ rather than ~which~, for systems which have an unusual which (?!), and an improvement to examples below in the README. Thanks to Klaus Ethgen the invocation of ~sqlite3~ is now unaffected by some potential confusions in your sqlite rc files. -- 30/06/20 :: Thanks to rolandwalker, add-zsh-hook is used so histdb is a better citizen. - Thanks to GreenArchon and phiresky the sqlite helper process is terminated on exit better, and the WAL is truncated before doing histdb sync. This should make things behave a bit better. Thanks to gabreal (and others, I think), some things have been changed to ~declare -ga~ which helps when using antigen or somesuch? Thanks to sheperdjerred and fuero there is now a file which might make antigen and oh-my-zsh work. - - There is a *breaking change*, which is that you no longer need to ~add-zsh-hook precmd histdb-update-outcome~ in your rc file. This now happens when you source ~sqlite-history.zsh~. -- 11/03/20 :: Thanks to phiresky (https://github.com/phiresky) history appends within a shell session are performed through a single long-running sqlite process rather than by starting a new process per history append. This reduces contention between shells that are trying to write, as sqlite always fsyncs on exit. -- 29/05/19 :: Thanks to Matthias Bilger (https://github.com/m42e/) a bug has been removed which would have broken the database if the vacuum command were used. Turns out, you can't use rowid as a foreign key unless you've given it a name. As a side-effect your database will need updating, in a non-backwards compatible way, so you'll need to update on all your installations at once if you share a history file. - Also, it's not impossible that this change will make a problem for someone somewhere, so be careful with this update. - - Also thanks to Matthias, the exit status of long-running commands is handled better. -- 05/04/18 :: I've done a bit of work to make a replacement reverse-isearch function, which is in a usable state now. - - If you want to use it, see the [[Reverse isearch]] section below which now covers it. - -- 09/09/17 :: If you have already installed and you want to get the right timings in the database, see the installation section again. Fix to issue #18. - -* What is this - -This is a small bit of zsh code that stores your history into a sqlite3 database. -It improves on the normal history by storing, for each history command: - -- The start and stop times of the command -- The working directory where the command was run -- The hostname of the machine -- A unique per-host session ID, so history from several sessions is not confused -- The exit status of the command - -It is also possible to merge multiple history databases together without conflict, so long as all your machines have different hostnames. - -* Installation - -You will need ~sqlite3~ and the usual coreutils commands installed on your ~PATH~. -To load and activate history recording you need to source ~sqlite-history.zsh~ from your shell in your zsh startup files. - -Example for installing in ~$HOME/.oh-my-zsh/custom/plugins/zsh-histdb~ (note that ~oh-my-zsh~ is not required): - -#+BEGIN_SRC zsh -mkdir -p $HOME/.oh-my-zsh/custom/plugins/ -git clone https://github.com/larkery/zsh-histdb $HOME/.oh-my-zsh/custom/plugins/zsh-histdb -#+END_SRC - -Add this to your ~$HOME/.zshrc~: - -#+BEGIN_SRC zsh -source $HOME/.oh-my-zsh/custom/plugins/zsh-histdb/sqlite-history.zsh -autoload -Uz add-zsh-hook -#+END_SRC - -in your zsh startup files. - -** Note for OS X users - -Add the following line before you source `sqlite-history.zsh`. See https://github.com/larkery/zsh-histdb/pull/31 for details. - -#+BEGIN_SRC zsh -HISTDB_TABULATE_CMD=(sed -e $'s/\x1f/\t/g') -#+END_SRC - -** Importing your old history - -[[https://github.com/drewis/go-histdbimport][go-histdbimport]] and [[https://github.com/phiresky/ts-histdbimport][ts-histdbimport]] are useful tools for doing this! Note that the imported history will not include metadata such as the working directory or the exit status, since that is not stored in the normal history file format, so queries using ~--in DIR~, etc. will not work as expected. - -* Configuration -histdb can be configured exactly as zsh: -- [[https://zsh.sourceforge.io/Doc/Release/Parameters.html#index-HISTORY_005fIGNORE][HISTORY_IGNORE]]: If set, is treated as a single glob pattern to match the commands that should be ignored. Ignored commands are not saved to the database. Example: ~(ls|cd|top|htop)~. - -* Querying history -You can query the history with the ~histdb~ command. -With no arguments it will print one screenful of history on the current host. - -With arguments, it will print history lines matching their concatenation. - -For wildcards within a history line, you can use the ~%~ character, which is like the shell glob ~*~, so ~histdb this%that~ will match any history line containing ~this~ followed by ~that~ with zero or more characters in-between. - -To search on particular hosts, directories, sessions, or time periods, see the help with ~histdb --help~. - -You can also run ~histdb-top~ to see your most frequent commands, and ~histdb-top dir~ to show your favourite directory for running commands in, but these commands are really a bit useless. -** Example: - -#+BEGIN_SRC text -$ histdb strace -time ses dir cmd -17/03 438 ~ strace conkeror -22/03 522 ~ strace apropos cake -22/03 522 ~ strace -e trace=file s -22/03 522 ~ strace -e trace=file ls -22/03 522 ~ strace -e trace=file cat temp/people.vcf -22/03 522 ~ strace -e trace=file cat temp/gammu.log -22/03 522 ~ run-help strace -24/03 547 ~ man strace -#+END_SRC - -These are all the history entries involving ~strace~ in my history. -If there was more than one screenful, I would need to say ~--limit 1000~ or some other large number. -The command does not warn you if you haven't seen all the results. -The ~ses~ column contains a unique session number, so all the ~522~ rows are from the same shell session. - -To see all hosts, add ~--host~ /after/ the query terms. -To see a specific host, add ~--host hostname~. -To see all of a specific session say e.g. ~-s 522 --limit 10000~. -** Integration with ~zsh-autosuggestions~ - -If you use [[https://github.com/zsh-users/zsh-autosuggestions][zsh-autosuggestions]] you can configure it to search the history database instead of the zsh history file thus: - -#+BEGIN_SRC sh - _zsh_autosuggest_strategy_histdb_top_here() { - local query="select commands.argv from - history left join commands on history.command_id = commands.rowid - left join places on history.place_id = places.rowid - where places.dir LIKE '$(sql_escape $PWD)%' - and commands.argv LIKE '$(sql_escape $1)%' - group by commands.argv order by count(*) desc limit 1" - suggestion=$(_histdb_query "$query") - } - - ZSH_AUTOSUGGEST_STRATEGY=histdb_top_here -#+END_SRC - -This query will find the most frequently issued command that is issued in the current directory or any subdirectory. You can get other behaviours by changing the query, for example - -#+BEGIN_SRC sh - _zsh_autosuggest_strategy_histdb_top() { - local query=" - select commands.argv from history - left join commands on history.command_id = commands.rowid - left join places on history.place_id = places.rowid - where commands.argv LIKE '$(sql_escape $1)%' - group by commands.argv, places.dir - order by places.dir != '$(sql_escape $PWD)', count(*) desc - limit 1 - " - suggestion=$(_histdb_query "$query") - } - - ZSH_AUTOSUGGEST_STRATEGY=histdb_top -#+END_SRC - -This will find the most frequently issued command issued exactly in this directory, or if there are no matches it will find the most frequently issued command in any directory. You could use other fields like the hostname to restrict to suggestions on this host, etc. -** Reverse isearch -If you want a history-reverse-isearch type feature there is one defined in ~histdb-interactive.zsh~. If you source that file you will get a new widget called _histdb-isearch which you can bind to a key, e.g. - -#+BEGIN_SRC sh -source histdb-interactive.zsh -bindkey '^r' _histdb-isearch -#+END_SRC - -This is like normal ~history-reverse-isearch~ except: -- The search will start with the buffer contents automatically -- The editing keys are all standard (because it does not really use the minibuffer). - - This means pressing ~C-a~ or ~C-e~ or similar will not exit the search like normal ~history-reverse-isearch~ -- The accept key (~RET~) does not cause the command to run immediately but instead lets you edit it - -There are also a few extra keybindings: - -- ~M-j~ will ~cd~ to the directory for the history entry you're looking at. - This means you can search for ./run-this-command and then ~M-j~ to go to the right directory before running. -- ~M-h~ will toggle limiting the search to the current host's history. -- ~M-d~ will toggle limiting the search to the current directory and subdirectories' histories -* Database schema -The database lives by default in ~$HOME/.histdb/zsh-history.db~. -You can look in it easily by running ~_histdb_query~, as this actually just fires up sqlite with the database. - -For inspiration you can also use ~histdb~ with the ~-d~ argument and it will print the SQL it's running. -* Synchronising history -You should be able to synchronise the history using ~git~; a 3-way merge driver is supplied in ~histdb-merge~. - -The 3-way merge will only work properly if all the computers on which you use the repository have different hostnames. - -The ~histdb-sync~ function will initialize git in the histdb directory and configure the merge driver for you first time you run it. -Subsequent times it will commit all changes, pull all changes, force a merge, and push all changes back again. -The commit message is useless, so if you find that kind of thing upsetting you will need to fix it. - -The reason for using ~histdb-sync~ instead of doing it by hand is that if you are running the git steps in your shell the history database will be changed each command, and so you will never be able to do a pull / merge. -* Completion -None, and I've used the names with underscores to mean something else. -* Pull requests / missing features -Happy to look at changes. -I did at one point have a reverse-isearch thing in here for searching the database interactively, but it didn't really make my life any better so I deleted it. diff --git a/modules/mixins/dotfiles/config/zsh/plugins/zsh-histdb/db_migrations/0to2.sql b/modules/mixins/dotfiles/config/zsh/plugins/zsh-histdb/db_migrations/0to2.sql @@ -1,30 +0,0 @@ -PRAGMA foreign_keys=OFF; -begin transaction; -create table commands_new (id integer primary key autoincrement, argv text, unique(argv) on conflict ignore); -create table places_new (id integer primary key autoincrement, host text, dir text, unique(host, dir) on conflict ignore); -create table history_new (id integer primary key autoincrement, - session int, - command_id int references commands (id), - place_id int references places (id), - exit_status int, - start_time int, - duration int); - -INSERT INTO commands_new (id, argv) SELECT rowid, argv FROM commands; -INSERT INTO places_new (id, host, dir) SELECT rowid, host, dir FROM places; - -INSERT INTO history_new (session, command_id, place_id, exit_status, start_time, duration) -SELECT H.session, C.rowid, P.rowid, H.exit_status, H.start_time, H.duration -FROM history H -LEFT JOIN places P ON H.place_id = P.rowid -LEFT JOIN commands C ON H.command_id = C.rowid; -drop table history; -drop table places; -drop table commands; -ALTER TABLE commands_new RENAME TO commands; -ALTER TABLE places_new RENAME TO places; -ALTER TABLE history_new RENAME TO history; -PRAGMA foreign_key_check ; -PRAGMA user_version=2; -commit; -PRAGMA foreign_keys=ON; diff --git a/modules/mixins/dotfiles/config/zsh/plugins/zsh-histdb/histdb-interactive.zsh b/modules/mixins/dotfiles/config/zsh/plugins/zsh-histdb/histdb-interactive.zsh @@ -1,214 +0,0 @@ -typeset -g HISTDB_ISEARCH_N -typeset -g HISTDB_ISEARCH_MATCH -typeset -g HISTDB_ISEARCH_DIR -typeset -g HISTDB_ISEARCH_HOST -typeset -g HISTDB_ISEARCH_DATE -typeset -g HISTDB_ISEARCH_MATCH_END - -typeset -g HISTDB_ISEARCH_THIS_HOST=1 -typeset -g HISTDB_ISEARCH_THIS_DIR=0 -typeset -g HISTDB_ISEARCH_LAST_QUERY="" -typeset -g HISTDB_ISEARCH_LAST_N="" - -# TODO Show more info about match (n, date, pwd, host) -# TODO Keys to limit match? - -# make a keymap for histdb isearch -bindkey -N histdb-isearch main - -_histdb_isearch_query () { - if [[ -z $BUFFER ]]; then - HISTDB_ISEARCH_MATCH="" - return - fi - - local new_query="$BUFFER $HISTDB_ISEARCH_THIS_HOST $HISTDB_ISEARCH_THIS_DIR" - if [[ $new_query == $HISTDB_ISEARCH_LAST_QUERY ]] && [[ $HISTDB_ISEARCH_N == $HISTDB_ISEARCH_LAST_N ]]; then - return - elif [[ $new_query != $HISTDB_ISEARCH_LAST_QUERY ]]; then - HISTDB_ISEARCH_N=0 - fi - - HISTDB_ISEARCH_LAST_QUERY=$new_query - HISTDB_ISEARCH_LAST_N=HISTDB_ISEARCH_N - - if (( $HISTDB_ISEARCH_N < 0 )); then - local maxmin="min" - local ascdesc="asc" - local offset=$(( - $HISTDB_ISEARCH_N )) - else - local maxmin="max" - local ascdesc="desc" - local offset=$(( $HISTDB_ISEARCH_N )) - fi - - if [[ $HISTDB_ISEARCH_THIS_DIR == 1 ]]; then - local where_dir="and places.dir like '$(sql_escape $PWD)%'" - else - local where_dir="" - fi - - - if [[ $HISTDB_ISEARCH_THIS_HOST == 1 ]]; then - local where_host="and places.host = '$(sql_escape $HOST)'" - else - local where_host="" - fi - - local query="select -commands.argv, -places.dir, -places.host, -datetime(max(history.start_time), 'unixepoch', 'localtime') -from history left join commands -on history.command_id = commands.rowid -left join places -on history.place_id = places.rowid -where commands.argv glob '*$(sql_escape ${BUFFER})*' -${where_host} -${where_dir} -group by commands.argv, places.dir, places.host -order by ${maxmin}(history.start_time) ${ascdesc} -limit 1 -offset ${offset}" - local result=$(_histdb_query -separator $'\n' "$query") - local lines=("${(f)result}") - HISTDB_ISEARCH_DATE=${lines[-1]} - HISTDB_ISEARCH_HOST=${lines[-2]} - HISTDB_ISEARCH_DIR=${lines[-3]} - lines[-1]=() - lines[-1]=() - lines[-1]=() - HISTDB_ISEARCH_MATCH=${(F)lines} -} - -_histdb_isearch_display () { - if [[ $HISTDB_ISEARCH_THIS_HOST == 1 ]]; then - local host_bit=" h" - else - local host_bit="" - fi - if [[ $HISTDB_ISEARCH_THIS_DIR == 1 ]]; then - local dir_bit=" d" - else - local dir_bit="" - fi - local top_bit="histdb ${HISTDB_ISEARCH_N}${host_bit}${dir_bit}: " - if [[ -z ${HISTDB_ISEARCH_MATCH} ]]; then - PREDISPLAY="(no match) -$top_bit" - else - local qbuffer="${(b)BUFFER}" - qbuffer="${${qbuffer//\\\*/*}//\\\?/?}" - local match_len="${#HISTDB_ISEARCH_MATCH}" - local prefix="${HISTDB_ISEARCH_MATCH%%${~qbuffer}*}" - local prefix_len="${#prefix}" - local suffix_len="${#${HISTDB_ISEARCH_MATCH:${prefix_len}}##${~qbuffer}}" - local match_end=$(( $match_len - $suffix_len )) - HISTDB_ISEARCH_MATCH_END=${match_end} - - if [[ $HISTDB_ISEARCH_HOST == $HOST ]]; then - local host="" - else - local host=" - host: $HISTDB_ISEARCH_HOST" - fi - region_highlight=("P${prefix_len} ${match_end} underline") - PREDISPLAY="${HISTDB_ISEARCH_MATCH} -→ in ${HISTDB_ISEARCH_DIR}$host -→ on ${HISTDB_ISEARCH_DATE} -$top_bit" - fi -} - -_histdb-isearch-up () { - HISTDB_ISEARCH_N=$(( $HISTDB_ISEARCH_N + 1 )) -} - -_histdb-isearch-down () { - HISTDB_ISEARCH_N=$(( $HISTDB_ISEARCH_N - 1 )) -} - -zle -N self-insert-histdb-isearch - -_histdb_line_redraw () { - _histdb_isearch_query - _histdb_isearch_display -} - -_histdb-isearch () { - local old_buffer=${BUFFER} - local old_cursor=${CURSOR} - HISTDB_ISEARCH_N=0 - echo -ne "\e[4 q" # switch to underline cursor - - zle -K histdb-isearch - zle -N zle-line-pre-redraw _histdb_line_redraw - _histdb_isearch_query - _histdb_isearch_display - zle recursive-edit; local stat=$? - zle -D zle-line-pre-redraw # TODO push/pop zle-line-pre-redraw and - # self-insert, rather than nuking - - zle -K main - PREDISPLAY="" - region_highlight=() - - echo -ne "\e[1 q" #box cursor - - if ! (( stat )); then - BUFFER="${HISTDB_ISEARCH_MATCH}" - CURSOR="${HISTDB_ISEARCH_MATCH_END}" - else - BUFFER=${old_buffer} - CURSOR=${old_cursor} - fi - - return 0 -} - -# this will work outside histdb-isearch if you want -# so you can recover from history and then cd afterwards -_histdb-isearch-cd () { - if [[ -d ${HISTDB_ISEARCH_DIR} ]]; then - cd "${HISTDB_ISEARCH_DIR}" - zle reset-prompt - fi -} - -_histdb-isearch-toggle-host () { - if [[ $HISTDB_ISEARCH_THIS_HOST == 1 ]]; then - HISTDB_ISEARCH_THIS_HOST=0 - else - HISTDB_ISEARCH_THIS_HOST=1 - fi -} - -_histdb-isearch-toggle-dir () { - if [[ $HISTDB_ISEARCH_THIS_DIR == 1 ]]; then - HISTDB_ISEARCH_THIS_DIR=0 - else - HISTDB_ISEARCH_THIS_DIR=1 - fi -} - -zle -N _histdb-isearch-up -zle -N _histdb-isearch-down -zle -N _histdb-isearch -zle -N _histdb-isearch-cd -zle -N _histdb-isearch-toggle-dir -zle -N _histdb-isearch-toggle-host - -bindkey -M histdb-isearch '' _histdb-isearch-up -bindkey -M histdb-isearch '^[[A' _histdb-isearch-up - -bindkey -M histdb-isearch '' _histdb-isearch-down -bindkey -M histdb-isearch '^[[B' _histdb-isearch-down - -bindkey -M histdb-isearch '^[j' _histdb-isearch-cd - -bindkey -M histdb-isearch '^[h' _histdb-isearch-toggle-host -bindkey -M histdb-isearch '^[d' _histdb-isearch-toggle-dir - -# because we are using BUFFER for output, we have to reimplement -# pretty much the whole set of buffer editing operations diff --git a/modules/mixins/dotfiles/config/zsh/plugins/zsh-histdb/histdb-merge b/modules/mixins/dotfiles/config/zsh/plugins/zsh-histdb/histdb-merge @@ -1,62 +0,0 @@ -#!/usr/bin/env zsh - -typeset -g HERE=$(dirname "${(%):-%N}") - -local ancestor=${1:?three databases required}; shift -local ours=${1:?three databases required}; shift -local theirs=${1:?three databases required} - -$HERE/histdb-migrate $ancestor # this is always reasonable to do -$HERE/histdb-migrate $ours # this also seems fine - -V_OURS=$(sqlite3 -batch -noheader $ours 'PRAGMA user_version') -V_THEIRS=$(sqlite3 -batch -noheader $theirs 'PRAGMA user_version') - -if [[ ${V_OURS} -lt ${V_THEIRS} ]] ; then - echo "Attempting to merge with a database from a future version (${V_THEIRS})." - echo "You need to update your histdb version to continue." - exit 1 -elif [[ ${V_THEIRS} -lt ${V_OURS} ]]; then - echo "Merging different database versions: ours ${V_OURS}, theirs ${V_THEIRS}." - echo "To continue merging, their database needs migrating to newer version." - echo "If you do this, and push the changes, then the remote version of histdb will need upgrading too." - - read -q "REPLY?Try migrating their database? [y/n] " - if [[ $REPLY != "y" ]]; then - echo "Cancelled." - exit 1 - fi -fi - -# for reasons I cannot use the encryption filter here. -# most annoying. -# -echo "Ancestor has $(sqlite3 ${ancestor} 'select count(*) from history') entries" -echo "We have $(sqlite3 ${ours} 'select count(*) from history') entries" -echo "Theirs have $(sqlite3 ${theirs} 'select count(*) from history') entries" - -sqlite3 -batch -noheader "${theirs}" <<EOF -ATTACH DATABASE '${ours}' AS n; -ATTACH DATABASE '${ancestor}' AS a; - --- copy missing commands and places -INSERT INTO commands (argv) SELECT argv FROM n.commands as NC where NC.id > (SELECT max(id) FROM a.commands); -INSERT INTO places (host, dir) SELECT host, dir FROM n.places as NP where NP.id > (SELECT max(id) FROM a.places); - --- insert missing history, rewriting IDs --- could uniquify sessions by host in this way too - -INSERT INTO history (session, command_id, place_id, exit_status, start_time, duration) -SELECT NO.session, C.id, P.id, NO.exit_status, NO.start_time, NO.duration -FROM n.history NO -LEFT JOIN n.places PO ON NO.place_id = PO.id -LEFT JOIN n.commands CO ON NO.command_id = CO.id -LEFT JOIN commands C ON C.argv = CO.argv -LEFT JOIN places P ON (P.host = PO.host -AND P.dir = PO.dir) -WHERE NO.id > (SELECT MAX(id) FROM a.history) -; -VACUUM; -EOF -cp ${theirs} ${ours} -echo "Now we have $(sqlite3 ${ours} 'select count(*) from history') entries" diff --git a/modules/mixins/dotfiles/config/zsh/plugins/zsh-histdb/histdb-migrate b/modules/mixins/dotfiles/config/zsh/plugins/zsh-histdb/histdb-migrate @@ -1,27 +0,0 @@ -#!/usr/bin/env zsh - -typeset -g HISTDB_SCHEMA_VERSION=2 -typeset -g HISTDB_INSTALLED_IN="${(%):-%N}" - -local TARGET_FILE="$1" -local CURRENT_VERSION=$(sqlite3 -batch -noheader "${TARGET_FILE}" 'PRAGMA user_version') -if [[ ${CURRENT_VERSION} -lt ${HISTDB_SCHEMA_VERSION} ]]; then - echo "History database ${TARGET_FILE} is using an older schema (${CURRENT_VERSION}) and will be updated to version ${HISTDB_SCHEMA_VERSION}." - local MIGRATION_FILENAME="$(dirname ${HISTDB_INSTALLED_IN})/db_migrations/${CURRENT_VERSION}to${HISTDB_SCHEMA_VERSION}.sql" - if [[ -f $MIGRATION_FILENAME ]]; then - local BACKUP_FILE="${TARGET_FILE}-$(date +%s).bak" - echo "Backing up database to ${BACKUP_FILE} before migration" - cp ${BACKUP_FILE} ${HISTDB_FILE} - sqlite3 -batch -noheader "${TARGET_FILE}" < "${MIGRATION_FILENAME}" - local R="$?" - [[ "$R" -ne 0 ]] && (echo "Error during database conversion"; cp ${BACKUP_FILE} ${HISTDB_FILE}) || echo "Update successful (you may want to remove the backup)" - return "$R" - else - echo "There is no migration script from version ${CURRENT_VERSION} to ${HISTDB_SCHEMA_VERSION}." - return 1 - fi -elif [[ ${CURRENT_VERSION} -gt ${HISTDB_SCHEMA_VERSION} ]]; then - echo "History database ${TARGET_FILE} is using a newer schema (${CURRENT_VERSION}) than this version of histdb understands (${HISTDB_SCHEMA_VERSION})." - echo "Most likely, you have updated histdb on another machine which has updated your history database, and you need to update this copy of histdb." - return 1 -fi diff --git a/modules/mixins/dotfiles/config/zsh/plugins/zsh-histdb/sqlite-history.zsh b/modules/mixins/dotfiles/config/zsh/plugins/zsh-histdb/sqlite-history.zsh @@ -1,503 +0,0 @@ -which sqlite3 >/dev/null 2>&1 || return; - -zmodload zsh/datetime # for EPOCHSECONDS -zmodload zsh/system # for sysopen -builtin which sysopen &>/dev/null || return; # guard against zsh older than 5.0.8. - -zmodload -F zsh/stat b:zstat # just zstat -autoload -U add-zsh-hook - -typeset -g HISTDB_QUERY="" -if [[ -z ${HISTDB_FILE} ]]; then - typeset -g HISTDB_FILE="${HOME}/.histdb/zsh-history.db" -else - typeset -g HISTDB_FILE -fi - -typeset -g HISTDB_FD -typeset -g HISTDB_INODE=() -typeset -g HISTDB_SESSION="" -typeset -g HISTDB_HOST="" -typeset -g HISTDB_INSTALLED_IN="${(%):-%N}" - - - -sql_escape () { - print -r -- ${${@//\'/\'\'}//$'\x00'} -} - -_histdb_query () { - sqlite3 -batch -noheader -cmd ".timeout 1000" "${HISTDB_FILE}" "$@" - [[ "$?" -ne 0 ]] && echo "error in $@" -} - -_histdb_stop_sqlite_pipe () { - if [[ -n $HISTDB_FD ]]; then - if print -nu$HISTDB_FD; then - exec {HISTDB_FD}>&-; # https://stackoverflow.com/a/22794374/2639190 - fi - fi - # Sometimes, it seems like closing the fd does not terminate the - # sqlite batch process, so here is a horrible fallback. - # if [[ -n $HISTDB_SQLITE_PID ]]; then - # ps -o args= -p $HISTDB_SQLITE_PID | read -r args - # if [[ $args == "sqlite3 -batch ${HISTDB_FILE}" ]]; then - # kill -TERM $HISTDB_SQLITE_PID - # fi - # fi -} - -add-zsh-hook zshexit _histdb_stop_sqlite_pipe - -_histdb_start_sqlite_pipe () { - local PIPE==(<<<'') - setopt local_options no_notify no_monitor - mkfifo $PIPE - sqlite3 -batch -noheader "${HISTDB_FILE}" < $PIPE >/dev/null &| - sysopen -w -o cloexec -u HISTDB_FD -- $PIPE - command rm $PIPE - zstat -A HISTDB_INODE +inode ${HISTDB_FILE} -} - -_histdb_query_batch () { - local CUR_INODE - zstat -A CUR_INODE +inode ${HISTDB_FILE} - if [[ $CUR_INODE != $HISTDB_INODE ]]; then - _histdb_stop_sqlite_pipe - _histdb_start_sqlite_pipe - fi - cat >&$HISTDB_FD - echo ';' >&$HISTDB_FD # make sure last command is executed -} - -_histdb_init () { - if [[ -n "${HISTDB_SESSION}" ]]; then - return - fi - - if ! [[ -e "${HISTDB_FILE}" ]]; then - local hist_dir="${HISTDB_FILE:h}" - if ! [[ -d "$hist_dir" ]]; then - mkdir -p -- "$hist_dir" - fi - _histdb_query <<-EOF -create table commands (id integer primary key autoincrement, argv text, unique(argv) on conflict ignore); -create table places (id integer primary key autoincrement, host text, dir text, unique(host, dir) on conflict ignore); -create table history (id integer primary key autoincrement, - session int, - command_id int references commands (id), - place_id int references places (id), - exit_status int, - start_time int, - duration int); -PRAGMA user_version = 2; -EOF - fi - if [[ -z "${HISTDB_SESSION}" ]]; then - ${HISTDB_INSTALLED_IN:h}/histdb-migrate "${HISTDB_FILE}" - HISTDB_HOST=${HISTDB_HOST:-"'$(sql_escape ${HOST})'"} - HISTDB_SESSION=$(_histdb_query "select 1+max(session) from history inner join places on places.id=history.place_id where places.host = ${HISTDB_HOST}") - HISTDB_SESSION="${HISTDB_SESSION:-0}" - readonly HISTDB_SESSION - fi - - _histdb_start_sqlite_pipe - _histdb_query_batch >/dev/null <<EOF -create index if not exists hist_time on history(start_time); -create index if not exists place_dir on places(dir); -create index if not exists place_host on places(host); -create index if not exists history_command_place on history(command_id, place_id); -PRAGMA journal_mode = WAL; -PRAGMA synchronous=normal; -EOF -} - -declare -ga _BORING_COMMANDS -_BORING_COMMANDS=("^ls$" "^cd$" "^ " "^histdb" "^top$" "^htop$") - -if [[ -z "${HISTDB_TABULATE_CMD[*]:-}" ]]; then - declare -ga HISTDB_TABULATE_CMD - HISTDB_TABULATE_CMD=(column -t -s $'\x1f') -fi - -_histdb_update_outcome () { - local retval=$? - local finished=$EPOCHSECONDS - [[ -z "${HISTDB_SESSION}" ]] && return - - _histdb_init - _histdb_query_batch <<EOF &| -update history set - exit_status = ${retval}, - duration = ${finished} - start_time -where id = (select max(id) from history) and - session = ${HISTDB_SESSION} and - exit_status is NULL; -EOF -} - -_histdb_addhistory () { - local cmd="${1[0, -2]}" - - if [[ -o histignorespace && "$cmd" =~ "^ " ]]; then - return 0 - fi - if [[ ${cmd} == ${~HISTORY_IGNORE} ]]; then - return 0 - fi - local boring - for boring in "${_BORING_COMMANDS[@]}"; do - if [[ "$cmd" =~ $boring ]]; then - return 0 - fi - done - - local cmd="'$(sql_escape $cmd)'" - local pwd="'$(sql_escape ${PWD})'" - local started=$EPOCHSECONDS - _histdb_init - - if [[ "$cmd" != "''" ]]; then - _histdb_query_batch <<EOF &| -insert into commands (argv) values (${cmd}); -insert into places (host, dir) values (${HISTDB_HOST}, ${pwd}); -insert into history - (session, command_id, place_id, start_time) -select - ${HISTDB_SESSION}, - commands.id, - places.id, - ${started} -from - commands, places -where - commands.argv = ${cmd} and - places.host = ${HISTDB_HOST} and - places.dir = ${pwd} -; -EOF - fi - return 0 -} - -add-zsh-hook zshaddhistory _histdb_addhistory -add-zsh-hook precmd _histdb_update_outcome - -histdb-top () { - _histdb_init - local sep=$'\x1f' - local field - local join - local table - 1=${1:-cmd} - case "$1" in - dir) - field=places.dir - join='places.id = history.place_id' - table=places - ;; - cmd) - field=commands.argv - join='commands.id = history.command_id' - table=commands - ;;; - esac - _histdb_query -separator "$sep" \ - -header \ - "select count(*) as count, places.host, replace($field, ' -', ' -$sep$sep') as ${1:-cmd} from history left join commands on history.command_id=commands.id left join places on history.place_id=places.id group by places.host, $field order by count(*)" | \ - "${HISTDB_TABULATE_CMD[@]}" -} - -histdb-sync () { - _histdb_init - - # this ought to apply to other readers? - echo "truncating WAL" - echo 'pragma wal_checkpoint(truncate);' | _histdb_query_batch - - local hist_dir="${HISTDB_FILE:h}" - if [[ -d "$hist_dir" ]]; then - () { - setopt local_options no_pushd_ignore_dups - - pushd -q "$hist_dir" - if [[ $(git rev-parse --is-inside-work-tree) != "true" ]] || [[ "$(git rev-parse --show-toplevel)" != "${PWD:A}" ]]; then - git init - git config merge.histdb.driver "${HISTDB_INSTALLED_IN:h}/histdb-merge %O %A %B" - echo "${HISTDB_FILE:t} merge=histdb" >>! .gitattributes - git add .gitattributes - git add "${HISTDB_FILE:t}" - fi - _histdb_stop_sqlite_pipe # Stop in case of a merge, starting again afterwards - git commit -am "history" && git pull --no-edit - _histdb_start_sqlite_pipe - popd -q - } - fi - - echo 'pragma wal_checkpoint(passive);' | _histdb_query_batch -} - -histdb () { - _histdb_init - local -a opts - local -a hosts - local -a indirs - local -a atdirs - local -a sessions - - zparseopts -E -D -a opts \ - -host+::=hosts \ - -in+::=indirs \ - -at+::=atdirs \ - -forget \ - -yes \ - -detail \ - -sep:- \ - -exact \ - d h -help \ - s+::=sessions \ - -from:- -until:- -limit:- \ - -status:- -desc - - local usage="usage:$0 terms [--desc] [--host[ x]] [--in[ x]] [--at] [-s n]+* [-d] [--detail] [--forget] [--yes] [--exact] [--sep x] [--from x] [--until x] [--limit n] [--status x] - --desc reverse sort order of results - --host print the host column and show all hosts (otherwise current host) - --host x find entries from host x - --in find only entries run in the current dir or below - --in x find only entries in directory x or below - --at like --in, but excluding subdirectories - -s n only show session n - -d debug output query that will be run - --detail show details - --forget forget everything which matches in the history - --yes don't ask for confirmation when forgetting - --exact don't match substrings - --sep x print with separator x, and don't tabulate - --from x only show commands after date x (sqlite date parser) - --until x only show commands before date x (sqlite date parser) - --limit n only show n rows. defaults to $LINES or 25 - --status x only show rows with exit status x. Can be 'error' to find all nonzero." - - local selcols="session as ses, dir" - local cols="session, replace(places.dir, '$HOME', '~') as dir" - local where="1" - if [[ -p /dev/stdout ]]; then - local limit="" - else - local limit="${$((LINES - 4)):-25}" - fi - - local forget="0" - local forget_accept=0 - local exact=0 - - if (( ${#hosts} )); then - local hostwhere="" - local host="" - for host ($hosts); do - host="${${host#--host}#=}" - hostwhere="${hostwhere}${host:+${hostwhere:+ or }places.host='$(sql_escape ${host})'}" - done - where="${where}${hostwhere:+ and (${hostwhere})}" - cols="${cols}, places.host as host" - selcols="${selcols}, host" - else - where="${where} and places.host=${HISTDB_HOST}" - fi - - if (( ${#indirs} + ${#atdirs} )); then - local dirwhere="" - local dir="" - for dir ($indirs); do - dir="${${${dir#--in}#=}:-$PWD}" - dirwhere="${dirwhere}${dirwhere:+ or }places.dir like '$(sql_escape $dir)%'" - done - for dir ($atdirs); do - dir="${${${dir#--at}#=}:-$PWD}" - dirwhere="${dirwhere}${dirwhere:+ or }places.dir = '$(sql_escape $dir)'" - done - where="${where}${dirwhere:+ and (${dirwhere})}" - fi - - if (( ${#sessions} )); then - local sin="" - local ses="" - for ses ($sessions); do - ses="${${${ses#-s}#=}:-${HISTDB_SESSION}}" - sin="${sin}${sin:+, }$ses" - done - where="${where}${sin:+ and session in ($sin)}" - fi - - local sep=$'\x1f' - local orderdir='asc' - local debug=0 - local opt="" - for opt ($opts); do - case $opt in - --desc) - orderdir='desc' - ;; - --sep*) - sep=${opt#--sep} - ;; - --from*) - local from=${opt#--from} - case $from in - -*) - from="datetime('now', '$from')" - ;; - today) - from="datetime('now', 'start of day')" - ;; - yesterday) - from="datetime('now', 'start of day', '-1 day')" - ;; - esac - where="${where} and datetime(start_time, 'unixepoch') >= $from" - ;; - --status*) - local xstatus=${opt#--status} - case $xstatus in - <->) - where="${where} and exit_status = $xstatus" - ;; - error) - where="${where} and exit_status <> 0" - ;; - esac - ;; - --until*) - local until=${opt#--until} - case $until in - -*) - until="datetime('now', '$until')" - ;; - today) - until="datetime('now', 'start of day')" - ;; - yesterday) - until="datetime('now', 'start of day', '-1 day')" - ;; - esac - where="${where} and datetime(start_time, 'unixepoch') <= $until" - ;; - -d) - debug=1 - ;; - --detail) - cols="${cols}, exit_status, duration " - selcols="${selcols}, exit_status as [?],duration as secs " - ;; - -h|--help) - echo "$usage" - return 0 - ;; - --forget) - forget=1 - ;; - --yes) - forget_accept=1 - ;; - --exact) - exact=1 - ;; - --limit*) - limit=${opt#--limit} - ;; - esac - done - - if [[ -n "$*" ]]; then - if [[ $exact -eq 0 ]]; then - where="${where} and commands.argv glob '*$(sql_escape $@)*'" - else - where="${where} and commands.argv = '$(sql_escape $@)'" - fi - fi - - if [[ $forget -gt 0 ]]; then - limit="" - fi - local seps=$(echo "$cols" | tr -c -d ',' | tr ',' $sep) - cols="${cols}, replace(commands.argv, ' -', ' -$seps') as argv, max(start_time) as max_start" - - local mst="datetime(max_start, 'unixepoch')" - local dst="datetime('now', 'start of day')" - local timecol="strftime(case when $mst > $dst then '%H:%M' else '%d/%m' end, max_start, 'unixepoch', 'localtime') as time" - - selcols="${timecol}, ${selcols}, argv as cmd" - - local r_order="asc" - if [[ $orderdir == "asc" ]]; then - r_order="desc" - fi - - local query="select ${selcols} from (select ${cols} -from - commands - join history on history.command_id = commands.id - join places on history.place_id = places.id -where ${where} -group by history.command_id, history.place_id -order by max_start ${r_order} -${limit:+limit $limit}) order by max_start ${orderdir}" - - ## min max date? - local count_query="select count(*) from (select ${cols} -from - commands - join history on history.command_id = commands.id - join places on history.place_id = places.id -where ${where} -group by history.command_id, history.place_id -order by max_start desc) order by max_start ${orderdir}" - - if [[ $debug = 1 ]]; then - echo "$query" - else - local count=$(_histdb_query "$count_query") - if [[ -p /dev/stdout ]]; then - buffer() { - ## this runs out of memory for big files I think perl -e 'local $/; my $stdin = <STDIN>; print $stdin;' - temp=$(mktemp) - cat >! "$temp" - cat -- "$temp" - rm -f -- "$temp" - } - else - buffer() { - cat - } - fi - if [[ $sep == $'\x1f' ]]; then - _histdb_query -header -separator $sep "$query" | iconv -f utf-8 -t utf-8 -c | buffer | "${HISTDB_TABULATE_CMD[@]}" - else - _histdb_query -header -separator $sep "$query" | buffer - fi - [[ -n $limit ]] && [[ $limit -lt $count ]] && echo "(showing $limit of $count results)" - fi - - if [[ $forget -gt 0 ]]; then - if [[ $forget_accept -gt 0 ]]; then - REPLY=y - else - read -q "REPLY?Forget all these results? [y/n] " - fi - if [[ $REPLY =~ "[yY]" ]]; then - _histdb_query "delete from history where -history.id in ( -select history.id from -history - left join commands on history.command_id = commands.id - left join places on history.place_id = places.id -where ${where})" - _histdb_query "delete from commands where commands.id not in (select distinct history.command_id from history)" - fi - fi -} diff --git a/modules/mixins/dotfiles/config/zsh/plugins/zsh-histdb/zsh-histdb.plugin.zsh b/modules/mixins/dotfiles/config/zsh/plugins/zsh-histdb/zsh-histdb.plugin.zsh @@ -1 +0,0 @@ -source ${0:A:h}/sqlite-history.zsh diff --git a/modules/mixins/dotfiles/default.nix b/modules/mixins/dotfiles/default.nix @@ -65,9 +65,21 @@ in { config = { home.file = (mkMapping ./home ".") - // (lib.mapAttrs (_: v: v // {executable = true;}) (mkMapping ./bin "bin/")); + // (lib.mapAttrs (_: v: v // {executable = true;}) (mkMapping ./bin "bin/")) + // { + # Fetched as a flake input, not vendored in-repo. + "bin/xpanes" = { + source = "${inputs.tmux-xpanes}/bin/xpanes"; + executable = true; + }; + }; - xdg.configFile = mkMapping ./config ""; + xdg.configFile = + (mkMapping ./config "") + // { + "zsh/plugins/zsh-autopair".source = inputs.zsh-autopair; + "zsh/plugins/zsh-histdb".source = inputs.zsh-histdb; + }; home.sessionPath = ["$HOME/bin"]; }; diff --git a/modules/mixins/dotfiles/home/vim/colors/tempus_rift.vim b/modules/mixins/dotfiles/home/vim/colors/tempus_rift.vim @@ -1,254 +0,0 @@ -" Name: Tempus Rift -" Description: Dark theme with a subdued palette on the green side of the spectrum (WCAG AA compliant) -" Author: Protesilaos Stavrou (https://protesilaos.com) -" Meta: Created with the Tempus Themes Generator -" URL: https://gitlab.com/protesilaos/tempus-themes-generator - -set background=dark -hi clear -if exists("syntax_on") - syntax reset -endif -let g:colors_name = "tempus_rift" - -" General -" ------- -if exists("g:tempus_enforce_background_color") - hi Normal guibg=#162c22 guifg=#bbbcbc ctermbg=0 ctermfg=15 -else - " NOTE the ctermbg=none is for terminals with transparency - hi Normal guibg=#162c22 guifg=#bbbcbc ctermbg=none ctermfg=15 -endif - -hi Visual guibg=#bbbcbc guifg=#162c22 ctermbg=15 ctermfg=0 -hi Search gui=underline,bold guibg=#283431 guifg=#bbbcbc cterm=underline,bold ctermbg=8 ctermfg=3 -hi IncSearch gui=underline,bold guibg=#ab9aa9 guifg=#162c22 term=none cterm=underline,bold ctermbg=7 ctermfg=0 - -hi StatusLine gui=none guibg=#bbbcbc guifg=#162c22 cterm=none ctermbg=15 ctermfg=0 -hi StatusLineNC gui=none guibg=#283431 guifg=#ab9aa9 cterm=none ctermbg=8 ctermfg=7 -hi StatusLineTerm gui=none guibg=#34b534 guifg=#162c22 cterm=none ctermbg=2 ctermfg=0 -hi StatusLineTermNC gui=none guibg=#283431 guifg=#34b534 cterm=none ctermbg=8 ctermfg=2 - -hi VertSplit gui=none cterm=none -hi TabLine gui=none guibg=#283431 guifg=#ab9aa9 cterm=none ctermbg=8 ctermfg=7 -hi TabLineSel gui=none guibg=#5fad8f guifg=#162c22 cterm=none ctermbg=6 ctermfg=0 -hi TabLineFill gui=none cterm=none - -hi Comment gui=italic guifg=#ab9aa9 cterm=none ctermfg=7 -hi Todo gui=bold guibg=#283431 guifg=#82bd00 cterm=bold ctermbg=8 ctermfg=11 - -hi Warning gui=none guibg=#7fad00 guifg=#162c22 cterm=none ctermbg=3 ctermfg=0 -hi WarningMsg gui=none guibg=#7fad00 guifg=#162c22 cterm=none ctermbg=3 ctermfg=0 -hi Error gui=none guibg=#c19904 guifg=#162c22 cterm=none ctermbg=1 ctermfg=0 -hi ErrorMsg gui=none guibg=#c19904 guifg=#162c22 cterm=none ctermbg=1 ctermfg=0 - -hi MatchParen gui=underline,bold guibg=#283431 guifg=#ab9aa9 cterm=underline,bold ctermbg=8 ctermfg=7 - -hi ToolbarLine guibg=#ab9aa9 guifg=#162c22 term=none ctermbg=7 ctermfg=0 -hi ToolbarButton gui=bold guibg=#ab9aa9 guifg=#162c22 term=none cterm=bold ctermbg=7 ctermfg=0 - -hi WildMenu guibg=#162c22 guifg=#bbbcbc term=standout ctermbg=0 ctermfg=15 - -hi Terminal guibg=#162c22 guifg=#bbbcbc term=none ctermbg=0 ctermfg=15 - -" Constructs -" ---------- -hi Constant guifg=#30aeb0 ctermfg=4 -hi Number guifg=#30aeb0 ctermfg=4 -hi Float guifg=#30aeb0 ctermfg=4 -hi String guifg=#56bdad ctermfg=12 - -hi Function guifg=#c8954c ctermfg=5 -hi Identifier guifg=#cca0ba term=none ctermfg=13 -hi Label guifg=#c8954c ctermfg=5 -hi Tag guifg=#c8954c ctermfg=5 -hi Keyword gui=bold guifg=#cca0ba gui=bold ctermfg=13 - -hi Character gui=bold guifg=#10c480 cterm=bold ctermfg=14 - -hi Type gui=none,bold guifg=#5fad8f term=none cterm=none,bold ctermfg=6 -hi Boolean guifg=#5fad8f ctermfg=6 -hi StorageClass guifg=#5fad8f ctermfg=6 -hi Structure guifg=#5fad8f ctermfg=6 -hi Typedef gui=bold guifg=#10c480 cterm=bold ctermfg=14 - -hi Conditional gui=bold guifg=#34b534 cterm=bold ctermfg=2 -hi Statement gui=none guifg=#6ac134 cterm=none ctermfg=10 -hi Repeat gui=bold guifg=#6ac134 cterm=bold ctermfg=10 -hi Operator gui=bold guifg=#bbbcbc cterm=bold ctermfg=15 -hi Exception gui=bold guifg=#c19904 cterm=bold ctermfg=1 - -hi Preproc gui=none guifg=#d2a634 term=none cterm=none ctermfg=9 -hi PreCondit gui=bold guifg=#d2a634 cterm=bold ctermfg=9 -hi Macro gui=bold guifg=#d2a634 cterm=bold ctermfg=9 -hi Include guifg=#d2a634 ctermfg=9 -hi Define guifg=#d2a634 ctermfg=9 - -hi Title gui=bold guibg=#162c22 guifg=#5fad8f cterm=bold ctermbg=0 ctermfg=6 - -hi Delimeter gui=bold guifg=#c8954c cterm=bold ctermfg=5 -hi Delimiter gui=bold guifg=#c8954c cterm=bold ctermfg=5 -hi SpecialComment gui=bold guifg=#c8954c cterm=bold ctermfg=5 - -hi Debug guifg=#cca0ba ctermfg=13 - -" Other -" ----- -hi LineNr guibg=#283431 guifg=#ab9aa9 term=none ctermbg=8 ctermfg=7 -hi Cursor guibg=#bbbcbc guifg=#162c22 ctermbg=15 ctermfg=0 -hi CursorLine gui=none guibg=#283431 term=none cterm=none ctermbg=8 -hi CursorColumn gui=none guibg=#283431 term=none cterm=none ctermbg=8 -hi CursorLineNr gui=bold guibg=#ab9aa9 guifg=#162c22 cterm=bold ctermbg=7 ctermfg=0 -hi ColorColumn guibg=#283431 guifg=#bbbcbc term=none ctermbg=8 ctermfg=15 -hi SignColumn guibg=#283431 guifg=#ab9aa9 term=none ctermbg=8 ctermfg=7 - -hi Folded guibg=#283431 guifg=#ab9aa9 ctermbg=8 ctermfg=7 -hi FoldColumn guibg=#283431 guifg=#ab9aa9 ctermbg=8 ctermfg=7 - -hi Special gui=bold guifg=#82bd00 term=none cterm=bold ctermfg=11 -hi SpecialKey gui=none guibg=#283431 guifg=#ab9aa9 cterm=none ctermbg=8 ctermfg=7 -hi SpecialChar gui=bold guifg=#82bd00 cterm=bold ctermfg=11 -hi NonText gui=none guibg=#283431 guifg=#ab9aa9 cterm=none ctermbg=8 ctermfg=7 -hi EndOfBuffer gui=bold guifg=#ab9aa9 cterm=bold ctermfg=7 - -hi Directory gui=none guifg=#34b534 term=none cterm=none ctermfg=2 -hi Question gui=bold guifg=#82bd00 cterm=bold ctermfg=11 -hi MoreMsg guifg=#6ac134 ctermfg=10 -hi ModeMsg gui=bold guifg=#34b534 cterm=bold ctermfg=2 - -hi VimOption guifg=#c8954c ctermfg=5 -hi VimGroup guifg=#c8954c ctermfg=5 - -hi Underlined gui=underline guifg=#bbbcbc cterm=underline ctermfg=15 -hi Ignore guibg=#283431 guifg=#ab9aa9 ctermbg=8 ctermfg=7 -hi Conceal guibg=#ab9aa9 guifg=#283431 ctermbg=7 ctermfg=8 - -hi SpellBad guibg=#c19904 guifg=#162c22 ctermbg=1 ctermfg=0 -hi SpellCap guibg=#7fad00 guifg=#162c22 ctermbg=3 ctermfg=0 -hi SpellRare guibg=#cca0ba guifg=#162c22 ctermbg=13 ctermfg=0 -hi SpellLocal guibg=#10c480 guifg=#162c22 ctermbg=14 ctermfg=0 - -hi Pmenu gui=italic guibg=#283431 guifg=#bbbcbc cterm=none ctermbg=8 ctermfg=15 -hi PmenuSel gui=none,bold guibg=#ab9aa9 guifg=#162c22 cterm=none,bold ctermbg=7 ctermfg=0 -hi PmenuSbar guibg=#283431 ctermbg=8 -hi PmenuThumb guibg=#ab9aa9 ctermbg=7 - -" Terminal -" -------- - -if exists('*term_setansicolors') - let g:terminal_ansi_colors = [ - \ "#162c22", - \ "#c19904", - \ "#34b534", - \ "#7fad00", - \ "#30aeb0", - \ "#c8954c", - \ "#5fad8f", - \ "#ab9aa9", - \ "#283431", - \ "#d2a634", - \ "#6ac134", - \ "#82bd00", - \ "#56bdad", - \ "#cca0ba", - \ "#10c480", - \ "#bbbcbc" - \ ] -endif -if has('nvim') - let g:terminal_color_0 = "#162c22" - let g:terminal_color_1 = "#c19904" - let g:terminal_color_2 = "#34b534" - let g:terminal_color_3 = "#7fad00" - let g:terminal_color_4 = "#30aeb0" - let g:terminal_color_5 = "#c8954c" - let g:terminal_color_6 = "#5fad8f" - let g:terminal_color_7 = "#ab9aa9" - let g:terminal_color_8 = "#283431" - let g:terminal_color_9 = "#d2a634" - let g:terminal_color_10 = "#6ac134" - let g:terminal_color_11 = "#82bd00" - let g:terminal_color_12 = "#56bdad" - let g:terminal_color_13 = "#cca0ba" - let g:terminal_color_14 = "#10c480" - let g:terminal_color_15 = "#bbbcbc" -endif - -" Diffs -" ----- -hi DiffAdd gui=bold guibg=#34b534 guifg=#162c22 cterm=bold ctermbg=10 ctermfg=0 -hi DiffDelete gui=none guibg=#c19904 guifg=#162c22 cterm=none ctermbg=9 ctermfg=0 -hi DiffChange gui=bold guibg=#283431 guifg=#ab9aa9 cterm=bold ctermbg=8 ctermfg=7 -hi DiffText gui=bold guibg=#283431 guifg=#d2a634 cterm=bold ctermbg=8 ctermfg=1 - -hi diffAdded guifg=#34b534 ctermfg=2 -hi diffRemoved guifg=#c19904 ctermfg=1 -hi diffNewFile gui=none guifg=#30aeb0 ctermfg=4 -hi diffFile gui=none guifg=#7fad00 cterm=none ctermfg=3 - -hi GitGutterAdd guibg=#283431 guifg=#34b534 ctermbg=8 ctermfg=2 -hi GitGutterChange gui=bold guibg=#283431 guifg=#ab9aa9 cterm=bold ctermbg=8 ctermfg=7 -hi GitGutterDelete guibg=#283431 guifg=#c19904 ctermbg=8 ctermfg=1 -hi GitGutterChangeDelete gui=bold guibg=#283431 guifg=#c19904 cterm=bold ctermbg=8 ctermfg=1 - -" Neomake -" ------- -hi NeomakeError gui=none guibg=#c19904 guifg=#162c22 cterm=none ctermbg=1 ctermfg=0 -hi NeomakeInfo gui=none guibg=#5fad8f guifg=#162c22 cterm=none ctermbg=6 ctermfg=0 -hi NeomakeWarning gui=none guibg=#7fad00 guifg=#162c22 cterm=none ctermbg=3 ctermfg=0 -hi NeomakeMessage gui=none guibg=#82bd00 guifg=#162c22 cterm=none ctermbg=11 ctermfg=0 - -hi NeomakeVirtualtextInfoDefault guifg=#10c480 ctermfg=14 -hi NeomakeVirtualtextMessageDefault guifg=#82bd00 ctermfg=11 -hi NeomakeVirtualtextWarningDefault guifg=#7fad00 ctermfg=3 -hi NeomakeVirtualtextErrorDefault guifg=#c19904 ctermfg=1 - -hi NeomakeStatusGood gui=none guibg=#34b534 guifg=#162c22 cterm=none ctermbg=2 ctermfg=0 -hi NeomakeStatusGoodNC gui=none guibg=#283431 guifg=#34b534 cterm=none ctermbg=8 ctermfg=2 - -hi NeomakeStatColorDefault gui=none guibg=#30aeb0 guifg=#162c22 cterm=none ctermbg=4 ctermfg=0 -hi NeomakeStatColorTypeE gui=none guibg=#c19904 guifg=#162c22 cterm=none ctermbg=1 ctermfg=0 -hi NeomakeStatColorTypeW gui=none guibg=#7fad00 guifg=#162c22 cterm=none ctermbg=3 ctermfg=0 - -" Markdown -" -------- -hi MarkdownRule gui=bold guibg=#283431 guifg=#6ac134 cterm=bold ctermbg=8 ctermfg=10 - -hi MarkdownHeading gui=bold guifg=#bbbcbc cterm=bold ctermfg=15 -hi default link MarkdownH1 MarkdownHeading -hi default link MarkdownH2 MarkdownHeading -hi default link MarkdownH3 MarkdownHeading -hi default link MarkdownH4 MarkdownHeading -hi default link MarkdownH5 MarkdownHeading -hi default link MarkdownH6 MarkdownHeading -hi default link MarkdownHeadingDelimiter MarkdownHeading -hi default link MarkdownHeadingRule MarkdownHeading - -hi MarkdownBold gui=bold guifg=#d2a634 cterm=bold ctermfg=9 -hi default link MarkdownBoldDelimiter MarkdownBold - -hi MarkdownItalic gui=italic guifg=#7fad00 cterm=none ctermfg=3 -hi default link MarkdownItalicDelimiter MarkdownItalic - -hi MarkdownUrl gui=underline guifg=#30aeb0 cterm=underline ctermfg=4 -hi MarkdownLinkText gui=none guifg=#56bdad cterm=none ctermfg=12 -hi MarkdownLinkDelimiter gui=bold guifg=#bbbcbc cterm=bold ctermfg=15 -hi default link MarkdownLinkTextDelimiter MarkdownLinkDelimiter - -hi MarkdownCode guifg=#c8954c ctermfg=5 -hi default link MarkdownCodeDelimiter MarkdownCode - -hi MarkdownCodeBlock guifg=#bbbcbc ctermfg=15 - -hi MarkdownListMarker gui=none guifg=#34b534 cterm=none ctermfg=2 -hi default link MarkdownOrderedListMarker MarkdownListMarker - -" Linting -" ------- -hi YcmErrorSection gui=undercurl guisp=#c19904 cterm=underline -hi YcmWarningSection gui=undercurl guisp=#7fad00 cterm=underline -hi SyntasticError gui=undercurl guisp=#c19904 cterm=underline -hi SyntasticWarning gui=undercurl guisp=#7fad00 cterm=underline -hi SyntasticErrorSing guifg=#162c22 guibg=#c19904 ctermfg=0 ctermbg=1 -hi SyntasticWarningSign guifg=#162c22 guibg=#7fad00 ctermfg=0 ctermbg=3 diff --git a/modules/mixins/dotfiles/home/vimrc b/modules/mixins/dotfiles/home/vimrc @@ -3,8 +3,6 @@ exe "set runtimepath=~/.vim," . $VIMRUNTIME filetype plugin on syntax on -silent! colorscheme tempus_rift - set autoindent set backspace=indent,eol,start set backupcopy=yes