diff options
Diffstat (limited to 'build/latex/letter')
-rw-r--r-- | build/latex/letter/%INIT_APPLICATION_NAME.tex | 86 | ||||
-rw-r--r-- | build/latex/letter/.envrc | 9 | ||||
-rw-r--r-- | build/latex/letter/.gitignore | 8 | ||||
-rw-r--r-- | build/latex/letter/.reuse/templates/default.jinja2 | 1 | ||||
-rw-r--r-- | build/latex/letter/README.md | 11 | ||||
-rwxr-xr-x | build/latex/letter/build.sh | 14 | ||||
-rw-r--r-- | build/latex/letter/cog.toml | 24 | ||||
-rw-r--r-- | build/latex/letter/flake.lock | 129 | ||||
-rw-r--r-- | build/latex/letter/flake.nix | 100 | ||||
-rw-r--r-- | build/latex/letter/init | 152 | ||||
-rwxr-xr-x | build/latex/letter/scripts/cprh.sh | 57 | ||||
-rwxr-xr-x | build/latex/letter/scripts/extract_text_from_all.sh | 8 | ||||
-rw-r--r-- | build/latex/letter/shell_line_editor.sh | 247 | ||||
-rw-r--r-- | build/latex/letter/treefmt.nix | 70 | ||||
-rwxr-xr-x | build/latex/letter/update.sh | 3 | ||||
-rwxr-xr-x | build/latex/letter/watch.sh | 70 |
16 files changed, 989 insertions, 0 deletions
diff --git a/build/latex/letter/%INIT_APPLICATION_NAME.tex b/build/latex/letter/%INIT_APPLICATION_NAME.tex new file mode 100644 index 0000000..2037aa6 --- /dev/null +++ b/build/latex/letter/%INIT_APPLICATION_NAME.tex @@ -0,0 +1,86 @@ +% LTeX: language=%INIT_LANGUAGE +\documentclass[a4paper, version=last]{scrlttr2} +\usepackage{lmodern} +\usepackage[utf8]{inputenc} +\usepackage[T1]{fontenc} +\usepackage[%INIT_BABLE_LANGUAGE]{babel} +\usepackage{url} +\usepackage[%INIT_DATE_TIME_LANGUAGE, showdow]{datetime2} % make handling dates easier + +\setkomafont{fromname}{\sffamily \LARGE} +\setkomafont{fromaddress}{\sffamily}%% statt \small +\setkomafont{pagenumber}{\sffamily} +\setkomafont{subject}{\bfseries} +\setkomafont{backaddress}{\mdseries} + +\LoadLetterOption{DIN} +% \setkomavar{backaddressseparator}{\enspace\textperiodcentered\enspace} +% \setkomavar{backaddress}{%INIT_AUTHOR_NAME\\ PO Box 8421\\ Bachbrecht\\10007\\ Namibia} +\setkomavar{backaddressseparator}{ $\cdot$ } +\setkomavar{customer}{2342} +\setkomavar{date}{\DTMToday} +\setkomavar{enclseparator}{: } +\setkomavar{fromaddress}{Musterstraße 00\\00000 Musterort} +\setkomavar{fromemail}{%INIT_AUTHOR_EMAIL} +\setkomavar{fromname}{%INIT_AUTHOR_NAME} +\setkomavar{fromphone}{+49 0000 00\,00\,00\,0} +\setkomavar{place}{Musterort} +\setkomavar{signature}{%INIT_AUTHOR_NAME} +\setkomavar{subject}{%INIT_APPLICATION_NAME_STYLIZED} + +\renewcommand*{\raggedsignature}{\raggedright} + +\KOMAoptions{% + addrfield=true, % Adress field for envelope with window + backaddress=true, % Sender address in this window + enlargefirstpage=true, % More space on first page + foldmarks=true, % Print foldmarks? + footsepline=true, % separate the footer with a line on page >1 + fromalign=center, % alignment of the address + % fromalign=right, % Placement of name in letter head + fromemail=true, % print sender e-mail address + fromfax=false, % print sender fax number + fromlogo=false, % print a logo (position depends on fromalign) + fromphone=true, % print sender phone number + fromrule=afteraddress, % separate the address with a line? + % fromrule=aftername, % Rule after sender name in letter head + fromurl=false, % print sender URL + headsepline=true, % separate the header with a line on page >1 + locfield=narrow, % Additional field for sender + pagenumber=botright, % position of the page number (see docu) + paper=a4, % pagesize + parskip=half, % Use indent instead of skip + refline=wide, % layout of the refline + subject=beforeopening, % Placement of subject +} + +\begin{document} + +\begin{letter}{Director \\ Doe \& Co \\ 35 Anthony Road \\ Newport \\ Ipswich IP3 5RT} + \opening{Dear Sir or Madam,} + + I am writing to you on behalf of the Wikipedia project + (\url{http://www.wikipedia.org/}), an endeavour to build a + fully-fledged multilingual encyclopaedia in an entirely open + manner, to ask for permission to use your copyrighted material. + + \ldots + + That said, allow me to reiterate that your material will be used + to the noble end of providing a free collection of knowledge for + everyone; naturally enough, only if you agree. If that is the + case, could you kindly fill in the attached form and post it back + to me? We shall greatly appreciate it. + + Thank you for your time and consideration. + + I look forward to your reply. + + \closing{Yours Faithfully,} + \ps{P.S. You can find the full text of GFDL license at + \url{http://www.gnu.org/copyleft/fdl.html}.} + \encl{Copyright permission form} + +\end{letter} + +\end{document} diff --git a/build/latex/letter/.envrc b/build/latex/letter/.envrc new file mode 100644 index 0000000..3bc1085 --- /dev/null +++ b/build/latex/letter/.envrc @@ -0,0 +1,9 @@ +use flake || use nix +watch_file flake.nix + +PATH_add ./scripts + +if on_git_branch; then + echo && git status --short --branch && + echo && git fetch --verbose +fi diff --git a/build/latex/letter/.gitignore b/build/latex/letter/.gitignore new file mode 100644 index 0000000..539b891 --- /dev/null +++ b/build/latex/letter/.gitignore @@ -0,0 +1,8 @@ +# build +/result +/build + +/resources.local + +# dev env +.direnv diff --git a/build/latex/letter/.reuse/templates/default.jinja2 b/build/latex/letter/.reuse/templates/default.jinja2 new file mode 100644 index 0000000..7a2d08f --- /dev/null +++ b/build/latex/letter/.reuse/templates/default.jinja2 @@ -0,0 +1 @@ +<!-- This file will be replaced by the init script --> diff --git a/build/latex/letter/README.md b/build/latex/letter/README.md new file mode 100644 index 0000000..9c5c6da --- /dev/null +++ b/build/latex/letter/README.md @@ -0,0 +1,11 @@ +# %INIT_APPLICATION_NAME_STYLIZED + +> %INIT_DESCRIPTION + +## Licensing +This project complies with the REUSE v3.2 specification. This means that every file +clearly states its copyright. +Please run `./scripts/cprh.sh contributer NAME EMAIL FILES..` after you +contributed to `FILES..` to record your contribution (obviously replacing +the `NAME`, `EMAIL` and `FILES..` placeholders with your name, email, and +the paths to the changed files respectively (see the `--help` output for more)). diff --git a/build/latex/letter/build.sh b/build/latex/letter/build.sh new file mode 100755 index 0000000..1206ee7 --- /dev/null +++ b/build/latex/letter/build.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env sh + +# if no parameter is given, use 'dst' as destination directory +if [ -z "$1" ]; then + dst=build +else + dst="$1" +fi + +# find all directories which are not the destination dir or inside it +find . -type d -not -name "$dst" -not -path "./$dst/*" -printf '%P\n' | while IFS= read -r dir; do + mkdir --parents "$dst/$dir" +done +latexmk -outdir="$dst" -file-line-error -pdflatex -recorder "./%INIT_APPLICATION_NAME.tex" diff --git a/build/latex/letter/cog.toml b/build/latex/letter/cog.toml new file mode 100644 index 0000000..ccca764 --- /dev/null +++ b/build/latex/letter/cog.toml @@ -0,0 +1,24 @@ +tag_prefix = "v" +branch_whitelist = ["main", "prime"] +ignore_merge_commits = false + +pre_bump_hooks = [ + "nix flake check", # verify the project builds + "./scripts/renew_copyright_header.sh", # update the license header in each file + "flake_version_update --version v{{version}} --input-file flake.nix", # update the version in the flake.nix file + "nix fmt", # format +] +post_bump_hooks = [ + "git push", + "git push origin v{{version}}", # push the new tag to origin +] + +[bump_profiles] + +[changelog] +path = "NEWS.md" +template = "remote" +remote = "%INIT_REMOTE" +repository = "%INIT_REPOSITORY" +owner = "%INIT_OWNER" +authors = [{ signature = "%INIT_AUTHOR_NAME", username = "%INIT_OWNER" }] diff --git a/build/latex/letter/flake.lock b/build/latex/letter/flake.lock new file mode 100644 index 0000000..544cbdf --- /dev/null +++ b/build/latex/letter/flake.lock @@ -0,0 +1,129 @@ +{ + "nodes": { + "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1696426674, + "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-utils": { + "inputs": { + "systems": [ + "systems" + ] + }, + "locked": { + "lastModified": 1710146030, + "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flake_version_update": { + "inputs": { + "flake-utils": [ + "flake-utils" + ], + "nixpkgs": [ + "nixpkgs" + ], + "systems": [ + "systems" + ] + }, + "locked": { + "lastModified": 1685288691, + "narHash": "sha256-oP6h34oJ8rm6KlUpyZrX+ww3hnoWny2ecrEXxkU7F3c=", + "ref": "refs/heads/prime", + "rev": "e9a97e01eca780bd16e1dbdbd8856b59558f4959", + "revCount": 5, + "type": "git", + "url": "https://codeberg.org/soispha/flake_version_update.git" + }, + "original": { + "type": "git", + "url": "https://codeberg.org/soispha/flake_version_update.git" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1711715736, + "narHash": "sha256-9slQ609YqT9bT/MNX9+5k5jltL9zgpn36DpFB7TkttM=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "807c549feabce7eddbf259dbdcec9e0600a0660d", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-compat": "flake-compat", + "flake-utils": "flake-utils", + "flake_version_update": "flake_version_update", + "nixpkgs": "nixpkgs", + "systems": "systems", + "treefmt-nix": "treefmt-nix" + } + }, + "systems": { + "locked": { + "lastModified": 1680978846, + "narHash": "sha256-Gtqg8b/v49BFDpDetjclCYXm8mAnTrUzR0JnE2nv5aw=", + "owner": "nix-systems", + "repo": "x86_64-linux", + "rev": "2ecfcac5e15790ba6ce360ceccddb15ad16d08a8", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "x86_64-linux", + "type": "github" + } + }, + "treefmt-nix": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1711803027, + "narHash": "sha256-Qic3OvsVLpetchzaIe2hJqgliWXACq2Oee6mBXa/IZQ=", + "owner": "numtide", + "repo": "treefmt-nix", + "rev": "1810d51a015c1730f2fe05a255258649799df416", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "treefmt-nix", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/build/latex/letter/flake.nix b/build/latex/letter/flake.nix new file mode 100644 index 0000000..4847a9c --- /dev/null +++ b/build/latex/letter/flake.nix @@ -0,0 +1,100 @@ +{ + description = "%INIT_DESCRIPTION"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; + + treefmt-nix = { + url = "github:numtide/treefmt-nix"; + inputs = { + nixpkgs.follows = "nixpkgs"; + }; + }; + flake_version_update = { + url = "git+https://codeberg.org/soispha/flake_version_update.git"; + inputs = { + systems.follows = "systems"; + nixpkgs.follows = "nixpkgs"; + flake-utils.follows = "flake-utils"; + }; + }; + + # inputs for following + systems = { + url = "github:nix-systems/x86_64-linux"; # only evaluate for this system + }; + flake-compat = { + url = "github:edolstra/flake-compat"; + flake = false; + }; + flake-utils = { + url = "github:numtide/flake-utils"; + inputs = { + systems.follows = "systems"; + }; + }; + }; + + outputs = { + self, + nixpkgs, + flake-utils, + treefmt-nix, + flake_version_update, + ... + }: + flake-utils.lib.eachDefaultSystem (system: let + pkgs = nixpkgs.legacyPackages.${system}; + + # This version is set automatically on `cog bump --auto`; + version = "v%INIT_APPLICATION_VERSION"; # GUIDING VERSION STRING + + # TODO reduce to the needed ones + texlive = pkgs.texlive.combined.scheme-full; + + treefmtEval = import ./treefmt.nix {inherit treefmt-nix pkgs;}; + + build = pkgs.stdenv.mkDerivation { + pname = "%INIT_APPLICATION_NAME"; + inherit version; + src = ./.; + + buildInputs = [ + texlive + ]; + + # Run local + preferLocalBuild = true; + allowSubstitutes = false; + + buildPhase = '' + # TODO: I have no idea, why calling it with `./build.sh` does not work <2024-03-20> + bash ./build.sh + ''; + + installPhase = '' + install -D ./build/main.pdf "$out/%INIT_APPLICATION_NAME.pdf"; + ''; + }; + in { + packages.default = build; + + checks = { + inherit build; + formatting = treefmtEval.config.build.check self; + }; + + formatter = treefmtEval.config.build.wrapper; + + devShells.default = pkgs.mkShell { + packages = with pkgs; [ + cocogitto + reuse + flake_version_update.packages."${system}".default + texlive + + zathura + ]; + }; + }); +} diff --git a/build/latex/letter/init b/build/latex/letter/init new file mode 100644 index 0000000..1ea1603 --- /dev/null +++ b/build/latex/letter/init @@ -0,0 +1,152 @@ +#!/usr/bin/env sh + +# shellcheck source=/dev/null +. "$(realpath "$(dirname "$0")")/shell_line_editor.sh" + +replacement_file="$(mktemp)" + +trap cleanup INT +trap "cleanup; remove_self" EXIT +cleanup() { + rm "$replacement_file" +} +remove_self() { + rm "$(realpath "$0")" + rm "$(realpath "$(dirname "$0")")/shell_line_editor.sh" +} +require() { + program="$1" + if ! command -v "$program" >/dev/null; then + echo "Please install '$program' for this init script to work." 1>&2 + exit 1 + fi +} + +# Prompt the user for a specific variable. +# ## Args: +# [1]: Name of the variable to populate the answer to +# [2]: An optional description +# [3]: An optionally suggested answer +# [4]: If this is set, the user is not even asked. +prompt() { + pr_variable_upper="$(echo "$1" | sed 's/\([a-z]\)/\U\1/')" + pr_description="$2" + pr_suggested_answer="$3" + pr_ask="$4" + + if [ -n "$pr_ask" ]; then + REPLY="$pr_suggested_answer" + else + printf "\033[94;1mEnter %s\033[0m" "$pr_variable_upper" + if [ -n "$pr_description" ]; then + printf " (\033[93;1m%s\033[0m):\n" "$pr_description" + else + printf ":\n" + fi + + # LE "> " 0 " " "$pr_suggested_answer" "yes_please_produce_debug_output" + LE "> " 0 " " "$pr_suggested_answer" "" + fi + + pr_new_variable="$(printf '%s="%s"' "$pr_variable_upper" "$REPLY")" + + eval "$pr_new_variable" + printf "%s\n" "$pr_new_variable" >>"$replacement_file" +} + +require git + +require jq +require curl + +require fd +require mv +require sed +require chmod + +git init + +# necessary meta data +prompt APPLICATION_NAME "The name of the application" "$(basename "$PWD")" +prompt APPLICATION_NAME_STYLIZED "The stylized name of the application (for documentation)" "$(echo "$APPLICATION_NAME" | sed 's/[_-]/ /g' | sed 's/^\(\w\)/\U\1/g' | sed 's/ \(\w\)/ \U\1/g')" +prompt APPLICATION_NAME_CAPITALIZED_MAN_PART "The capitalized name of the application (for documentation also with a man section part)" "$(echo "$APPLICATION_NAME" | sed 's/_/-/g' | sed 's/\(.*\)/\U\1(1)/')" "dont_ask" +prompt APPLICATION_VERSION "The version of this program, without the prefix" "0.1.0" + +prompt AUTHOR_NAME "The name of the author (or authors)" "$(git config --get user.name)" +prompt AUTHOR_EMAIL "The email of the author (or authors)" "$(git config --get user.email)" + +# cog change-log variables +prompt REMOTE "The remote, this project will be pushed to" "git.vhack.eu" +prompt REPOSITORY "The path of the repository on the remote" "$APPLICATION_NAME" +prompt OWNER "The name of owner of the repository" "$AUTHOR_NAME" + +# nice meta data +prompt DESCRIPTION "The description of this project" "" +prompt CURRENT_DATE "The stylized version of the current date" "$(date +'%b %Y')" +prompt YEAR "The year the work on this has begun (for copyright reasons)" "$(date +'%Y')" +prompt APPLICATION_SOURCE_CODE_REPOSITORY "The package's source code repository URL" "https://$REMOTE/$OWNER/$REPOSITORY" +prompt HOME_PAGE "The home page URL of the project" "https://$REPOSITORY.org/" +prompt BUG_URL "The URL people should report bugs to" "$APPLICATION_SOURCE_CODE_REPOSITORY/issues" + +if [ -e ./lpm.toml ]; then + # Use a different default license in latex projects. + init_default_license="CC-BY-SA-4.0" +else + init_default_license="AGPL-3.0-or-later" +fi +prompt SPDX_LICENSE_IDENTIFIER "THE SPDX identifer of your choosen license" "$init_default_license" + +default_license_url="$(curl --silent --show-error "https://spdx.org/licenses/$SPDX_LICENSE_IDENTIFIER.json" | jq --raw-output '.seeAlso[0]')" + +# Prefer possible text versions of the license +if curl --fail --silent --show-error "$default_license_url.txt" >/dev/null; then + default_license_url="$default_license_url.txt" +fi +prompt LICENSE_URL "The url of the license" "$default_license_url" + +if [ -e ./.reuse/templates/default.jinja2 ]; then + cat <<EOF | fmt --uniform-spacing --width=75 >./.reuse/templates/default.jinja2 +{% for copyright_line in copyright_lines %} +{{ copyright_line }} +{% endfor %} +{% for contributor_line in contributor_lines %} +SPDX-FileContributor: {{ contributor_line }} +{% endfor %} +{% for expression in spdx_expressions %} +SPDX-License-Identifier: {{ expression }} +{% endfor %} + +This file is part of $APPLICATION_NAME_STYLIZED - $DESCRIPTION. + +You should have received a copy of the License along with this program. +If not, see <$LICENSE_URL>. +<!-- vim: ft=htmldjango --> +EOF +fi + +# Allow templates to add template specific prompts +[ -e init.local ] && . ./init.local + +echo "$DESCRIPTION" >.git/description + +while read -r var; do + var_name="${var%=*}" + var_value="${var#*=\"}" + var_value="${var_value%\"}" + + fd . --hidden --type file --exec sed --in-place "s|%\bINIT_$var_name\b|$var_value|g" + + # Replace the variable in file paths + fd "%INIT_$var_name" . --hidden | while read -r file_path; do + new_file_path="$(echo "$file_path" | sed "s|%INIT_$var_name|$var_value|g")" + mv "$file_path" "$new_file_path" + done +done <"$replacement_file" + +# HACK: Re-add the executable permissions to files, which the nix template has somehow +# removed <2024-04-02> +chmod +x scripts/* +chmod +x update.sh +[ -f ./build.sh ] && chmod +x build.sh + +# vim: ft=sh diff --git a/build/latex/letter/scripts/cprh.sh b/build/latex/letter/scripts/cprh.sh new file mode 100755 index 0000000..9582575 --- /dev/null +++ b/build/latex/letter/scripts/cprh.sh @@ -0,0 +1,57 @@ +#! /usr/bin/env sh + +die() { + echo "$@" 1>&2 + exit 1 +} + +help() { + cat <<EOF +A copyright header managment tool. + +USAGE: + cprh.sh [OPTIONS] contribute NAME EMAIL FILE.. + +OPTIONS: + --help | -h + Display this help and exit. + +ARGUMENTS: + NAME := [[git config user.name]] + Your name. + + NAME := [[git config user.email]] + Your email address. + + FILE := [[git diff --name-only --cached]] + The file you want to change. This can be given multiple times. +EOF +} + +for arg in "$@"; do + case "$arg" in + "--help" | "-h") + help + exit 0 + ;; + *) + echo "'$1' is not a recognized option. See --help for more!" 1>&2 + exit 1 + ;; + esac +done + +user_name="$1" +[ -z "$user_name" ] && die "No NAME set! See --help for more" + +user_email="$2" +[ -z "$user_email" ] && die "No EMAIL set! See --help for more" +shift 2 + +styleOne="" +styleTwo="" +[ "$COMMENT_STYLE" ] && styleOne="--style" && styleTwo="$COMMENT_STYLE" + +# The styleTwo must be unquoted to avoid adding empty args to reuse +# shellcheck disable=2086 +reuse annotate --copyright "$user_name <$user_email>" --copyright-prefix string-c --template default --multi-line $styleOne $styleTwo diff --git a/build/latex/letter/scripts/extract_text_from_all.sh b/build/latex/letter/scripts/extract_text_from_all.sh new file mode 100755 index 0000000..11b2ac4 --- /dev/null +++ b/build/latex/letter/scripts/extract_text_from_all.sh @@ -0,0 +1,8 @@ +#! /usr/bin/env sh + +grep 'INPUT ./' ./build/main.fls | uniq | sed 's/INPUT //' | while read -r file; do + if ! [ "$(basename "$file")" = preamble.tex ] && ! [ "$(basename "$file")" = gymnasium.png ]; then + printf "\n%% Filename: %s\n" "$file" + grep -v '^\s*%' "$file" + fi +done diff --git a/build/latex/letter/shell_line_editor.sh b/build/latex/letter/shell_line_editor.sh new file mode 100644 index 0000000..8d6833a --- /dev/null +++ b/build/latex/letter/shell_line_editor.sh @@ -0,0 +1,247 @@ +#! /usr/bin/env sh +# Taken in verbatim from: https://unix.stackexchange.com/a/113450, and somewhat changed + +LE_print_debug() { + LE_debug="$1" + LE_debug_msg="$2" + [ -n "$LE_debug" ] && printf "\nDBG: (%s)\n" "$LE_debug_msg" >outfile.debug +} + +LE() { + # Shell Line Editor. Extremely slow and stupid code. However it + # should work on ansi/vt100/linux derived terminals on POSIX + # systems. + # Understands some emacs key bindings: CTRL-(A,B,D,E,F,H,K,L) + # plus the CTRL-W and CTRL-U normal killword and kill. + # no Meta-X key, but handling of <Left>, <Right>, <Home>, <End> + # <Suppr>. + # + # Args: + # [1]: prompt (\x sequences recognized, defaults to "") + # [2]: max input length (unlimited if < 0, (default)) + # [3]: fill character when erasing (defaults to space) + # [4]: initial value. + # [5]: whether to output debugfiles (outfile.debug and outfile.raw.debug) + # Returns: + # 0: OK + # 1: od(d) error or CTRL-C hit + + LE_prompt="$1" + LE_max=${2--1} + LE_fill=${3-" "} + LE_debug="$5" + + LE_backward() { + LE_substract="$1" + while [ -n "$LE_substract" ]; do + printf '\b%s' "$2" + LE_substract=${LE_substract%?} + done + } + + LE_fill() { + LE_substract="$1" + while [ -n "$LE_substract" ]; do + printf '%s' "$LE_fill" + LE_substract=${LE_substract%?} + done + } + + # Used but not right now + # shellcheck disable=2016 + LE_restore='stty "$LE_tty" + LC_COLLATE='${LC_COLLATE-"; unset LC_COLLATE"} + + # LE_tty is used in the restore above + # shellcheck disable=2034 + LE_ret=1 LE_tty=$(stty -g) LC_COLLATE=C + + # text on the right of the cursor + LE_left=$4 + # text on the left of the cursor + LE_right='' + + # Tell the terminal to show us every char inputted + stty -icanon -echo -isig min 3 time 1 -istrip + printf '%b%s' "$LE_prompt" "$LE_left" + + # clear the output + [ -n "$LE_debug" ] && printf "" >outfile.debug + [ -n "$LE_debug" ] && printf "" >outfile.raw.debug + + # The value needs to be split for it to work (and it's either way just numbers) + # shellcheck disable=2046 + while set -- $(dd bs=3 count=1 2>/dev/null | od -vAn -to1); do + while [ "$#" -gt 0 ]; do + [ -n "$LE_debug" ] && printf "%b" "\0$1" >>outfile.debug + [ -n "$LE_debug" ] && printf "%s " "$1" >>outfile.raw.debug + LE_current_key=$1 + shift + + # 033 is ^[ (`printf "\\$1\n" | cat -v`) + if [ "$LE_current_key" = 033 ]; then + case "$1$2$3" in + # [ C | O C -> ^F forward + 133103* | 117103*) + shift 2 + LE_current_key=006 + ;; + # [ D | O D -> ^B backward + 133104* | 117104*) + shift 2 + LE_current_key=002 + ;; + # [ H | O H -> ^A beginning of line + 133110* | 117110*) + shift 2 + LE_current_key=001 + ;; + # [ P | O P -> ^D del char + 133120* | 117120*) + shift 2 + LE_current_key=004 + ;; + # [ F | O F -> ^E end of line + 133106* | 117106*) + shift 2 + LE_current_key=005 + ;; + # [ 1 ~ -> ^A beginning of line + 133061176) + shift 3 + LE_current_key=001 + ;; + # [ 4 ~ -> ^E end of line + 133064176) + shift 3 + LE_current_key=005 + ;; + # [ 3 ~ -> ^D del char + 133063176) + shift 3 + LE_current_key=004 + ;; + # [ | O + 133* | 117*) + shift + # Is $1 in ge 0 AND le 9 OR eq ';'? + # These are control sequences for things like colors; Ignore them + while [ "0$1" -ge 060 ] && [ "0$1" -le 071 ] || + [ "0$1" -eq 073 ]; do + shift + done + ;; + esac + fi + + case "$LE_current_key" in + 001) # ^A beginning of line + LE_backward "$LE_left" + LE_right="$LE_left$LE_right" + LE_left= + ;; + 002) # ^B backward + if [ "$LE_left" = "" ]; then + # bell + printf '\a' + LE_print_debug "$LE_debug" "backward with empty left" + else + printf '\b' + LE_tmp="${LE_left%?}" + LE_right="${LE_left#"$LE_tmp"}$LE_right" + LE_left="$LE_tmp" + fi ;; + 003) # CTRL-C + break 2 ;; + 004) # ^D del char + if [ "$LE_right" = "" ]; then + # bell (tell the user that the line is empty) + printf '\a' + LE_print_debug "$LE_debug" "delete with empty right" + else + LE_right="${LE_right#?}" + printf '%s\b' "$LE_right$LE_fill" + LE_backward "$LE_right" + fi ;; + 012 | 015) # NL or CR + LE_ret=0 + break 2 + ;; + 005) # ^E end of line + printf '%s' "$LE_right" + LE_left="$LE_left$LE_right" + LE_right= + ;; + 006) # ^F forward + if [ "$LE_right" = "" ]; then + # bell (tell the user that the line is empty) + printf '\a' + LE_print_debug "$LE_debug" "forward with empty right" + else + LE_tmp="${LE_right#?}" + LE_left="$LE_left${LE_right%"$LE_tmp"}" + printf %s "${LE_right%"$LE_tmp"}" + LE_right="$LE_tmp" + fi ;; + 010 | 177) # backspace or del + if [ "$LE_left" = "" ]; then + # bell + printf '\a' + LE_print_debug "$LE_debug" "backspace with empty left" + else + printf '\b%s\b' "$LE_right$LE_fill" + LE_backward "$LE_right" + LE_left="${LE_left%?}" + fi ;; + 013) # ^K kill to end of line + LE_fill "$LE_right" + LE_backward "$LE_right" + LE_right="" + ;; + 014) # ^L redraw + printf '\r%b%s' "$LE_prompt" "$LE_left$LE_right" + LE_backward "$LE_right" + ;; + 025) # ^U kill line + LE_backward "$LE_left" + LE_fill "$LE_left$LE_right" + LE_backward "$LE_left$LE_right" + LE_left="" + LE_right="" + ;; + 027) # ^W kill word + if [ "$LE_left" = "" ]; then + # bell + printf '\a' + else + LE_tmp="${LE_left% *}" + LE_backward "${LE_left#"$LE_tmp"}" + LE_fill "${LE_left#"$LE_tmp"}" + LE_backward "${LE_left#"$LE_tmp"}" + LE_left="$LE_tmp" + fi ;; + # Print the received key, as it did not match a special key + [02][4-7]? | [13]??) # 040 -> 177, 240 -> 377 + # was assuming iso8859-x at the time + if [ "$LE_max" -gt 0 ] && LE_tmp="$LE_left$LE_right" && + [ "${#LE_tmp}" -eq "$LE_max" ]; then + # bell, when the user is trying to cross the line limit + printf '\a' + LE_print_debug "$LE_debug" "max output reached" + else + LE_left="$LE_left$(printf '%b' "\0$LE_current_key")" + printf '%b%s' "\0$LE_current_key" "$LE_right" + LE_backward "$LE_right" + fi ;; + *) + LE_print_debug "$LE_debug" "key not recognized: $(printf "%b" "\0$LE_current_key")" + printf '\a' + ;; + esac + done + done + eval "$LE_restore" + REPLY=$LE_left$LE_right + echo + return "$LE_ret" +} diff --git a/build/latex/letter/treefmt.nix b/build/latex/letter/treefmt.nix new file mode 100644 index 0000000..794e8fc --- /dev/null +++ b/build/latex/letter/treefmt.nix @@ -0,0 +1,70 @@ +{ + treefmt-nix, + pkgs, +}: +treefmt-nix.lib.evalModule pkgs ( + {pkgs, ...}: { + # Used to find the project root + projectRootFile = "flake.nix"; + + programs = { + alejandra.enable = true; + rustfmt.enable = true; + clang-format.enable = true; + mdformat.enable = true; + shfmt = { + enable = true; + indent_size = 4; + }; + shellcheck.enable = true; + prettier = { + enable = true; + settings = { + arrowParens = "always"; + bracketSameLine = false; + bracketSpacing = true; + editorconfig = true; + embeddedLanguageFormatting = "auto"; + endOfLine = "lf"; + # experimentalTernaries = false; + htmlWhitespaceSensitivity = "css"; + insertPragma = false; + jsxSingleQuote = true; + printWidth = 80; + proseWrap = "always"; + quoteProps = "consistent"; + requirePragma = false; + semi = true; + singleAttributePerLine = true; + singleQuote = false; + trailingComma = "all"; + useTabs = false; + vueIndentScriptAndStyle = false; + + tabWidth = 2; + }; + }; + stylua.enable = true; + ruff = { + enable = true; + format = true; + }; + taplo.enable = true; + }; + + settings = { + global.excludes = [ + "CHANGELOG.md" + "NEWS.md" + ]; + formatter = { + clang-format = { + options = ["--style" "GNU"]; + }; + shfmt = { + includes = ["*.bash"]; + }; + }; + }; + } +) diff --git a/build/latex/letter/update.sh b/build/latex/letter/update.sh new file mode 100755 index 0000000..49216b8 --- /dev/null +++ b/build/latex/letter/update.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env sh + +nix flake update diff --git a/build/latex/letter/watch.sh b/build/latex/letter/watch.sh new file mode 100755 index 0000000..e5147f2 --- /dev/null +++ b/build/latex/letter/watch.sh @@ -0,0 +1,70 @@ +#!/usr/bin/env sh + +help() { + cat <<EOF +An simple watch script, useful to see the changes in the document as it evolves. + +USAGE: + watch.sh [OPTIONS] [COMMAND] + +OPTIONS: + --help | -h + Display this help and exit. + + --open [READER] | -o [READER] + Open the build PDF in READER before waiting for changes. + READER defaults to the READER environment variable or + 'zathura' if the env variable is unset. + --sleeptime [T] | -s [T] + How long to sleep between each build attempt in seconds. The + time defaults to 10 seconds. +ARGUMENTS: + READER := [[echo "\${READER-zathura}"]] + The reader to open the build PDF with. + + T := [[seq 1 100]] + The time to sleep between each build attempt. +EOF +} + +reader="" +time="10" +for arg in "$@"; do + case "$arg" in + "--help" | "-h") + help + exit 0 + ;; + + "--open" | "-o") + shift 1 + reader="$1" + if [ -z "$reader" ]; then + reader="${READER-zathura}" + else + shift 1 + fi + ;; + + "--sleeptime" | "-s") + shift 1 + time="$1" + if [ -z "$time" ]; then + time=10 + else + shift 1 + fi + ;; + *) + echo "'$1' is not a recognized option! See '--help' for more detail." 1>&2 + exit 1 + ;; + esac +done + +[ -n "$reader" ] && "$reader" ./build/%INIT_APPLICATION_NAME.pdf & + +while true; do + ./build.sh + sleep "$time" +done |