7 Commits

Author SHA1 Message Date
426e97c10e feat(riot): sshl supports specifying local port and unix sock 2025-12-19 17:34:37 +08:00
e1f0ec0ebc fix(tmux): press ^a twice to send ^a 2025-11-20 20:22:17 +08:00
8dbb310e02 fix(zshrc): bnd exit when build error 2025-11-17 01:45:53 +08:00
8865dee1e9 feat: add bnd and nor and completions 2025-11-15 14:48:19 +08:00
65d690f47c build(riot-config): nasp.fit -> jump.nasp.fit 2025-10-28 17:18:56 +08:00
ecf652ad7b feat(riot): command git 2025-07-24 16:28:37 +08:00
86670306af feat(riot): support literal ipv6 addresses (with or without ports given)
feat(riot): -v, -4, and -6

fix(riot): do not call external binaries if possible
2025-07-16 21:09:04 +08:00
7 changed files with 100 additions and 23 deletions

View File

@@ -1,4 +1,5 @@
set -g prefix ^a
bind ^a send-prefix
set -g mouse on
set -g set-clipboard on
set -g default-terminal "xterm-256color"

27
.zshrc2
View File

@@ -9,6 +9,7 @@ else
fi
export DOTFILES=$( cd "$( dirname "${BASH_SOURCE[0]:-${(%):-%x}}" )" && pwd )
export PATH="$PATH:$DOTFILES/scripts"
fpath=($DOTFILES/functions $fpath)
export EDITOR='vim'
# env for apps
export PYTHONIOENCODING='UTF-8'
@@ -130,9 +131,29 @@ alias "jcf"='jc -f'
alias "jcfu"='jc -fu'
alias "sc"='systemctl'
alias "t"='tmux'
gbes() { git for-each-ref --sort=-committerdate refs/heads refs/remotes --format="%(authordate:format:%y-%m-%d.%a %H:%M %z)|%(color:red)%(objectname:short)|%(color:yellow)%(refname:short)%(color:reset)|%(color:reset)%(authorname): %(color:green)%(subject)" --color=always | column -ts"|" | less -FX }
sagt() { eval "$($DOTFILES/tools/sagent.sh $@)" }
use() { nix --experimental-features nix-command --extra-experimental-features flakes shell "${(*)@/#%(#b)([^#]#)/nixpkgs#$match}" }
gbes() { git for-each-ref --sort=-committerdate refs/heads refs/remotes --format="%(authordate:format:%y-%m-%d.%a %H:%M %z)|%(color:red)%(objectname:short)|%(color:yellow)%(refname:short)%(color:reset)|%(color:reset)%(authorname): %(color:green)%(subject)" --color=always | column -ts"|" | less -FX ; }
sagt() { eval "$($DOTFILES/tools/sagent.sh $@)" ; }
## nixos
use() { nix --experimental-features nix-command --extra-experimental-features flakes shell "${(*)@/#%(#b)([^#]#)/nixpkgs#$match}" ; }
bnd() {
if [[ -n "$1" && -d "./hosts/$1" ]]; then
nixos-rebuild --flake .#$1 build || return $?
nix-diff /opt/NixOS-Config/results/hosts/$1 ./result --color=always | less
else
echo host $1 does not exist
fi
}
nor() {
test -n "$1" || { echo fatal: no verb given; return 1; }
nixos-rebuild "$1" --flake .${2:+#}$2
}
alias 'nors'='nor switch'
alias 'norbt'='nor boot'
alias 'nort'='nor test'
alias 'norb'='nor build'
alias 'nordb'='nor dry-build'
alias 'norda'='nor dry-activate'
# key bindings
bindkey "^b" beginning-of-line # ctrl+b

View File

@@ -0,0 +1,3 @@
#compdef bnd nor
compadd -- /root/NixOS-Config/hosts/*(/:t)

3
functions/_sagt Normal file
View File

@@ -0,0 +1,3 @@
#compdef sagt
compadd -- kill ls op piv reset

3
functions/_use Normal file
View File

@@ -0,0 +1,3 @@
#compdef use
compadd -- $(nix eval --impure --expr 'builtins.attrNames ( (import <nixpkgs>) {} )' 2>/dev/null | tr '[]"' ' ')

View File

@@ -25,7 +25,7 @@ nasps.batch() {
# remotes
nasp.remote() {
remote=nasp.fit
remote=jump.nasp.fit
RET_PORT=${RET_PORT:-36022}
RET_USERNAME=${RET_USERNAME:-root}
RET_TRUST_SERVER=1
@@ -60,7 +60,7 @@ nasp.domain() {
RET_HOSTNAME=$host
RET_PORT=${RET_PORT:-12022}
RET_USERNAME=${RET_USERNAME:-root}
RET_JUMP_SERVER="ssh@nasp.fit:36022"
RET_JUMP_SERVER="ssh@jump.nasp.fit:36022"
RET_TRUST_SERVER=1
}

View File

@@ -20,14 +20,14 @@ done
# check if port number valid
check_port() {
( echo $1 | grep -qxE "[1-9][0-9]{0,4}" ) || return 1
test $1 -lt 65536 -a $1 -gt 0 || return 1
[[ "$1" =~ ^[1-9][0-9]{0,4}$ ]] || return 1
[[ $1 < 65536 && $1 > 0 ]] || return 1
return 0
}
# check if username valid
check_username() {
( echo $1 | grep -qxE "^[a-z][-a-z0-9_]*\$" ) || return 1
[[ "$1" =~ ^[a-z][-a-z0-9_]*$ ]] || return 1
return 0
}
@@ -42,18 +42,28 @@ get_server_meta() {
RET_JUMP_SERVER="" # optional
# body
local remote="$1"
# if in the form user@...
# extract username from user@...
if [[ "$remote" == *@* ]]; then
RET_USERNAME=${remote%%@*}
remote=${remote#*@}
check_username $RET_USERNAME || fmt_warning \"$RET_USERNAME\" is not a valid unix username
fi
# if in the form ...:22
if [[ "$remote" == "["*"]":* || ( "$remote" != "["*"]" && "$remote" == *:* ) ]]; then
# extract port from ...:port
if [[
"$remote" =~ ^[^:]+:[1-9][0-9]*$ # contains only one colon
|| "$remote" =~ ^\[.+\]:[1-9][0-9]*$ # in the form of [host]:port
|| "$remote" =~ :::[1-9][0-9]*$ # in the form of :::port
|| "$remote" =~ ^([0-9a-f]{1,4}:){7}[0-9a-f]{1,4}:[1-9][0-9]*$ # full ipv6 address with port
|| "$remote" =~ ^[0-9a-f:]+%.+:[1-9][0-9]*$ # ipv6 address with scope and port
]]; then
RET_PORT=${remote##*:}
remote=${remote%:*}
check_port $RET_PORT || fmt_fatal invalid port number \"$RET_PORT\"
fi
# remove square brackets
if [[ "$remote" =~ ^\[.*\]$ ]]; then
remote=${remote:1:-1}
fi
# presets -- match remote
local remote_func="$remote.remote"
if is_function "$remote_func"; then
@@ -63,8 +73,8 @@ get_server_meta() {
RET_HOSTNAME=${remote}
local domain=${remote##*.}
local host=${remote%.*}
# if there's no dot
if [[ "$host" == "$domain" && "$host" != "["*"]" ]]; then
# if it contains no dot and is not ipv6
if [[ "$remote" != *.* && "$remote" != *:* ]]; then
domain="default"
fi
local domain_func="$domain.domain"
@@ -125,7 +135,7 @@ parse_remote() {
print_cmd() {
local output=""
for s in "${CMD[@]}"; do
if [[ "$s" =~ [\ \\\'\"] ]]; then
if [[ "$s" =~ [\ \\\'\"] ]]; then # needs to be escaped
s="${s@Q}"
fi
output+="$s "
@@ -185,16 +195,35 @@ run_ssh()
# sshl
run_sshl()
{
local arg="$1"
if [[ "$arg" != *":"* ]]; then
# treat as a port number
arg=localhost:$arg
is_port() {
if [[ "$1" =~ ^[1-9][0-9]*$ && $1 -gt 1 && $1 -lt 65535 ]]; then return 0; else return 1; fi
}
res="${1//[^:]}"
if [[ ${#res} -eq 2 ]]; then
arg="$1"
elif [[ ${#res} -eq 0 ]]; then
arg="$(get_free_port):localhost:$1"
else
left=${1%%:*}
right=${1##*:}
if is_port "$left"; then
arg="$1"
elif is_port "$right"; then
arg="$(get_free_port):$1"
else
arg="$1"
localsock=1
fi
fi
local port=$(get_free_port)
SSH_OPTIONS+=("-NC" "-L" "$port:$arg")
if [[ "$localsock" == "1" ]]; then
access="unix://${arg%%:*}"
else
access="localhost:${arg%%:*}"
fi
SSH_OPTIONS+=("-NC" "-L" "$arg")
prepare_ssh_cmd ssh
print_cmd
fmt_note " > please access localhost:$port"
fmt_note " > please access $access"
eval_or_echo
}
@@ -259,11 +288,12 @@ remove_hostkey() {
# main
print_help()
{
fmt_info "usage: $0 [-Ddhlqt] [--dry-run] [--dev] [--help] [--lite] [--quite] [--trust] [--tmux] [--password] [[-o ssh-option]...] remote [command] [--] [ssh-command-args]"
fmt_info "usage: $0 [-Ddhlqt] [--dry-run] [--dev] [--help] [--lite] [--quite] [--trust] [--tmux] [--password] [[-o ssh-option]...] remote [command] [--] [command-args]"
cat <<EOF
available commands:
- ssh [ssh-command-args] (default)
- tmux [ssh-command-args] (run ssh in multiple tmux windows)
- git [git-command-args] (run git on remote machine)
- sshl [local-port:remote-host:]remote-port (ssh -L)
- sshd [local-port] (ssh -D)
- zssh [ssh-command-args]
@@ -295,13 +325,22 @@ router() {
EXTRA_SSH_OPTIONS+=("-o" "$2")
shift
;;
-4 )
EXTRA_SSH_OPTIONS+=("-4")
;;
-6 )
EXTRA_SSH_OPTIONS+=("-6")
;;
-v )
EXTRA_SSH_OPTIONS+=("-v")
;;
-- )
shift
positional+=("$@")
break
;;
-* )
fmt_fatal "unknown option: $1"
fmt_fatal "unknown option: '$1'. if this option is for the remote command, add '--' before."
;;
* )
positional+=("$1")
@@ -328,6 +367,13 @@ router() {
[[ "${positional[1]}" == tmux ]] && USE_TMUX=1
run_ssh ssh "${positional[@]:2}"
;;
git )
if printf '%s\0' "${positional[@]:2}" | grep -Fxqz -- '-C'; then
run_ssh ssh git "${positional[@]:2}"
else
run_ssh ssh git -C "$(pwd)" "${positional[@]:2}"
fi
;;
ping|ping4|ping6 )
test "${#positional[@]}" -eq 2 || fmt_fatal "ping requires no arguments"
run_ping "${positional[1]}"