diff options
Diffstat (limited to 'Omni/Ide')
-rwxr-xr-x | Omni/Ide/MakeTags.py | 105 | ||||
-rwxr-xr-x | Omni/Ide/ftags.sh | 21 | ||||
-rwxr-xr-x | Omni/Ide/hoog.sh | 17 | ||||
-rwxr-xr-x | Omni/Ide/hooks/commit-msg | 7 | ||||
-rwxr-xr-x | Omni/Ide/hooks/post-applypatch | 6 | ||||
-rwxr-xr-x | Omni/Ide/hooks/post-checkout | 20 | ||||
-rwxr-xr-x | Omni/Ide/hooks/post-commit | 6 | ||||
-rwxr-xr-x | Omni/Ide/hooks/post-merge | 6 | ||||
-rwxr-xr-x | Omni/Ide/hooks/post-rewrite | 6 | ||||
-rwxr-xr-x | Omni/Ide/hooks/pre-auto-gc | 6 | ||||
-rwxr-xr-x | Omni/Ide/hooks/pre-commit | 21 | ||||
-rwxr-xr-x | Omni/Ide/hooks/pre-push | 22 | ||||
-rwxr-xr-x | Omni/Ide/hooks/reference-transaction | 12 | ||||
-rwxr-xr-x | Omni/Ide/ns.sh | 50 | ||||
-rwxr-xr-x | Omni/Ide/push.sh | 20 | ||||
-rwxr-xr-x | Omni/Ide/repl.sh | 84 | ||||
-rwxr-xr-x | Omni/Ide/run.sh | 6 | ||||
-rwxr-xr-x | Omni/Ide/ship.sh | 25 | ||||
-rwxr-xr-x | Omni/Ide/tips.sh | 12 | ||||
-rwxr-xr-x | Omni/Ide/version.sh | 15 |
20 files changed, 467 insertions, 0 deletions
diff --git a/Omni/Ide/MakeTags.py b/Omni/Ide/MakeTags.py new file mode 100755 index 0000000..add07c0 --- /dev/null +++ b/Omni/Ide/MakeTags.py @@ -0,0 +1,105 @@ +#!/usr/bin/env python +""" +Make tags for internal or external code. + +This should run fast, and be executable with just Python, meaning it does not +require a build step. +""" + +# : out maketags +# : run universal-ctags +import argparse +import os +import pathlib +import subprocess +import tarfile +import zipfile + + +def main() -> None: + """Run ctags on internal or external source code. + + Raises: + ValueError: if CODEROOT is not set + ArgumentError: when explicit paths aren't provided + """ + coderoot = os.environ.get("CODEROOT") + if coderoot is None: + msg = "CODEROOT not set" + raise ValueError(msg) + cabsrc = pathlib.Path(coderoot) / "_" / "src" + cli = argparse.ArgumentParser() + cli.add_argument( + "paths", + nargs="*", + default=".", + help="List of paths to run ctags on. Defaults to '.'", + ) + cli.add_argument( + "-x", + "--external", + action="store_true", + help=" ".join([ + "Use this when `paths` is a list of external packages,", + f"they will be extracted or linked into {cabsrc}", + ]), + ) + args = cli.parse_args() + if args.external and args.paths == ".": + msg = "requires explicit paths" + raise argparse.ArgumentError(argument=args.external, message=msg) + if args.external: + extract_and_copy(cabsrc, args.paths) + ctags(["--recurse=yes"], cwd=cabsrc) + else: + ctags(["--exclude=*_/*", "--recurse=yes"], cwd=pathlib.Path(coderoot)) + + +def strip_nix_hash(path: str) -> str: + """Remove the /nix/store/ and hash prefix from a path.""" + hash_len = 33 + return path.removeprefix("/nix/store/")[hash_len:] + + +def extract_and_copy(cabsrc: pathlib.Path, paths: list[str]) -> None: + """ + Extract and copy or link sources. + + Loop over `paths`, if the path is an archive, extract it into `cabsrc`. If + its a directory, just symlink the directory into `cabsrc`. Either way, we + end up with a directory full of source trees for running ctags on. + """ + for path in paths: + outpath: pathlib.Path = cabsrc / strip_nix_hash(path) + if outpath.exists(): + continue + if path.endswith(".zip"): + out = outpath.with_suffix("") + if out.exists(): + continue + zipfile.ZipFile(path).extractall(out) # noqa: S202 + elif path.endswith(".tar.gz"): + out = outpath.with_suffix("").with_suffix("") + if out.exists(): + continue + with tarfile.open(path) as tarball: + tarball.extractall(out) # noqa: S202 + elif pathlib.Path(path).is_dir(): + outpath.symlink_to(path) + + +def ctags(args: list[str], cwd: pathlib.Path = pathlib.Path()) -> None: + """Call `ctags` with `args` for both emacs and vim.""" + os.chdir(cwd) + excludes = [ + "--exclude=.mypy_cache", + "--exclude=.git", + "--exclude=.direnv", + "--exclude=.ruff_cache", + ] + subprocess.check_call(["ctags", *excludes, *args]) + subprocess.check_call(["ctags", "-e", *excludes, *args]) + + +if __name__ == "__main__": + main() diff --git a/Omni/Ide/ftags.sh b/Omni/Ide/ftags.sh new file mode 100755 index 0000000..b29d994 --- /dev/null +++ b/Omni/Ide/ftags.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +# +# search tags with fzf +# + set -euo pipefail + tags=${CODEROOT:?}/tags + tag_search=$( + awk 'BEGIN { FS="\t" } !/^!/ {print toupper($4)"\t"$1"\t"$2"\t"$3}' "$tags" \ + | cut -c1-80 \ + | fzf-tmux \ + --nth=1,2 \ + --preview-window=down,border-none \ + --bind="pgdn:preview-page-down" \ + --bind="pgup:preview-page-up" \ + --preview "rg --pretty --context 2 --fixed-strings --regexp {+2}" + ) + ${EDITOR:-vim} \ + "$(cut -f3 <<< "$tag_search")" \ + -c "set nocst" \ + -c "silent tag $(cut -f2 <<< "$tag_search")" +## diff --git a/Omni/Ide/hoog.sh b/Omni/Ide/hoog.sh new file mode 100755 index 0000000..237eb78 --- /dev/null +++ b/Omni/Ide/hoog.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +# +# search hoogle with fzf +# + set -euo pipefail + HOOG="hoogle search --count=200" + export FZF_DEFAULT_COMMAND="$HOOG $*" + result=$(fzf-tmux \ + --preview-window=down,border-none \ + --preview "hoogle search --link --info {+2}" \ + --bind "change:reload:$HOOG {q} || true" \ + --ansi \ + | cut -d' ' -f 1,2 \ + | sed -e 's/ /./g' + ) + hoogle search --info "$result" +## diff --git a/Omni/Ide/hooks/commit-msg b/Omni/Ide/hooks/commit-msg new file mode 100755 index 0000000..e07d1f4 --- /dev/null +++ b/Omni/Ide/hooks/commit-msg @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +if ! gitlint --ignore-stdin --staged --msg-filename "$1" run-hook; then + backup="$CODEROOT"/.git/COMMIT_EDITMSG.backup + cp "$CODEROOT"/.git/COMMIT_EDITMSG "$backup" + echo "error: gitlint failed, saved your commit msg as $backup" + exit 1 +fi diff --git a/Omni/Ide/hooks/post-applypatch b/Omni/Ide/hooks/post-applypatch new file mode 100755 index 0000000..5071dc5 --- /dev/null +++ b/Omni/Ide/hooks/post-applypatch @@ -0,0 +1,6 @@ +#!/bin/sh +## START BRANCHLESS CONFIG + +git branchless hook post-applypatch "$@" + +## END BRANCHLESS CONFIG diff --git a/Omni/Ide/hooks/post-checkout b/Omni/Ide/hooks/post-checkout new file mode 100755 index 0000000..85541a2 --- /dev/null +++ b/Omni/Ide/hooks/post-checkout @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +set -e +function MakeTags { + ${CODEROOT:?}/Omni/Ide/MakeTags.py +} +old=$1 +new=$2 +# filter out only the changed haskell files +mapfile -t changed < <(git diff --diff-filter=d --name-only "$old" "$new" -- '*.hs') +if [[ ! -r tags ]] || [[ ! -r TAGS ]] +then + MakeTags "$CODEROOT"/**/* +elif [[ ${#changed[@]} -gt 0 ]] +then + MakeTags "${changed[@]}" +fi +## START BRANCHLESS CONFIG + +git branchless hook post-checkout "$@" +## END BRANCHLESS CONFIG diff --git a/Omni/Ide/hooks/post-commit b/Omni/Ide/hooks/post-commit new file mode 100755 index 0000000..cd1f195 --- /dev/null +++ b/Omni/Ide/hooks/post-commit @@ -0,0 +1,6 @@ +#!/bin/sh +## START BRANCHLESS CONFIG + +git branchless hook post-commit "$@" + +## END BRANCHLESS CONFIG diff --git a/Omni/Ide/hooks/post-merge b/Omni/Ide/hooks/post-merge new file mode 100755 index 0000000..fcfd314 --- /dev/null +++ b/Omni/Ide/hooks/post-merge @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +"${CODEROOT:?}"/Omni/Ide/hooks/post-checkout 'HEAD@{1}' HEAD +## START BRANCHLESS CONFIG + +git branchless hook post-merge "$@" +## END BRANCHLESS CONFIG diff --git a/Omni/Ide/hooks/post-rewrite b/Omni/Ide/hooks/post-rewrite new file mode 100755 index 0000000..8b3237a --- /dev/null +++ b/Omni/Ide/hooks/post-rewrite @@ -0,0 +1,6 @@ +#!/bin/sh +## START BRANCHLESS CONFIG + +git branchless hook post-rewrite "$@" + +## END BRANCHLESS CONFIG diff --git a/Omni/Ide/hooks/pre-auto-gc b/Omni/Ide/hooks/pre-auto-gc new file mode 100755 index 0000000..c92a844 --- /dev/null +++ b/Omni/Ide/hooks/pre-auto-gc @@ -0,0 +1,6 @@ +#!/bin/sh +## START BRANCHLESS CONFIG + +git branchless hook pre-auto-gc "$@" + +## END BRANCHLESS CONFIG diff --git a/Omni/Ide/hooks/pre-commit b/Omni/Ide/hooks/pre-commit new file mode 100755 index 0000000..06f1716 --- /dev/null +++ b/Omni/Ide/hooks/pre-commit @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +# +# - prevent frozen code from being checked in +# - guard against lint errors +## + set -e + mapfile -t changed < <(git diff-index --cached --name-only HEAD) + for ns in "${changed[@]}" + do + version=$("${CODEROOT:?}"/Omni/Ide/version.sh "$ns") + if [[ $version -eq -1 ]]; then + echo "info: version: $ns: deleted" + elif [[ $version -lt 1 ]]; then + echo "fail: version: $ns: $version" + exit 1 + else + echo "info: version: $ns: $version" + fi + done + lint "${changed[@]}" +## diff --git a/Omni/Ide/hooks/pre-push b/Omni/Ide/hooks/pre-push new file mode 100755 index 0000000..00110bd --- /dev/null +++ b/Omni/Ide/hooks/pre-push @@ -0,0 +1,22 @@ +#!/usr/bin/env bash +set -euo pipefail +remote="$1" +z40=0000000000000000000000000000000000000000 +IFS=" " +while read local_ref local_sha remote_ref remote_sha +do + if [ "$local_sha" = $z40 ] + then + # delete, do nothing + continue + elif [ "$remote_sha" = $z40 ] + then + # new branch, test all commits since ci was implemented + range="11d95581fb178a5d21e88dfd8030a61886cc2519..$local_sha" + else + range="$remote_sha..$local_sha" + fi +done +gitlint --commits "$range" lint +git test run --command ci "$range" +git push "$remote" refs/notes/ci --no-verify diff --git a/Omni/Ide/hooks/reference-transaction b/Omni/Ide/hooks/reference-transaction new file mode 100755 index 0000000..ea0cce6 --- /dev/null +++ b/Omni/Ide/hooks/reference-transaction @@ -0,0 +1,12 @@ +#!/bin/sh +## START BRANCHLESS CONFIG + +# Avoid canceling the reference transaction in the case that `branchless` fails +# for whatever reason. +git branchless hook reference-transaction "$@" || ( +echo 'branchless: Failed to process reference transaction!' +echo 'branchless: Some events (e.g. branch updates) may have been lost.' +echo 'branchless: This is a bug. Please report it.' +) + +## END BRANCHLESS CONFIG diff --git a/Omni/Ide/ns.sh b/Omni/Ide/ns.sh new file mode 100755 index 0000000..a56ed89 --- /dev/null +++ b/Omni/Ide/ns.sh @@ -0,0 +1,50 @@ +#!/usr/bin/env bash +set -euo pipefail +nss="fd --color=always --exclude=_ -t f . \"${CODEROOT:?}\" | sed \"s,${CODEROOT:?}/*,,g\"" +keybindings=$(cat <<EOF +repl {}:enter +repl --bash {}:alt+enter +edit {} with $EDITOR:tab +lint -f {}:alt+c +bild {}:alt+space +bild --test {}:alt+t +exec {}:alt+e +ship {}:ctrl+space +create new namespace:alt+n +change preview window:alt+0-6 +resize preview window:ctrl+/ +EOF +) +fzf_flags=( + --ansi + --bind "focus:transform-preview-label:echo {}" + --bind "?:change-preview(column -o ' -> ' -s':' -t <<< \"$keybindings\")" + --bind "alt-n:execute(touch {q})+reload($nss)" + --bind "alt-space:execute(bild {} ; read -p [fin])" + --bind "tab:execute($EDITOR {})" + --bind "alt-c:execute(lint -f {} ; read -p [fin])" + --bind "enter:execute(repl.sh {})" + --bind "alt-enter:execute(repl.sh --bash {})" + --bind "ctrl-space:execute(ship.sh {} ; read -p [fin])" + --bind "alt-t:execute(bild {} ; run.sh {} test ; read -p [fin])" + --bind "ctrl-/:change-preview-window(right,88|right,70%|hidden|)" + --bind "alt-0:change-preview(bat -p --color=always {})" + --bind "alt-1:change-preview(git log --color=always --date=relative --abbrev-commit --pretty=format:'%Cred%h%Creset %s / %an %Creset%C(yellow)%d%Creset%Cgreen(%cr)%Creset' -- {})" + --bind "alt-2:change-preview(git log --color=always {})" + --bind "alt-3:change-preview(git log --color=always -p {})" + --bind "alt-4:change-preview(git blame -c --date=short {})" + --bind "alt-5:change-preview(git log --pretty=short {} | git shortlog -nse)" + --bind "alt-6:change-preview(git log --pretty=short {} | git shortlog)" + --bind "backward-eof:abort" + --bind "pgup:preview-page-up" + --bind "pgdn:preview-page-down" + --header-first + --header="? for keybindings" + --border=top + --border-label="$(lolcat -f <<< "hack a namespace")" + --color=label:italic + --preview-window="bottom,80%" + --preview "bat -p --color=always {}" +) +sh -c "$nss" | fzf "${fzf_flags[@]}" + diff --git a/Omni/Ide/push.sh b/Omni/Ide/push.sh new file mode 100755 index 0000000..43dff28 --- /dev/null +++ b/Omni/Ide/push.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +# Eventually convert to haskell, see: +# - https://github.com/awakesecurity/nix-deploy/blob/master/src/Main.hs +# - http://www.haskellforall.com/2018/08/nixos-in-production.html +prefix=${PWD/$CODEROOT} +if [[ "$prefix" == "" ]] +then + target="$1" +else + target="$prefix.$1" +fi +what=$(realpath "${CODEROOT:?}/_/nix/$target") +# hack: get the domain from the systemd service. there does not seem to be a way +# to get it from nix-instantiate. (or, maybe i should put this in bild --plan?) +where=$(rg --only-matching --replace '$2' --regexp '(domainname ")(.*)(")' \ + "$what/etc/systemd/system/domainname.service") +nix copy --to ssh://"$USER"@"$where" "$what" +ssh "$USER"@"$where" sudo "$what"/bin/switch-to-configuration switch +ssh "$USER"@"$where" sudo nix-env --profile /nix/var/nix/profiles/system --set "$what" +echo "${GRN}good: push: $target${NC}" diff --git a/Omni/Ide/repl.sh b/Omni/Ide/repl.sh new file mode 100755 index 0000000..3b6a536 --- /dev/null +++ b/Omni/Ide/repl.sh @@ -0,0 +1,84 @@ +#!/usr/bin/env bash +### +### a simple complement to bild which only deals with launching repls +### +### > repl [opts] <target..> +### +### Starts a repl/shell for one or more targets. (Currently, all targets must +### have the same extension for this to work.) Repls started with this script +### should bind to `localhost:$PORT`. +### +### Options: +### --bash start bash instead of the target language repl +help() { + sed -rn 's/^### ?//;T;p' "$0" +} +if [[ $# == 0 ]] || [[ "$1" == "-h" ]]; then + help + exit 1 +fi +## + set -e + CMD= + if [[ "$1" == "--bash" ]]; then + CMD="bash" + shift + fi + targets="${*:?}" + json=$(bild --plan "${targets[@]}") + mapfile -t langdeps < <(jq --raw-output '.[].langdeps | select(length > 0) | join("\n")' <<< "$json") + mapfile -t sysdeps < <(jq --raw-output '.[].sysdeps | select(length > 0) | join("\n")' <<< "$json") + mapfile -t rundeps < <(jq --raw-output '.[].rundeps | select(length > 0) | join("\n")' <<< "$json") + exts=$(jq --raw-output '.[].namespace.ext' <<< "$json" | sort | uniq) + packageSet=$(jq --raw-output '.[].packageSet' <<< "$json") + module=$(jq --raw-output '.[].mainModule' <<< "$json") + BILD="(import ${CODEROOT:?}/Omni/Bild.nix {})" + declare -a flags=(--packages "$BILD.pkgs.pkg-config") + for lib in "${sysdeps[@]}"; do + flags+=(--packages "$BILD.pkgs.${lib}") + done + for lib in "${rundeps[@]}"; do + flags+=(--packages "$BILD.pkgs.${lib}") + done + case $exts in + C) + flags+=(--packages "$BILD.pkgs.gcc") + command="bash" + ;; + Hs) + if [ -z ${var+PORT} ]; then + echo "warn: repl: ghci does not support binding to a port" + fi + flags+=(--packages "$BILD.haskell.ghcWith (h: with h; [${langdeps[*]}])") + command=${CMD:-"ghci -i${CODEROOT:?} -ghci-script ${CODEROOT:?}/.ghci ${targets[@]}"} + ;; + Scm) + for lib in "${langdeps[@]}"; do + flags+=(--packages "$BILD.guile-${lib}") + done + flags+=(--packages "$BILD.guile") + command=${CMD:-"guile -L ${CODEROOT:?} -C ${CODEROOT:?}/_/int --r7rs --listen=${PORT:-37146}"} + ;; + Lisp) + flags+=(--packages "$BILD.$packageSet (p: with p; [asdf swank ${langdeps[*]}])") + command=${CMD:-"sbcl --eval '(require :asdf)' --eval '(require :swank)' --eval '(swank:create-server :port ${PORT:-4005})' --load $targets"} + ;; + Rs) + flags+=(--packages "$BILD.pkgs.rustc") + command=bash + ;; + Py) + langdeps+=("mypy") + flags+=(--packages "$BILD.python.pythonWith (p: with p; [${langdeps[*]}])") + PYTHONPATH=$CODEROOT:$PYTHONPATH + pycommand="python -i $CODEROOT/Omni/Repl.py $module ${targets[*]}" + command=${CMD:-"$pycommand"} + ;; + *) + echo "unsupported targets: ${targets[*]}" + exit 1 + ;; + esac +## + nix-shell "${flags[@]}" --command "$command" --show-trace +## diff --git a/Omni/Ide/run.sh b/Omni/Ide/run.sh new file mode 100755 index 0000000..506aa92 --- /dev/null +++ b/Omni/Ide/run.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +set -eu +target=$1 +shift +out=$(bild --plan "$target" | jq --raw-output ".\"${target}\".out") +exec "${CODEROOT:?}/_/bin/$out" "$@" diff --git a/Omni/Ide/ship.sh b/Omni/Ide/ship.sh new file mode 100755 index 0000000..8783e9b --- /dev/null +++ b/Omni/Ide/ship.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash +# +# ship <target>... +# +# lint, bild, test, and push one or more targets. if no targets are supplied, +# ship everything we know how to ship +## + set -eu + stuff=("${@}") + if [[ ${#stuff[@]} -eq 0 ]] + then + mapfile -t stuff < <(fd -t l . "$CODEROOT/_/nix/" \ + | sed "s,$CODEROOT/_/nix/,,g" \ + | fzf --multi --prompt="ship _/nix/" \ + --preview="file $CODEROOT/_/nix/{}" \ + --preview-window=bottom,wrap + ) + fi + lint "${stuff[@]}" + bild --test "${stuff[@]}" + for thing in "${stuff[@]}" + do + push.sh "$thing" + done +## diff --git a/Omni/Ide/tips.sh b/Omni/Ide/tips.sh new file mode 100755 index 0000000..453e464 --- /dev/null +++ b/Omni/Ide/tips.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +echo "" +echo "omnidev" | figlet | lolcat +echo "" +echo " bild compile code" +echo " repl.sh start a repl" +echo " deps manage dependencies with niv" +echo " tips.sh show this message" +echo " lint auto-lint all changed files" +echo " push.sh send a namespace to the cloud" +echo " ship.sh lint, bild, and push one (or all) namespace(s)" +echo "" diff --git a/Omni/Ide/version.sh b/Omni/Ide/version.sh new file mode 100755 index 0000000..60f9c91 --- /dev/null +++ b/Omni/Ide/version.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +# +# simple implementation of kelvin versioning +## + ns=$1 + if [[ -e "$1" ]]; then + commits=$(git log --oneline --follow "$ns" | wc -l) + # gold melts at 1337 kelvin, so we start with this + # bc we are forging gold here + version=$(bc -l <<< "1337 - $commits") + echo "$version" + else + echo -1 # signal that file doesn't exist + fi +## |